browser_view.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// Copyright 2012 The Chromium Authors. All rights reserved. 2975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// Use of this source code is governed by a BSD-style license that can be 3975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// found in the LICENSE file. 4975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 5975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/frame/browser_view.h" 6975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 7975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include <algorithm> 8975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 9975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/auto_reset.h" 10975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/command_line.h" 11975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/i18n/rtl.h" 12975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/memory/scoped_ptr.h" 13975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/metrics/histogram.h" 14975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/prefs/pref_service.h" 15975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/strings/string_number_conversions.h" 16975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/strings/utf_string_conversions.h" 17975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/app/chrome_command_ids.h" 18975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/app/chrome_dll_resource.h" 19e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/app_mode/app_mode_utils.h" 20e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/bookmarks/bookmark_stats.h" 21975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/browser_process.h" 22975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/chrome_notification_types.h" 23975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/extensions/tab_helper.h" 24e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/infobars/infobar_service.h" 25975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/native_window_notification_source.h" 26975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/password_manager/password_manager.h" 27975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/profiles/avatar_menu.h" 28975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/profiles/profile.h" 29975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/profiles/profile_info_cache.h" 30975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/profiles/profile_manager.h" 31975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/search/search.h" 32975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/sessions/tab_restore_service.h" 33975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/sessions/tab_restore_service_factory.h" 34975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/speech/tts_controller.h" 35975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/themes/theme_properties.h" 36975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/themes/theme_service_factory.h" 37975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 38975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" 39975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h" 40975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h" 41975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h" 42975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser.h" 43975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_command_controller.h" 44975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_commands.h" 45975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_dialogs.h" 46975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_finder.h" 47975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_list.h" 48975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/browser_window_state.h" 49975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/immersive_fullscreen_configuration.h" 50975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/ntp_background_util.h" 51975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 52975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" 53975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/omnibox/omnibox_view.h" 54975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/search/search_delegate.h" 55975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/search/search_model.h" 56975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/search/search_ui.h" 57975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/tabs/tab_menu_model.h" 58975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/tabs/tab_strip_model.h" 59975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/view_ids.h" 60975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/accelerator_table.h" 61975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/accessibility/invert_bubble_view.h" 62975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/avatar_menu_bubble_view.h" 63975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/avatar_menu_button.h" 64975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" 65975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h" 66975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/browser_dialogs.h" 67975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h" 68975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/download/download_shelf_view.h" 69e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/ui/views/frame/browser_view_layout.h" 70975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h" 71975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/frame/contents_container.h" 72975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/frame/immersive_mode_controller.h" 73975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/frame/top_container_view.h" 74975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h" 75975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/infobars/infobar_container_view.h" 76975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 77975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/location_bar/location_icon_view.h" 78e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h" 79975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/omnibox/omnibox_views.h" 80975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/password_generation_bubble_view.h" 81975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/status_bubble_views.h" 82975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" 83975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/tabs/tab.h" 84975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/tabs/tab_strip.h" 85975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/toolbar_view.h" 86975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/update_recommended_message_box.h" 87975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h" 88975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/window_sizer/window_sizer.h" 89975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/common/chrome_switches.h" 90975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/common/pref_names.h" 91975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/common/url_constants.h" 92975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/download_manager.h" 93975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/native_web_keyboard_event.h" 94975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/notification_service.h" 95975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/render_view_host.h" 96975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/render_widget_host.h" 97975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/user_metrics.h" 98975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/web_contents.h" 99975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/browser/web_contents_view.h" 100975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "content/public/common/content_switches.h" 101975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/chromium_strings.h" 102975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/generated_resources.h" 103975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/locale_settings.h" 104975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/theme_resources.h" 105975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/ui_resources.h" 106975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "grit/ui_strings.h" 107e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "grit/webkit_resources.h" 108e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "ui/base/accelerators/accelerator.h" 109975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/base/accessibility/accessible_view_state.h" 110e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "ui/base/hit_test.h" 111975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/base/l10n/l10n_util.h" 112975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/base/resource/resource_bundle.h" 113975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/base/theme_provider.h" 114975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/events/event_utils.h" 115e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "ui/gfx/canvas.h" 116e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "ui/gfx/color_utils.h" 117975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/gfx/sys_color_change_listener.h" 118e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "ui/views/controls/button/menu_button.h" 119975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/controls/single_split_view.h" 120975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/controls/textfield/textfield.h" 121975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/controls/webview/webview.h" 122975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/focus/external_focus_tracker.h" 123975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/focus/view_storage.h" 124975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/layout/grid_layout.h" 125975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/widget/native_widget.h" 126975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/widget/root_view.h" 127975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/widget/widget.h" 128975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/window/dialog_delegate.h" 129975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 130975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#if defined(USE_ASH) 131975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ash/launcher/launcher.h" 132975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ash/launcher/launcher_model.h" 133975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ash/shell.h" 134975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/ash/ash_util.h" 135975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#endif 136975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 137975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#if defined(USE_AURA) 138975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/aura/window.h" 139975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/gfx/screen.h" 140975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#elif defined(OS_WIN) // !defined(USE_AURA) 141975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/jumplist_win.h" 142e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#include "chrome/browser/ui/views/omnibox/omnibox_view_win.h" 143975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/widget/native_widget_win.h" 144975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "ui/views/win/scoped_fullscreen_visibility.h" 145975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#endif 146975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 147e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org#if defined(OS_WIN) 148975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "base/win/windows_version.h" 149975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "win8/util/win8_util.h" 150975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#endif 151975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 152975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#if defined(ENABLE_ONE_CLICK_SIGNIN) 153975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/sync/one_click_signin_bubble_delegate.h" 154975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/sync/one_click_signin_bubble_links_delegate.h" 155975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h" 156975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org#endif 157975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 158975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing base::TimeDelta; 159975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing content::NativeWebKeyboardEvent; 160975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing content::SSLStatus; 161975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing content::UserMetricsAction; 162975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing content::WebContents; 163975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing views::ColumnSet; 164975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgusing views::GridLayout; 165e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.orgusing web_modal::WebContentsModalDialogHost; 166975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 167975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgnamespace { 168975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// The height of the status bubble. 169975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgconst int kStatusBubbleHeight = 20; 170975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// The name of a key to store on the window handle so that other code can 171975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// locate this object using just the handle. 172975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgconst char* const kBrowserViewKey = "__BROWSER_VIEW__"; 173975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 174975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// The number of milliseconds between loading animation frames. 175975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgconst int kLoadingAnimationFrameTimeMs = 30; 176975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// The amount of space we expect the window border to take up. 177975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgconst int kWindowBorderWidth = 5; 178e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org 179975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// How round the 'new tab' style bookmarks bar is. 180975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgconst int kNewtabBarRoundness = 5; 181975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 182975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// TODO(kuan): These functions are temporarily for the bookmark bar while its 183975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// detached state is at the top of the page; it'll be moved to float on the 184975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// content page in the very near future, at which time, these local functions 185975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org// will be removed. 186975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgvoid PaintDetachedBookmarkBar(gfx::Canvas* canvas, 187975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org DetachableToolbarView* view, 188975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org ThemeService* theme_service) { 189975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org // Paint background for detached state; if animating, this is fade in/out. 190975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org canvas->DrawColor( 191975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org chrome::GetDetachedBookmarkBarBackgroundColor(theme_service)); 192975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org // Draw the separators above and below bookmark bar; 193975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org // if animating, these are fading in/out. 194975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org SkColor separator_color = 195975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org chrome::GetDetachedBookmarkBarSeparatorColor(theme_service); 196975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org DetachableToolbarView::PaintHorizontalBorder(canvas, view, true, 197975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org separator_color); 198975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org // The bottom border needs to be 1-px thick in both regular and retina 199 // displays, so we can't use DetachableToolbarView::PaintHorizontalBorder 200 // which paints a 2-px thick border in retina display. 201 SkPaint paint; 202 paint.setAntiAlias(false); 203 // Sets border to 1-px thick regardless of scale factor. 204 paint.setStrokeWidth(0); 205 // Bottom border is at 50% opacity of top border. 206 paint.setColor(SkColorSetA(separator_color, 207 SkColorGetA(separator_color) / 2)); 208 // Calculate thickness of bottom border as per current scale factor to 209 // determine where to draw the 1-px thick border. 210 float thickness = views::NonClientFrameView::kClientEdgeThickness / 211 canvas->image_scale(); 212 SkScalar y = SkIntToScalar(view->height()) - SkFloatToScalar(thickness); 213 canvas->sk_canvas()->drawLine(SkIntToScalar(0), y, 214 SkIntToScalar(view->width()), y, paint); 215} 216 217void PaintAttachedBookmarkBar(gfx::Canvas* canvas, 218 DetachableToolbarView* view, 219 BrowserView* browser_view, 220 chrome::HostDesktopType host_desktop_type, 221 int toolbar_overlap) { 222 // Paint background for attached state, this is fade in/out. 223 gfx::Point background_image_offset = 224 browser_view->OffsetPointForToolbarBackgroundImage( 225 gfx::Point(view->GetMirroredX(), view->y())); 226 DetachableToolbarView::PaintBackgroundAttachedMode(canvas, 227 view->GetThemeProvider(), view->GetLocalBounds(), 228 background_image_offset, host_desktop_type); 229 if (view->height() >= toolbar_overlap) { 230 // Draw the separator below bookmark bar; this is fading in/out. 231 DetachableToolbarView::PaintHorizontalBorder(canvas, view, false, 232 ThemeProperties::GetDefaultColor( 233 ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); 234 } 235} 236 237} // namespace 238 239// static 240const char BrowserView::kViewClassName[] = "BrowserView"; 241 242namespace { 243 244bool ShouldSaveOrRestoreWindowPos() { 245#if defined(OS_WIN) 246 // In Windows 8's single window Metro mode the window is always maximized 247 // (without the WS_MAXIMIZE style). 248 if (win8::IsSingleWindowMetroMode()) 249 return false; 250#endif 251 return true; 252} 253 254} // namespace 255 256/////////////////////////////////////////////////////////////////////////////// 257 258// Delegate implementation for BrowserViewLayout. Usually just forwards calls 259// into BrowserView. 260class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate { 261 public: 262 explicit BrowserViewLayoutDelegateImpl(BrowserView* browser_view) 263 : browser_view_(browser_view) {} 264 virtual ~BrowserViewLayoutDelegateImpl() {} 265 266 // BrowserViewLayoutDelegate overrides: 267 virtual views::View* GetWindowSwitcherButton() const OVERRIDE { 268 return browser_view_->window_switcher_button(); 269 } 270 271 virtual bool DownloadShelfNeedsLayout() const OVERRIDE { 272 DownloadShelfView* download_shelf = browser_view_->download_shelf_.get(); 273 // Re-layout the shelf either if it is visible or if its close animation 274 // is currently running. 275 return download_shelf && 276 (download_shelf->IsShowing() || download_shelf->IsClosing()); 277 } 278 279 virtual bool IsTabStripVisible() const OVERRIDE { 280 return browser_view_->IsTabStripVisible(); 281 } 282 283 virtual gfx::Rect GetBoundsForTabStrip( 284 views::View* tab_strip) const OVERRIDE { 285 return browser_view_->frame()->GetBoundsForTabStrip(tab_strip); 286 } 287 288 virtual bool IsToolbarVisible() const OVERRIDE { 289 return browser_view_->IsToolbarVisible(); 290 } 291 292 virtual bool IsBookmarkBarVisible() const OVERRIDE { 293 return browser_view_->IsBookmarkBarVisible(); 294 } 295 296 virtual FullscreenExitBubbleViews* GetFullscreenExitBubble() const OVERRIDE { 297 return browser_view_->fullscreen_exit_bubble(); 298 } 299 300 private: 301 BrowserView* browser_view_; 302 303 DISALLOW_COPY_AND_ASSIGN(BrowserViewLayoutDelegateImpl); 304}; 305 306/////////////////////////////////////////////////////////////////////////////// 307// BookmarkExtensionBackground, private: 308// This object serves as the views::Background object which is used to layout 309// and paint the bookmark bar. 310class BookmarkExtensionBackground : public views::Background { 311 public: 312 BookmarkExtensionBackground(BrowserView* browser_view, 313 DetachableToolbarView* host_view, 314 Browser* browser); 315 316 // View methods overridden from views:Background. 317 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE; 318 319 private: 320 BrowserView* browser_view_; 321 322 // The view hosting this background. 323 DetachableToolbarView* host_view_; 324 325 Browser* browser_; 326 327 DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground); 328}; 329 330BookmarkExtensionBackground::BookmarkExtensionBackground( 331 BrowserView* browser_view, 332 DetachableToolbarView* host_view, 333 Browser* browser) 334 : browser_view_(browser_view), 335 host_view_(host_view), 336 browser_(browser) { 337} 338 339void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas, 340 views::View* view) const { 341 int toolbar_overlap = host_view_->GetToolbarOverlap(); 342 if (!host_view_->IsDetached()) { 343 PaintAttachedBookmarkBar(canvas, host_view_, browser_view_, 344 browser_->host_desktop_type(), toolbar_overlap); 345 return; 346 } 347 348 // As 'hidden' according to the animation is the full in-tab state, we invert 349 // the value - when current_state is at '0', we expect the bar to be docked. 350 double current_state = 1 - host_view_->GetAnimationValue(); 351 352 ThemeService* ts = 353 ThemeServiceFactory::GetForProfile(browser_->profile()); 354 if (current_state == 0.0 || current_state == 1.0) { 355 PaintDetachedBookmarkBar(canvas, host_view_, ts); 356 return; 357 } 358 // While animating, set opacity to cross-fade between attached and detached 359 // backgrounds including their respective separators. 360 int detached_alpha = static_cast<uint8>(current_state * 255); 361 int attached_alpha = 255 - detached_alpha; 362 if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED) { 363 // To animate from attached to detached state: 364 // - fade out attached background 365 // - fade in detached background. 366 canvas->SaveLayerAlpha(attached_alpha); 367 PaintAttachedBookmarkBar(canvas, host_view_, browser_view_, 368 browser_->host_desktop_type(), 369 toolbar_overlap); 370 canvas->Restore(); 371 canvas->SaveLayerAlpha(detached_alpha); 372 PaintDetachedBookmarkBar(canvas, host_view_, ts); 373 } else { 374 // To animate from detached to attached state: 375 // - fade out detached background 376 // - fade in attached background. 377 canvas->SaveLayerAlpha(detached_alpha); 378 PaintDetachedBookmarkBar(canvas, host_view_, ts); 379 canvas->Restore(); 380 canvas->SaveLayerAlpha(attached_alpha); 381 PaintAttachedBookmarkBar(canvas, host_view_, browser_view_, 382 browser_->host_desktop_type(), 383 toolbar_overlap); 384 } 385 canvas->Restore(); 386} 387 388/////////////////////////////////////////////////////////////////////////////// 389// BrowserView, public: 390 391BrowserView::BrowserView() 392 : views::ClientView(NULL, NULL), 393 last_focused_view_storage_id_( 394 views::ViewStorage::GetInstance()->CreateStorageID()), 395 frame_(NULL), 396 top_container_(NULL), 397 tabstrip_(NULL), 398 toolbar_(NULL), 399 window_switcher_button_(NULL), 400 find_bar_host_view_(NULL), 401 infobar_container_(NULL), 402 contents_web_view_(NULL), 403 devtools_container_(NULL), 404 contents_container_(NULL), 405 contents_split_(NULL), 406 devtools_dock_side_(DEVTOOLS_DOCK_SIDE_BOTTOM), 407 devtools_window_(NULL), 408 initialized_(false), 409 ignore_layout_(true), 410#if defined(OS_WIN) && !defined(USE_AURA) 411 hung_window_detector_(&hung_plugin_action_), 412 ticker_(0), 413#endif 414 force_location_bar_focus_(false), 415 immersive_mode_controller_(chrome::CreateImmersiveModeController()), 416#if defined(OS_CHROMEOS) 417 scroll_end_effect_controller_(ScrollEndEffectController::Create()), 418#endif 419 color_change_listener_(this), 420 activate_modal_dialog_factory_(this) { 421} 422 423BrowserView::~BrowserView() { 424 // Immersive mode may need to reparent views before they are removed/deleted. 425 immersive_mode_controller_.reset(); 426 427 browser_->tab_strip_model()->RemoveObserver(this); 428 429#if defined(OS_WIN) && !defined(USE_AURA) 430 // Stop hung plugin monitoring. 431 ticker_.Stop(); 432 ticker_.UnregisterTickHandler(&hung_window_detector_); 433 434 // Terminate the jumplist (must be called before browser_->profile() is 435 // destroyed. 436 if (jumplist_) { 437 jumplist_->Terminate(); 438 } 439#endif 440 441 // We destroy the download shelf before |browser_| to remove its child 442 // download views from the set of download observers (since the observed 443 // downloads can be destroyed along with |browser_| and the observer 444 // notifications will call back into deleted objects). 445 BrowserViewLayout* browser_view_layout = GetBrowserViewLayout(); 446 if (browser_view_layout) 447 browser_view_layout->set_download_shelf(NULL); 448 download_shelf_.reset(); 449 450 // The TabStrip attaches a listener to the model. Make sure we shut down the 451 // TabStrip first so that it can cleanly remove the listener. 452 if (tabstrip_) { 453 tabstrip_->parent()->RemoveChildView(tabstrip_); 454 if (browser_view_layout) 455 browser_view_layout->set_tab_strip(NULL); 456 delete tabstrip_; 457 tabstrip_ = NULL; 458 } 459 // Child views maintain PrefMember attributes that point to 460 // OffTheRecordProfile's PrefService which gets deleted by ~Browser. 461 RemoveAllChildViews(true); 462 toolbar_ = NULL; 463 464 // It is possible that we were forced-closed by the native view system and 465 // that tabs remain in the browser. Close any such remaining tabs. Detach 466 // before destroying in hopes of avoiding less callbacks trying to access 467 // members since destroyed. 468 { 469 ScopedVector<content::WebContents> contents; 470 while (browser_->tab_strip_model()->count()) 471 contents.push_back(browser_->tab_strip_model()->DetachWebContentsAt(0)); 472 } 473 474 // Explicitly set browser_ to NULL. 475 browser_.reset(); 476} 477 478void BrowserView::Init(Browser* browser) { 479 browser_.reset(browser); 480 browser_->tab_strip_model()->AddObserver(this); 481} 482 483// static 484BrowserView* BrowserView::GetBrowserViewForNativeWindow( 485 gfx::NativeWindow window) { 486 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); 487 return widget ? 488 reinterpret_cast<BrowserView*>(widget->GetNativeWindowProperty( 489 kBrowserViewKey)) : NULL; 490} 491 492// static 493BrowserView* BrowserView::GetBrowserViewForBrowser(const Browser* browser) { 494 return static_cast<BrowserView*>(browser->window()); 495} 496 497void BrowserView::InitStatusBubble() { 498 status_bubble_.reset(new StatusBubbleViews(contents_container_)); 499} 500 501gfx::Rect BrowserView::GetToolbarBounds() const { 502 gfx::Rect toolbar_bounds(toolbar_->bounds()); 503 if (toolbar_bounds.IsEmpty()) 504 return toolbar_bounds; 505 // The apparent toolbar edges are outside the "real" toolbar edges. 506 toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0); 507 return toolbar_bounds; 508} 509 510gfx::Rect BrowserView::GetClientAreaBounds() const { 511 gfx::Rect container_bounds = contents_container_->bounds(); 512 gfx::Point container_origin = container_bounds.origin(); 513 ConvertPointToTarget(this, parent(), &container_origin); 514 container_bounds.set_origin(container_origin); 515 return container_bounds; 516} 517 518gfx::Rect BrowserView::GetFindBarBoundingBox() const { 519 return GetBrowserViewLayout()->GetFindBarBoundingBox(); 520} 521 522int BrowserView::GetTabStripHeight() const { 523 // We want to return tabstrip_->height(), but we might be called in the midst 524 // of layout, when that hasn't yet been updated to reflect the current state. 525 // So return what the tabstrip height _ought_ to be right now. 526 return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0; 527} 528 529gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage( 530 const gfx::Point& point) const { 531 // The background image starts tiling horizontally at the window left edge and 532 // vertically at the top edge of the horizontal tab strip (or where it would 533 // be). We expect our parent's origin to be the window origin. 534 gfx::Point window_point(point + GetMirroredPosition().OffsetFromOrigin()); 535 window_point.Offset(frame_->GetThemeBackgroundXInset(), 536 -frame_->GetTabStripInsets(false).top); 537 return window_point; 538} 539 540bool BrowserView::IsTabStripVisible() const { 541 if (immersive_mode_controller_->ShouldHideTopViews() && 542 immersive_mode_controller_->ShouldHideTabIndicators()) 543 return false; 544 return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); 545} 546 547bool BrowserView::IsOffTheRecord() const { 548 return browser_->profile()->IsOffTheRecord(); 549} 550 551int BrowserView::GetOTRIconResourceID() const { 552 int otr_resource_id = IDR_OTR_ICON; 553 if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) { 554 if (IsFullscreen()) 555 otr_resource_id = IDR_OTR_ICON_FULLSCREEN; 556#if defined(OS_WIN) 557 if (win8::IsSingleWindowMetroMode()) 558 otr_resource_id = IDR_OTR_ICON_FULLSCREEN; 559#endif 560 } 561 562 return otr_resource_id; 563} 564 565bool BrowserView::IsGuestSession() const { 566 return browser_->profile()->IsGuestSession(); 567} 568 569int BrowserView::GetGuestIconResourceID() const { 570 return IDR_GUEST_ICON; 571} 572 573bool BrowserView::ShouldShowAvatar() const { 574 if (!IsBrowserTypeNormal()) 575 return false; 576#if defined(OS_CHROMEOS) 577 if (IsOffTheRecord() && !IsGuestSession()) 578 return true; 579#else 580 if (IsOffTheRecord()) // Desktop guest is incognito and needs avatar. 581 return true; 582#endif 583 // Tests may not have a profile manager. 584 if (!g_browser_process->profile_manager()) 585 return false; 586 ProfileInfoCache& cache = 587 g_browser_process->profile_manager()->GetProfileInfoCache(); 588 if (cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath()) == 589 std::string::npos) { 590 return false; 591 } 592 593 return AvatarMenu::ShouldShowAvatarMenu(); 594} 595 596bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { 597 // We retrieve the accelerator information for standard accelerators 598 // for cut, copy and paste. 599 if (chrome::GetStandardAcceleratorForCommandId(cmd_id, accelerator)) 600 return true; 601 // Else, we retrieve the accelerator information from the accelerator table. 602 for (std::map<ui::Accelerator, int>::const_iterator it = 603 accelerator_table_.begin(); it != accelerator_table_.end(); ++it) { 604 if (it->second == cmd_id) { 605 *accelerator = it->first; 606 return true; 607 } 608 } 609 // Else, we retrieve the accelerator information from Ash (if applicable). 610 return chrome::GetAshAcceleratorForCommandId( 611 cmd_id, browser_->host_desktop_type(), accelerator); 612} 613 614bool BrowserView::IsAcceleratorRegistered(const ui::Accelerator& accelerator) { 615 return accelerator_table_.find(accelerator) != accelerator_table_.end(); 616} 617 618WebContents* BrowserView::GetActiveWebContents() const { 619 return browser_->tab_strip_model()->GetActiveWebContents(); 620} 621 622gfx::ImageSkia BrowserView::GetOTRAvatarIcon() const { 623 return *GetThemeProvider()->GetImageSkiaNamed(GetOTRIconResourceID()); 624} 625 626/////////////////////////////////////////////////////////////////////////////// 627// BrowserView, BrowserWindow implementation: 628 629void BrowserView::Show() { 630 // If the window is already visible, just activate it. 631 if (frame_->IsVisible()) { 632 frame_->Activate(); 633 return; 634 } 635 636 // Showing the window doesn't make the browser window active right away. 637 // This can cause SetFocusToLocationBar() to skip setting focus to the 638 // location bar. To avoid this we explicilty let SetFocusToLocationBar() 639 // know that it's ok to steal focus. 640 force_location_bar_focus_ = true; 641 642 // Setting the focus doesn't work when the window is invisible, so any focus 643 // initialization that happened before this will be lost. 644 // 645 // We really "should" restore the focus whenever the window becomes unhidden, 646 // but I think initializing is the only time where this can happen where 647 // there is some focus change we need to pick up, and this is easier than 648 // plumbing through an un-hide message all the way from the frame. 649 // 650 // If we do find there are cases where we need to restore the focus on show, 651 // that should be added and this should be removed. 652 RestoreFocus(); 653 654 frame_->Show(); 655 656 force_location_bar_focus_ = false; 657 658 browser()->OnWindowDidShow(); 659 660 chrome::MaybeShowInvertBubbleView(browser_.get(), contents_container_); 661} 662 663void BrowserView::ShowInactive() { 664 if (frame_->IsVisible()) 665 return; 666 frame_->ShowInactive(); 667} 668 669void BrowserView::Hide() { 670 // Not implemented. 671} 672 673void BrowserView::SetBounds(const gfx::Rect& bounds) { 674 ExitFullscreen(); 675 GetWidget()->SetBounds(bounds); 676} 677 678void BrowserView::Close() { 679 frame_->Close(); 680} 681 682void BrowserView::Activate() { 683 frame_->Activate(); 684} 685 686void BrowserView::Deactivate() { 687 frame_->Deactivate(); 688} 689 690bool BrowserView::IsActive() const { 691 return frame_->IsActive(); 692} 693 694void BrowserView::FlashFrame(bool flash) { 695 frame_->FlashFrame(flash); 696} 697 698bool BrowserView::IsAlwaysOnTop() const { 699 return false; 700} 701 702void BrowserView::SetAlwaysOnTop(bool always_on_top) { 703 // Not implemented for browser windows. 704 NOTIMPLEMENTED(); 705} 706 707gfx::NativeWindow BrowserView::GetNativeWindow() { 708 // While the browser destruction is going on, the widget can already be gone, 709 // but utility functions like FindBrowserWithWindow will come here and crash. 710 // We short circuit therefore. 711 if (!GetWidget()) 712 return NULL; 713 return GetWidget()->GetTopLevelWidget()->GetNativeWindow(); 714} 715 716BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() { 717 return this; 718} 719 720StatusBubble* BrowserView::GetStatusBubble() { 721 return status_bubble_.get(); 722} 723 724namespace { 725 // Only used by ToolbarSizeChanged() below, but placed here because template 726 // arguments (to base::AutoReset<>) must have external linkage. 727 enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE }; 728} 729 730void BrowserView::UpdateTitleBar() { 731 frame_->UpdateWindowTitle(); 732 if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning()) 733 frame_->UpdateWindowIcon(); 734} 735 736void BrowserView::BookmarkBarStateChanged( 737 BookmarkBar::AnimateChangeType change_type) { 738 if (bookmark_bar_view_.get()) { 739 BookmarkBar::State new_state = browser_->bookmark_bar_state(); 740 741 // We don't properly support animating the bookmark bar to and from the 742 // detached state in immersive fullscreen. 743 bool detached_changed = (new_state == BookmarkBar::DETACHED) || 744 bookmark_bar_view_->IsDetached(); 745 if (detached_changed && immersive_mode_controller_->IsEnabled()) 746 change_type = BookmarkBar::DONT_ANIMATE_STATE_CHANGE; 747 748 bookmark_bar_view_->SetBookmarkBarState(new_state, change_type); 749 } 750 if (MaybeShowBookmarkBar(GetActiveWebContents())) 751 Layout(); 752} 753 754void BrowserView::UpdateDevTools() { 755 UpdateDevToolsForContents(GetActiveWebContents()); 756 Layout(); 757} 758 759void BrowserView::UpdateLoadingAnimations(bool should_animate) { 760 if (should_animate) { 761 if (!loading_animation_timer_.IsRunning()) { 762 // Loads are happening, and the timer isn't running, so start it. 763 last_animation_time_ = base::TimeTicks::Now(); 764 loading_animation_timer_.Start(FROM_HERE, 765 TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this, 766 &BrowserView::LoadingAnimationCallback); 767 } 768 } else { 769 if (loading_animation_timer_.IsRunning()) { 770 last_animation_time_ = base::TimeTicks(); 771 loading_animation_timer_.Stop(); 772 // Loads are now complete, update the state if a task was scheduled. 773 LoadingAnimationCallback(); 774 } 775 } 776} 777 778void BrowserView::SetStarredState(bool is_starred) { 779 GetLocationBarView()->SetStarToggled(is_starred); 780} 781 782void BrowserView::OnActiveTabChanged(content::WebContents* old_contents, 783 content::WebContents* new_contents, 784 int index, 785 int reason) { 786 DCHECK(new_contents); 787 788 // If |contents_container_| already has the correct WebContents, we can save 789 // some work. This also prevents extra events from being reported by the 790 // Visibility API under Windows, as ChangeWebContents will briefly hide 791 // the WebContents window. 792 bool change_tab_contents = 793 contents_web_view_->web_contents() != new_contents; 794 795 // Update various elements that are interested in knowing the current 796 // WebContents. 797 798 // When we toggle the NTP floating bookmarks bar and/or the info bar, 799 // we don't want any WebContents to be attached, so that we 800 // avoid an unnecessary resize and re-layout of a WebContents. 801 if (change_tab_contents) 802 contents_web_view_->SetWebContents(NULL); 803 infobar_container_->ChangeInfoBarService( 804 InfoBarService::FromWebContents(new_contents)); 805 if (bookmark_bar_view_.get()) { 806 bookmark_bar_view_->SetBookmarkBarState( 807 browser_->bookmark_bar_state(), 808 BookmarkBar::DONT_ANIMATE_STATE_CHANGE); 809 } 810 UpdateUIForContents(new_contents); 811 812 // Layout for DevTools _before_ setting the main WebContents to avoid 813 // toggling the size of the main WebContents. 814 UpdateDevToolsForContents(new_contents); 815 816 if (change_tab_contents) 817 contents_web_view_->SetWebContents(new_contents); 818 819 if (!browser_->tab_strip_model()->closing_all() && GetWidget()->IsActive() && 820 GetWidget()->IsVisible()) { 821 // We only restore focus if our window is visible, to avoid invoking blur 822 // handlers when we are eventually shown. 823 new_contents->GetView()->RestoreFocus(); 824 } 825 826 // Update all the UI bits. 827 UpdateTitleBar(); 828} 829 830void BrowserView::ZoomChangedForActiveTab(bool can_show_bubble) { 831 GetLocationBarView()->ZoomChangedForActiveTab( 832 can_show_bubble && !toolbar_->IsWrenchMenuShowing()); 833} 834 835gfx::Rect BrowserView::GetRestoredBounds() const { 836 return frame_->GetRestoredBounds(); 837} 838 839ui::WindowShowState BrowserView::GetRestoredState() const { 840 if (IsMaximized()) 841 return ui::SHOW_STATE_MAXIMIZED; 842 if (IsMinimized()) 843 return ui::SHOW_STATE_MINIMIZED; 844 return ui::SHOW_STATE_NORMAL; 845} 846 847gfx::Rect BrowserView::GetBounds() const { 848 return frame_->GetWindowBoundsInScreen(); 849} 850 851bool BrowserView::IsMaximized() const { 852 return frame_->IsMaximized(); 853} 854 855bool BrowserView::IsMinimized() const { 856 return frame_->IsMinimized(); 857} 858 859void BrowserView::Maximize() { 860 frame_->Maximize(); 861} 862 863void BrowserView::Minimize() { 864 frame_->Minimize(); 865} 866 867void BrowserView::Restore() { 868 frame_->Restore(); 869} 870 871void BrowserView::EnterFullscreen( 872 const GURL& url, FullscreenExitBubbleType bubble_type) { 873 if (IsFullscreen()) 874 return; // Nothing to do. 875 876 ProcessFullscreen(true, FOR_DESKTOP, url, bubble_type); 877} 878 879void BrowserView::ExitFullscreen() { 880 if (!IsFullscreen()) 881 return; // Nothing to do. 882 883 ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE); 884} 885 886void BrowserView::UpdateFullscreenExitBubbleContent( 887 const GURL& url, 888 FullscreenExitBubbleType bubble_type) { 889 // Immersive mode has no exit bubble because it has a visible strip at the 890 // top that gives the user a hover target. 891 // TODO(jamescook): Figure out what to do with mouse-lock. 892 if (bubble_type == FEB_TYPE_NONE || ShouldUseImmersiveFullscreenForUrl(url)) { 893 fullscreen_bubble_.reset(); 894 } else if (fullscreen_bubble_.get()) { 895 fullscreen_bubble_->UpdateContent(url, bubble_type); 896 } else { 897 fullscreen_bubble_.reset(new FullscreenExitBubbleViews( 898 this, url, bubble_type)); 899 } 900} 901 902bool BrowserView::ShouldHideUIForFullscreen() const { 903#if defined(USE_ASH) 904 // Immersive mode needs UI for the slide-down top panel. 905 return IsFullscreen() && !immersive_mode_controller_->IsEnabled(); 906#endif 907 return IsFullscreen(); 908} 909 910bool BrowserView::IsFullscreen() const { 911 return frame_->IsFullscreen(); 912} 913 914bool BrowserView::IsFullscreenBubbleVisible() const { 915 return fullscreen_bubble_ != NULL; 916} 917 918#if defined(OS_WIN) 919void BrowserView::SetMetroSnapMode(bool enable) { 920 HISTOGRAM_COUNTS("Metro.SnapModeToggle", enable); 921 ProcessFullscreen(enable, FOR_METRO, GURL(), FEB_TYPE_NONE); 922} 923 924bool BrowserView::IsInMetroSnapMode() const { 925#if defined(USE_AURA) 926 return false; 927#else 928 return static_cast<views::NativeWidgetWin*>( 929 frame_->native_widget())->IsInMetroSnapMode(); 930#endif 931} 932#endif // defined(OS_WIN) 933 934void BrowserView::RestoreFocus() { 935 WebContents* selected_web_contents = GetActiveWebContents(); 936 if (selected_web_contents) 937 selected_web_contents->GetView()->RestoreFocus(); 938} 939 940void BrowserView::SetWindowSwitcherButton(views::Button* button) { 941 if (window_switcher_button_) 942 RemoveChildView(window_switcher_button_); 943 window_switcher_button_ = button; 944} 945 946void BrowserView::ToolbarSizeChanged(bool is_animating) { 947 // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in 948 // reentrancy; |call_state| tracks whether we're reentrant. We can't just 949 // early-return in this case because we need to layout again so the infobar 950 // container's bounds are set correctly. 951 static CallState call_state = NORMAL; 952 953 // A reentrant call can (and should) use the fast resize path unless both it 954 // and the normal call are both non-animating. 955 bool use_fast_resize = 956 is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE); 957 if (use_fast_resize) 958 contents_web_view_->SetFastResize(true); 959 UpdateUIForContents(GetActiveWebContents()); 960 if (use_fast_resize) 961 contents_web_view_->SetFastResize(false); 962 963 // Inform the InfoBarContainer that the distance to the location icon may have 964 // changed. We have to do this after the block above so that the toolbars are 965 // laid out correctly for calculating the maximum arrow height below. 966 { 967 base::AutoReset<CallState> resetter(&call_state, 968 is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT); 969 infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight()); 970 } 971 972 // When transitioning from animating to not animating we need to make sure the 973 // contents_container_ gets layed out. If we don't do this and the bounds 974 // haven't changed contents_container_ won't get a Layout out and we'll end up 975 // with a gray rect because the clip wasn't updated. Note that a reentrant 976 // call never needs to do this, because after it returns, the normal call 977 // wrapping it will do it. 978 if ((call_state == NORMAL) && !is_animating) { 979 contents_web_view_->InvalidateLayout(); 980 contents_split_->Layout(); 981 } 982} 983 984LocationBar* BrowserView::GetLocationBar() const { 985 return GetLocationBarView(); 986} 987 988void BrowserView::SetFocusToLocationBar(bool select_all) { 989 // On Windows, changing focus to the location bar causes the browser 990 // window to become active. This can steal focus if the user has 991 // another window open already. On ChromeOS, changing focus makes a 992 // view believe it has a focus even if the widget doens't have a 993 // focus. Either cases, we need to ignore this when the browser 994 // window isn't active. 995 if (!force_location_bar_focus_ && !IsActive()) 996 return; 997 998 // Temporarily reveal the top-of-window views (if not already revealed) so 999 // that the location bar view is visible and is considered focusable. If the 1000 // location bar view gains focus, |immersive_mode_controller_| will keep the 1001 // top-of-window views revealed. 1002 scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock( 1003 immersive_mode_controller_->GetRevealedLock( 1004 ImmersiveModeController::ANIMATE_REVEAL_YES)); 1005 1006 LocationBarView* location_bar = GetLocationBarView(); 1007 if (location_bar->IsLocationEntryFocusableInRootView()) { 1008 // Location bar got focus. 1009 location_bar->FocusLocation(select_all); 1010 } else { 1011 // If none of location bar got focus, 1012 // then clear focus. 1013 views::FocusManager* focus_manager = GetFocusManager(); 1014 DCHECK(focus_manager); 1015 focus_manager->ClearFocus(); 1016 } 1017} 1018 1019void BrowserView::UpdateReloadStopState(bool is_loading, bool force) { 1020 toolbar_->reload_button()->ChangeMode( 1021 is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force); 1022} 1023 1024void BrowserView::UpdateToolbar(content::WebContents* contents) { 1025 // We may end up here during destruction. 1026 if (toolbar_) 1027 toolbar_->Update(contents); 1028} 1029 1030void BrowserView::FocusToolbar() { 1031 // Temporarily reveal the top-of-window views (if not already revealed) so 1032 // that the toolbar is visible and is considered focusable. If the 1033 // toolbar gains focus, |immersive_mode_controller_| will keep the 1034 // top-of-window views revealed. 1035 scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock( 1036 immersive_mode_controller_->GetRevealedLock( 1037 ImmersiveModeController::ANIMATE_REVEAL_YES)); 1038 1039 // Start the traversal within the main toolbar. SetPaneFocus stores 1040 // the current focused view before changing focus. 1041 toolbar_->SetPaneFocus(NULL); 1042} 1043 1044void BrowserView::FocusBookmarksToolbar() { 1045 DCHECK(!immersive_mode_controller_->IsEnabled()); 1046 if (bookmark_bar_view_.get() && 1047 bookmark_bar_view_->visible() && 1048 bookmark_bar_view_->GetPreferredSize().height() != 0) { 1049 bookmark_bar_view_->SetPaneFocusAndFocusDefault(); 1050 } 1051} 1052 1053void BrowserView::FocusInfobars() { 1054 if (infobar_container_->child_count() > 0) 1055 infobar_container_->SetPaneFocusAndFocusDefault(); 1056} 1057 1058void BrowserView::FocusAppMenu() { 1059 // Chrome doesn't have a traditional menu bar, but it has a menu button in the 1060 // main toolbar that plays the same role. If the user presses a key that 1061 // would typically focus the menu bar, tell the toolbar to focus the menu 1062 // button. If the user presses the key again, return focus to the previous 1063 // location. 1064 // 1065 // Not used on the Mac, which has a normal menu bar. 1066 if (toolbar_->IsAppMenuFocused()) { 1067 RestoreFocus(); 1068 } else { 1069 DCHECK(!immersive_mode_controller_->IsEnabled()); 1070 toolbar_->SetPaneFocusAndFocusAppMenu(); 1071 } 1072} 1073 1074void BrowserView::RotatePaneFocus(bool forwards) { 1075 GetWidget()->GetFocusManager()->RotatePaneFocus( 1076 forwards ? 1077 views::FocusManager::kForward : views::FocusManager::kBackward, 1078 views::FocusManager::kWrap); 1079} 1080 1081void BrowserView::DestroyBrowser() { 1082 // After this returns other parts of Chrome are going to be shutdown. Close 1083 // the window now so that we are deleted immediately and aren't left holding 1084 // references to deleted objects. 1085 GetWidget()->RemoveObserver(this); 1086 GetLocationBar()->GetLocationEntry()->model()->popup_model()->RemoveObserver( 1087 this); 1088 frame_->CloseNow(); 1089} 1090 1091bool BrowserView::IsBookmarkBarVisible() const { 1092 if (!browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)) 1093 return false; 1094 if (!bookmark_bar_view_.get()) 1095 return false; 1096 if (bookmark_bar_view_->GetPreferredSize().height() == 0) 1097 return false; 1098 // New tab page needs visible bookmarks even when top-views are hidden. 1099 if (immersive_mode_controller_->ShouldHideTopViews() && 1100 !bookmark_bar_view_->IsDetached()) 1101 return false; 1102 return true; 1103} 1104 1105bool BrowserView::IsBookmarkBarAnimating() const { 1106 return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating(); 1107} 1108 1109bool BrowserView::IsTabStripEditable() const { 1110 return tabstrip_->IsTabStripEditable(); 1111} 1112 1113bool BrowserView::IsToolbarVisible() const { 1114 if (immersive_mode_controller_->ShouldHideTopViews()) 1115 return false; 1116 return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) || 1117 browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); 1118} 1119 1120gfx::Rect BrowserView::GetRootWindowResizerRect() const { 1121 // Views does not support resizer rects because they caused page cycler 1122 // performance regressions when they were added. See crrev.com/9654 1123 return gfx::Rect(); 1124} 1125 1126void BrowserView::DisableInactiveFrame() { 1127#if defined(OS_WIN) && !defined(USE_AURA) 1128 frame_->DisableInactiveRendering(); 1129#endif // No tricks are needed to get the right behavior on Linux. 1130} 1131 1132void BrowserView::ConfirmAddSearchProvider(TemplateURL* template_url, 1133 Profile* profile) { 1134 chrome::EditSearchEngine(GetWidget()->GetNativeWindow(), template_url, NULL, 1135 profile); 1136} 1137 1138void BrowserView::ShowUpdateChromeDialog() { 1139 UpdateRecommendedMessageBox::Show(GetWidget()->GetNativeWindow()); 1140} 1141 1142void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { 1143 scoped_ptr<BookmarkBubbleDelegate> delegate; 1144 delegate.reset(new BookmarkBubbleSignInDelegate(browser_.get())); 1145 1146 BookmarkBubbleView::ShowBubble(GetToolbarView()->GetBookmarkBubbleAnchor(), 1147 bookmark_bar_view_.get(), 1148 delegate.Pass(), 1149 browser_->profile(), 1150 url, 1151 !already_bookmarked); 1152} 1153 1154void BrowserView::ShowBookmarkPrompt() { 1155 GetLocationBarView()->ShowBookmarkPrompt(); 1156} 1157 1158#if defined(ENABLE_ONE_CLICK_SIGNIN) 1159void BrowserView::ShowOneClickSigninBubble( 1160 OneClickSigninBubbleType type, 1161 const string16& email, 1162 const string16& error_message, 1163 const StartSyncCallback& start_sync_callback) { 1164 scoped_ptr<OneClickSigninBubbleDelegate> delegate; 1165 delegate.reset(new OneClickSigninBubbleLinksDelegate(browser())); 1166 1167 views::View* anchor_view; 1168 if (type == BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE) 1169 anchor_view = toolbar_->app_menu(); 1170 else 1171 anchor_view = toolbar_->location_bar(); 1172 1173 OneClickSigninBubbleView::ShowBubble(type, email, error_message, 1174 delegate.Pass(), anchor_view, 1175 start_sync_callback); 1176} 1177#endif 1178 1179void BrowserView::SetDownloadShelfVisible(bool visible) { 1180 // This can be called from the superclass destructor, when it destroys our 1181 // child views. At that point, browser_ is already gone. 1182 if (browser_ == NULL) 1183 return; 1184 1185 if (visible && IsDownloadShelfVisible() != visible) { 1186 // Invoke GetDownloadShelf to force the shelf to be created. 1187 GetDownloadShelf(); 1188 } 1189 1190 if (browser_ != NULL) 1191 browser_->UpdateDownloadShelfVisibility(visible); 1192 1193 // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out 1194 // everything correctly, as if the animation had finished. This doesn't 1195 // matter for showing the shelf, as the show animation will do it. 1196 ToolbarSizeChanged(false); 1197} 1198 1199bool BrowserView::IsDownloadShelfVisible() const { 1200 return download_shelf_.get() && download_shelf_->IsShowing(); 1201} 1202 1203DownloadShelf* BrowserView::GetDownloadShelf() { 1204 if (!download_shelf_.get()) { 1205 download_shelf_.reset(new DownloadShelfView(browser_.get(), this)); 1206 download_shelf_->set_owned_by_client(); 1207 GetBrowserViewLayout()->set_download_shelf(download_shelf_.get()); 1208 } 1209 return download_shelf_.get(); 1210} 1211 1212void BrowserView::ConfirmBrowserCloseWithPendingDownloads( 1213 int download_count, 1214 Browser::DownloadClosePreventionType dialog_type, 1215 bool app_modal, 1216 const base::Callback<void(bool)>& callback) { 1217 DownloadInProgressDialogView::Show( 1218 GetNativeWindow(), download_count, dialog_type, app_modal, callback); 1219} 1220 1221void BrowserView::ShowCreateChromeAppShortcutsDialog( 1222 Profile* profile, 1223 const extensions::Extension* app) { 1224 chrome::ShowCreateChromeAppShortcutsDialog( 1225 GetNativeWindow(), profile, app, base::Closure()); 1226} 1227 1228void BrowserView::UserChangedTheme() { 1229 frame_->FrameTypeChanged(); 1230} 1231 1232int BrowserView::GetExtraRenderViewHeight() const { 1233 // Currently this is only used on linux. 1234 return 0; 1235} 1236 1237void BrowserView::WebContentsFocused(WebContents* contents) { 1238 if (contents_web_view_->GetWebContents() == contents) 1239 contents_web_view_->OnWebContentsFocused(contents); 1240 else 1241 devtools_container_->OnWebContentsFocused(contents); 1242} 1243 1244void BrowserView::ShowWebsiteSettings(Profile* profile, 1245 content::WebContents* web_contents, 1246 const GURL& url, 1247 const content::SSLStatus& ssl) { 1248 WebsiteSettingsPopupView::ShowPopup( 1249 GetLocationBarView()->location_icon_view(), profile, 1250 web_contents, url, ssl, browser_.get()); 1251} 1252 1253void BrowserView::ShowAppMenu() { 1254 // Keep the top-of-window views revealed as long as the app menu is visible. 1255 scoped_ptr<ImmersiveRevealedLock> revealed_lock( 1256 immersive_mode_controller_->GetRevealedLock( 1257 ImmersiveModeController::ANIMATE_REVEAL_NO)); 1258 1259 toolbar_->app_menu()->Activate(); 1260} 1261 1262bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 1263 bool* is_keyboard_shortcut) { 1264 *is_keyboard_shortcut = false; 1265 1266 if ((event.type != WebKit::WebInputEvent::RawKeyDown) && 1267 (event.type != WebKit::WebInputEvent::KeyUp)) { 1268 return false; 1269 } 1270 1271#if defined(OS_WIN) && !defined(USE_AURA) 1272 // As Alt+F4 is the close-app keyboard shortcut, it needs processing 1273 // immediately. 1274 if (event.windowsKeyCode == ui::VKEY_F4 && 1275 event.type == WebKit::WebInputEvent::RawKeyDown && 1276 event.modifiers == NativeWebKeyboardEvent::AltKey) { 1277 DefWindowProc(event.os_event.hwnd, event.os_event.message, 1278 event.os_event.wParam, event.os_event.lParam); 1279 return true; 1280 } 1281#endif 1282 1283 views::FocusManager* focus_manager = GetFocusManager(); 1284 DCHECK(focus_manager); 1285 1286 if (focus_manager->shortcut_handling_suspended()) 1287 return false; 1288 1289 ui::Accelerator accelerator( 1290 static_cast<ui::KeyboardCode>(event.windowsKeyCode), 1291 content::GetModifiersFromNativeWebKeyboardEvent(event)); 1292 if (event.type == WebKit::WebInputEvent::KeyUp) 1293 accelerator.set_type(ui::ET_KEY_RELEASED); 1294 1295 // What we have to do here is as follows: 1296 // - If the |browser_| is for an app, do nothing. 1297 // - If the |browser_| is not for an app, and the |accelerator| is not 1298 // associated with the browser (e.g. an Ash shortcut), process it. 1299 // - If the |browser_| is not for an app, and the |accelerator| is associated 1300 // with the browser, and it is a reserved one (e.g. Ctrl+w), process it. 1301 // - If the |browser_| is not for an app, and the |accelerator| is associated 1302 // with the browser, and it is not a reserved one, do nothing. 1303 1304 if (browser_->is_app()) { 1305 // Let all keys fall through to a v1 app's web content, even accelerators. 1306 // We don't have to flip |is_keyboard_shortcut| here. If we do that, the app 1307 // might not be able to see a subsequent Char event. See OnHandleInputEvent 1308 // in content/renderer/render_widget.cc for details. 1309 return false; 1310 } 1311 1312 chrome::BrowserCommandController* controller = browser_->command_controller(); 1313 1314 // Here we need to retrieve the command id (if any) associated to the 1315 // keyboard event. Instead of looking up the command id in the 1316 // |accelerator_table_| by ourselves, we block the command execution of 1317 // the |browser_| object then send the keyboard event to the 1318 // |focus_manager| as if we are activating an accelerator key. 1319 // Then we can retrieve the command id from the |browser_| object. 1320 bool original_block_command_state = controller->block_command_execution(); 1321 controller->SetBlockCommandExecution(true); 1322 // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the 1323 // command execution cannot be blocked and true is returned. However, it is 1324 // okay as long as is_app() is false. See comments in this function. 1325 const bool processed = focus_manager->ProcessAccelerator(accelerator); 1326 const int id = controller->GetLastBlockedCommand(NULL); 1327 controller->SetBlockCommandExecution(original_block_command_state); 1328 1329 // Executing the command may cause |this| object to be destroyed. 1330 if (controller->IsReservedCommandOrKey(id, event)) { 1331 UpdateAcceleratorMetrics(accelerator, id); 1332 return chrome::ExecuteCommand(browser_.get(), id); 1333 } 1334 1335 if (id != -1) { 1336 // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+f). 1337 if (event.type == WebKit::WebInputEvent::RawKeyDown) 1338 *is_keyboard_shortcut = true; 1339 } else if (processed) { 1340 // |accelerator| is a non-browser shortcut (e.g. F4-F10 on Ash). Report 1341 // that we handled it. 1342 return true; 1343 } 1344 1345 return false; 1346} 1347 1348void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 1349 unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, 1350 GetFocusManager()); 1351} 1352 1353// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always 1354// enabled in the page menu regardless of whether the command will do 1355// anything. When someone selects the menu item, we just act as if they hit 1356// the keyboard shortcut for the command by sending the associated key press 1357// to windows. The real fix to this bug is to disable the commands when they 1358// won't do anything. We'll need something like an overall clipboard command 1359// manager to do that. 1360void BrowserView::Cut() { 1361 // If a WebContent is focused, call RenderWidgetHost::Cut. Otherwise, e.g. if 1362 // Omnibox is focused, send a Ctrl+x key event to Chrome. Using RWH interface 1363 // rather than the fake key event for a WebContent is important since the fake 1364 // event might be consumed by the web content (crbug.com/137908). 1365 DoCutCopyPaste(&content::RenderWidgetHost::Cut, 1366#if defined(OS_WIN) 1367 WM_CUT, 1368#endif 1369 IDS_APP_CUT); 1370} 1371 1372void BrowserView::Copy() { 1373 DoCutCopyPaste(&content::RenderWidgetHost::Copy, 1374#if defined(OS_WIN) 1375 WM_COPY, 1376#endif 1377 IDS_APP_COPY); 1378} 1379 1380void BrowserView::Paste() { 1381 DoCutCopyPaste(&content::RenderWidgetHost::Paste, 1382#if defined(OS_WIN) 1383 WM_PASTE, 1384#endif 1385 IDS_APP_PASTE); 1386} 1387 1388WindowOpenDisposition BrowserView::GetDispositionForPopupBounds( 1389 const gfx::Rect& bounds) { 1390#if defined(OS_WIN) 1391 // If we are in Win8's single window Metro mode, we can't allow popup windows. 1392 return win8::IsSingleWindowMetroMode() ? NEW_BACKGROUND_TAB : NEW_POPUP; 1393#else 1394 return NEW_POPUP; 1395#endif 1396} 1397 1398FindBar* BrowserView::CreateFindBar() { 1399 return chrome::CreateFindBar(this); 1400} 1401 1402WebContentsModalDialogHost* BrowserView::GetWebContentsModalDialogHost() { 1403 return GetBrowserViewLayout()->GetWebContentsModalDialogHost(); 1404} 1405 1406/////////////////////////////////////////////////////////////////////////////// 1407// BrowserView, BrowserWindowTesting implementation: 1408 1409BookmarkBarView* BrowserView::GetBookmarkBarView() const { 1410 return bookmark_bar_view_.get(); 1411} 1412 1413LocationBarView* BrowserView::GetLocationBarView() const { 1414 return toolbar_ ? toolbar_->location_bar() : NULL; 1415} 1416 1417views::View* BrowserView::GetTabContentsContainerView() const { 1418 return contents_web_view_; 1419} 1420 1421ToolbarView* BrowserView::GetToolbarView() const { 1422 return toolbar_; 1423} 1424 1425/////////////////////////////////////////////////////////////////////////////// 1426// BrowserView, TabStripModelObserver implementation: 1427 1428void BrowserView::TabDetachedAt(WebContents* contents, int index) { 1429 // We use index here rather than comparing |contents| because by this time 1430 // the model has already removed |contents| from its list, so 1431 // browser_->GetActiveWebContents() will return NULL or something else. 1432 if (index == browser_->tab_strip_model()->active_index()) { 1433 // We need to reset the current tab contents to NULL before it gets 1434 // freed. This is because the focus manager performs some operations 1435 // on the selected WebContents when it is removed. 1436 contents_web_view_->SetWebContents(NULL); 1437 infobar_container_->ChangeInfoBarService(NULL); 1438 UpdateDevToolsForContents(NULL); 1439 } 1440} 1441 1442void BrowserView::TabDeactivated(WebContents* contents) { 1443 // We do not store the focus when closing the tab to work-around bug 4633. 1444 // Some reports seem to show that the focus manager and/or focused view can 1445 // be garbage at that point, it is not clear why. 1446 if (!contents->IsBeingDestroyed()) 1447 contents->GetView()->StoreFocus(); 1448} 1449 1450void BrowserView::TabStripEmpty() { 1451 // Make sure all optional UI is removed before we are destroyed, otherwise 1452 // there will be consequences (since our view hierarchy will still have 1453 // references to freed views). 1454 UpdateUIForContents(NULL); 1455} 1456 1457/////////////////////////////////////////////////////////////////////////////// 1458// BrowserView, ui::AcceleratorProvider implementation: 1459 1460bool BrowserView::GetAcceleratorForCommandId(int command_id, 1461 ui::Accelerator* accelerator) { 1462 // Let's let the ToolbarView own the canonical implementation of this method. 1463 return toolbar_->GetAcceleratorForCommandId(command_id, accelerator); 1464} 1465 1466/////////////////////////////////////////////////////////////////////////////// 1467// BrowserView, views::WidgetDelegate implementation: 1468 1469bool BrowserView::CanResize() const { 1470 return true; 1471} 1472 1473bool BrowserView::CanMaximize() const { 1474 return true; 1475} 1476 1477bool BrowserView::CanActivate() const { 1478 if (!AppModalDialogQueue::GetInstance()->active_dialog() || 1479 !AppModalDialogQueue::GetInstance()->active_dialog()->native_dialog()) 1480 return true; 1481 1482#if defined(USE_AURA) && defined(OS_CHROMEOS) 1483 // On Aura window manager controls all windows so settings focus via PostTask 1484 // will make only worse because posted task will keep trying to steal focus. 1485 AppModalDialogQueue::GetInstance()->ActivateModalDialog(); 1486#else 1487 // If another browser is app modal, flash and activate the modal browser. This 1488 // has to be done in a post task, otherwise if the user clicked on a window 1489 // that doesn't have the modal dialog the windows keep trying to get the focus 1490 // from each other on Windows. http://crbug.com/141650. 1491 base::MessageLoop::current()->PostTask( 1492 FROM_HERE, 1493 base::Bind(&BrowserView::ActivateAppModalDialog, 1494 activate_modal_dialog_factory_.GetWeakPtr())); 1495#endif 1496 return false; 1497} 1498 1499string16 BrowserView::GetWindowTitle() const { 1500 return browser_->GetWindowTitleForCurrentTab(); 1501} 1502 1503string16 BrowserView::GetAccessibleWindowTitle() const { 1504 if (IsOffTheRecord()) { 1505 return l10n_util::GetStringFUTF16( 1506 IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, 1507 GetWindowTitle()); 1508 } 1509 return GetWindowTitle(); 1510} 1511 1512views::View* BrowserView::GetInitiallyFocusedView() { 1513 return NULL; 1514} 1515 1516bool BrowserView::ShouldShowWindowTitle() const { 1517 // For Ash only, app host windows do not show an icon, crbug.com/119411. 1518 // Child windows (i.e. popups) do show an icon. 1519 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH && 1520 browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST) 1521 return false; 1522 1523 return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); 1524} 1525 1526gfx::ImageSkia BrowserView::GetWindowAppIcon() { 1527 if (browser_->is_app()) { 1528 WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents(); 1529 extensions::TabHelper* extensions_tab_helper = 1530 contents ? extensions::TabHelper::FromWebContents(contents) : NULL; 1531 if (extensions_tab_helper && extensions_tab_helper->GetExtensionAppIcon()) 1532 return gfx::ImageSkia::CreateFrom1xBitmap( 1533 *extensions_tab_helper->GetExtensionAppIcon()); 1534 } 1535 1536 return GetWindowIcon(); 1537} 1538 1539gfx::ImageSkia BrowserView::GetWindowIcon() { 1540 if (browser_->is_app() || browser_->is_type_popup()) 1541 return browser_->GetCurrentPageIcon().AsImageSkia(); 1542 return gfx::ImageSkia(); 1543} 1544 1545bool BrowserView::ShouldShowWindowIcon() const { 1546 // For Ash only, app host windows do not show an icon, crbug.com/119411. 1547 // Child windows (i.e. popups) do show an icon. 1548 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH && 1549 browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST) 1550 return false; 1551 1552 return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); 1553} 1554 1555bool BrowserView::ExecuteWindowsCommand(int command_id) { 1556 // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND. 1557#if defined(OS_WIN) 1558 if (command_id == IDC_DEBUG_FRAME_TOGGLE) 1559 GetWidget()->DebugToggleFrameType(); 1560 1561 // In Windows 8 metro mode prevent sizing and moving. 1562 if (win8::IsSingleWindowMetroMode()) { 1563 // Windows uses the 4 lower order bits of |notification_code| for type- 1564 // specific information so we must exclude this when comparing. 1565 static const int sc_mask = 0xFFF0; 1566 if (((command_id & sc_mask) == SC_MOVE) || 1567 ((command_id & sc_mask) == SC_SIZE) || 1568 ((command_id & sc_mask) == SC_MAXIMIZE)) 1569 return true; 1570 } 1571#endif 1572 // Translate WM_APPCOMMAND command ids into a command id that the browser 1573 // knows how to handle. 1574 int command_id_from_app_command = GetCommandIDForAppCommandID(command_id); 1575 if (command_id_from_app_command != -1) 1576 command_id = command_id_from_app_command; 1577 1578 return chrome::ExecuteCommand(browser_.get(), command_id); 1579} 1580 1581std::string BrowserView::GetWindowName() const { 1582 return chrome::GetWindowPlacementKey(browser_.get()); 1583} 1584 1585void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds, 1586 ui::WindowShowState show_state) { 1587 // If IsFullscreen() is true, we've just changed into fullscreen mode, and 1588 // we're catching the going-into-fullscreen sizing and positioning calls, 1589 // which we want to ignore. 1590 if (!ShouldSaveOrRestoreWindowPos()) 1591 return; 1592 1593 if (!IsFullscreen() && chrome::ShouldSaveWindowPlacement(browser_.get())) { 1594 WidgetDelegate::SaveWindowPlacement(bounds, show_state); 1595 chrome::SaveWindowPlacement(browser_.get(), bounds, show_state); 1596 } 1597} 1598 1599bool BrowserView::GetSavedWindowPlacement( 1600 gfx::Rect* bounds, 1601 ui::WindowShowState* show_state) const { 1602 if (!ShouldSaveOrRestoreWindowPos()) 1603 return false; 1604 chrome::GetSavedWindowBoundsAndShowState(browser_.get(), bounds, show_state); 1605 1606 if (browser_->is_type_popup() && 1607 !browser_->is_app() && 1608 !browser_->is_devtools()) { 1609 // This is non-app popup window. The value passed in |bounds| represents 1610 // two pieces of information: 1611 // - the position of the window, in screen coordinates (outer position). 1612 // - the size of the content area (inner size). 1613 // We need to use these values to determine the appropriate size and 1614 // position of the resulting window. 1615 if (IsToolbarVisible()) { 1616 // If we're showing the toolbar, we need to adjust |*bounds| to include 1617 // its desired height, since the toolbar is considered part of the 1618 // window's client area as far as GetWindowBoundsForClientBounds is 1619 // concerned... 1620 bounds->set_height( 1621 bounds->height() + toolbar_->GetPreferredSize().height()); 1622 } 1623 1624 gfx::Rect window_rect = frame_->non_client_view()-> 1625 GetWindowBoundsForClientBounds(*bounds); 1626 window_rect.set_origin(bounds->origin()); 1627 1628 // When we are given x/y coordinates of 0 on a created popup window, 1629 // assume none were given by the window.open() command. 1630 if (window_rect.x() == 0 && window_rect.y() == 0) { 1631 gfx::Size size = window_rect.size(); 1632 window_rect.set_origin( 1633 WindowSizer::GetDefaultPopupOrigin(size, 1634 browser_->host_desktop_type())); 1635 } 1636 1637 *bounds = window_rect; 1638 *show_state = ui::SHOW_STATE_NORMAL; 1639 } 1640 1641 // We return true because we can _always_ locate reasonable bounds using the 1642 // WindowSizer, and we don't want to trigger the Window's built-in "size to 1643 // default" handling because the browser window has no default preferred 1644 // size. 1645 return true; 1646} 1647 1648views::View* BrowserView::GetContentsView() { 1649 return contents_web_view_; 1650} 1651 1652views::ClientView* BrowserView::CreateClientView(views::Widget* widget) { 1653 return this; 1654} 1655 1656void BrowserView::OnWidgetActivationChanged(views::Widget* widget, 1657 bool active) { 1658 if (active) 1659 BrowserList::SetLastActive(browser_.get()); 1660} 1661 1662void BrowserView::OnWindowBeginUserBoundsChange() { 1663 WebContents* web_contents = GetActiveWebContents(); 1664 if (!web_contents) 1665 return; 1666 web_contents->GetRenderViewHost()->NotifyMoveOrResizeStarted(); 1667} 1668 1669void BrowserView::OnWidgetMove() { 1670 if (!initialized_) { 1671 // Creating the widget can trigger a move. Ignore it until we've initialized 1672 // things. 1673 return; 1674 } 1675 1676 // Cancel any tabstrip animations, some of them may be invalidated by the 1677 // window being repositioned. 1678 // Comment out for one cycle to see if this fixes dist tests. 1679 // tabstrip_->DestroyDragController(); 1680 1681 // status_bubble_ may be NULL if this is invoked during construction. 1682 if (status_bubble_.get()) 1683 status_bubble_->Reposition(); 1684 1685 BookmarkBubbleView::Hide(); 1686 1687 // Close the omnibox popup, if any. 1688 LocationBarView* location_bar_view = GetLocationBarView(); 1689 if (location_bar_view) 1690 location_bar_view->GetLocationEntry()->CloseOmniboxPopup(); 1691} 1692 1693views::Widget* BrowserView::GetWidget() { 1694 return View::GetWidget(); 1695} 1696 1697const views::Widget* BrowserView::GetWidget() const { 1698 return View::GetWidget(); 1699} 1700 1701void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) { 1702 // This should be in the order of pane traversal of the panes using F6 1703 // (Windows) or Ctrl+Back/Forward (Chrome OS). If one of these is 1704 // invisible or has no focusable children, it will be automatically 1705 // skipped. 1706 panes->push_back(toolbar_); 1707 if (bookmark_bar_view_.get()) 1708 panes->push_back(bookmark_bar_view_.get()); 1709 if (infobar_container_) 1710 panes->push_back(infobar_container_); 1711 if (download_shelf_.get()) 1712 panes->push_back(download_shelf_.get()); 1713 panes->push_back(GetTabContentsContainerView()); 1714 if (devtools_container_->visible()) 1715 panes->push_back(devtools_container_); 1716} 1717 1718/////////////////////////////////////////////////////////////////////////////// 1719// BrowserView, views::ClientView overrides: 1720 1721bool BrowserView::CanClose() { 1722 // You cannot close a frame for which there is an active originating drag 1723 // session. 1724 if (tabstrip_ && !tabstrip_->IsTabStripCloseable()) 1725 return false; 1726 1727 // Give beforeunload handlers the chance to cancel the close before we hide 1728 // the window below. 1729 if (!browser_->ShouldCloseWindow()) 1730 return false; 1731 1732 bool fast_tab_closing_enabled = 1733 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload); 1734 1735 if (!browser_->tab_strip_model()->empty()) { 1736 // Tab strip isn't empty. Hide the frame (so it appears to have closed 1737 // immediately) and close all the tabs, allowing the renderers to shut 1738 // down. When the tab strip is empty we'll be called back again. 1739 frame_->Hide(); 1740 browser_->OnWindowClosing(); 1741 if (fast_tab_closing_enabled) 1742 browser_->tab_strip_model()->CloseAllTabs(); 1743 return false; 1744 } else if (fast_tab_closing_enabled && 1745 !browser_->HasCompletedUnloadProcessing()) { 1746 // The browser needs to finish running unload handlers. 1747 // Hide the frame (so it appears to have closed immediately), and 1748 // the browser will call us back again when it is ready to close. 1749 frame_->Hide(); 1750 return false; 1751 } 1752 1753 // Empty TabStripModel, it's now safe to allow the Window to be closed. 1754 content::NotificationService::current()->Notify( 1755 chrome::NOTIFICATION_WINDOW_CLOSED, 1756 content::Source<gfx::NativeWindow>(frame_->GetNativeWindow()), 1757 content::NotificationService::NoDetails()); 1758 return true; 1759} 1760 1761int BrowserView::NonClientHitTest(const gfx::Point& point) { 1762 return GetBrowserViewLayout()->NonClientHitTest(point); 1763} 1764 1765gfx::Size BrowserView::GetMinimumSize() { 1766 return GetBrowserViewLayout()->GetMinimumSize(); 1767} 1768 1769/////////////////////////////////////////////////////////////////////////////// 1770// BrowserView, views::View overrides: 1771 1772const char* BrowserView::GetClassName() const { 1773 return kViewClassName; 1774} 1775 1776void BrowserView::Layout() { 1777 if (ignore_layout_) 1778 return; 1779 1780 views::View::Layout(); 1781 1782 // TODO(jamescook): Why was this in the middle of layout code? 1783 toolbar_->location_bar()->SetLocationEntryFocusable(IsToolbarVisible()); 1784 1785 // The status bubble position requires that all other layout finish first. 1786 LayoutStatusBubble(); 1787} 1788 1789void BrowserView::PaintChildren(gfx::Canvas* canvas) { 1790 // Paint the |infobar_container_| last so that it may paint its 1791 // overlapping tabs. 1792 for (int i = 0; i < child_count(); ++i) { 1793 View* child = child_at(i); 1794 if (child != infobar_container_ && !child->layer()) 1795 child->Paint(canvas); 1796 } 1797 1798 infobar_container_->Paint(canvas); 1799} 1800 1801void BrowserView::ViewHierarchyChanged( 1802 const ViewHierarchyChangedDetails& details) { 1803 if (!initialized_ && details.is_add && details.child == this && GetWidget()) { 1804 InitViews(); 1805 initialized_ = true; 1806 } 1807} 1808 1809void BrowserView::ChildPreferredSizeChanged(View* child) { 1810 Layout(); 1811} 1812 1813void BrowserView::GetAccessibleState(ui::AccessibleViewState* state) { 1814 state->role = ui::AccessibilityTypes::ROLE_CLIENT; 1815} 1816 1817/////////////////////////////////////////////////////////////////////////////// 1818// BrowserView, ui::AcceleratorTarget overrides: 1819 1820bool BrowserView::AcceleratorPressed(const ui::Accelerator& accelerator) { 1821#if defined(OS_CHROMEOS) 1822 // If accessibility is enabled, stop speech and return false so that key 1823 // combinations involving Search can be used for extra accessibility 1824 // functionality. 1825 if (accelerator.key_code() == ui::VKEY_LWIN && 1826 g_browser_process->local_state()->GetBoolean( 1827 prefs::kSpokenFeedbackEnabled)) { 1828 TtsController::GetInstance()->Stop(); 1829 return false; 1830 } 1831#endif 1832 1833 std::map<ui::Accelerator, int>::const_iterator iter = 1834 accelerator_table_.find(accelerator); 1835 DCHECK(iter != accelerator_table_.end()); 1836 int command_id = iter->second; 1837 1838 chrome::BrowserCommandController* controller = browser_->command_controller(); 1839 if (!controller->block_command_execution()) 1840 UpdateAcceleratorMetrics(accelerator, command_id); 1841 return chrome::ExecuteCommand(browser_.get(), command_id); 1842} 1843 1844/////////////////////////////////////////////////////////////////////////////// 1845// BrowserView, OmniboxPopupModelObserver overrides: 1846void BrowserView::OnOmniboxPopupShownOrHidden() { 1847 infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight()); 1848} 1849 1850/////////////////////////////////////////////////////////////////////////////// 1851// BrowserView, ImmersiveModeController::Delegate overrides: 1852 1853BookmarkBarView* BrowserView::GetBookmarkBar() { 1854 return bookmark_bar_view_.get(); 1855} 1856 1857FullscreenController* BrowserView::GetFullscreenController() { 1858 // Cannot be injected into ImmersiveModeController because it is constructed 1859 // after BrowserView. 1860 return browser()->fullscreen_controller(); 1861} 1862 1863void BrowserView::FullscreenStateChanged() { 1864 if (IsFullscreen()) { 1865 ProcessFullscreen(true, FOR_DESKTOP, GURL(), 1866 FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION); 1867 } else { 1868 ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE); 1869 } 1870} 1871 1872void BrowserView::SetImmersiveStyle(bool immersive) { 1873 // Only the tab strip changes its painting style for immersive fullscreen. 1874 if (tabstrip_) 1875 tabstrip_->SetImmersiveStyle(immersive); 1876} 1877 1878WebContents* BrowserView::GetWebContents() { 1879 return GetActiveWebContents(); 1880} 1881 1882/////////////////////////////////////////////////////////////////////////////// 1883// BrowserView, InfoBarContainer::Delegate overrides: 1884 1885SkColor BrowserView::GetInfoBarSeparatorColor() const { 1886 // NOTE: Keep this in sync with ToolbarView::OnPaint()! 1887 return (IsTabStripVisible() || !frame_->ShouldUseNativeFrame()) ? 1888 ThemeProperties::GetDefaultColor( 1889 ThemeProperties::COLOR_TOOLBAR_SEPARATOR) : 1890 SK_ColorBLACK; 1891} 1892 1893void BrowserView::InfoBarContainerStateChanged(bool is_animating) { 1894 ToolbarSizeChanged(is_animating); 1895} 1896 1897bool BrowserView::DrawInfoBarArrows(int* x) const { 1898 if (x) { 1899 const LocationIconView* location_icon_view = 1900 toolbar_->location_bar()->location_icon_view(); 1901 gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint()); 1902 ConvertPointToTarget(location_icon_view, this, &icon_center); 1903 *x = icon_center.x(); 1904 } 1905 return true; 1906} 1907 1908bool BrowserView::SplitHandleMoved(views::SingleSplitView* sender) { 1909 for (int i = 0; i < sender->child_count(); ++i) 1910 sender->child_at(i)->InvalidateLayout(); 1911 SchedulePaint(); 1912 Layout(); 1913 return false; 1914} 1915 1916void BrowserView::OnSysColorChange() { 1917 chrome::MaybeShowInvertBubbleView(browser_.get(), contents_container_); 1918} 1919 1920void BrowserView::InitViews() { 1921 GetWidget()->AddObserver(this); 1922 1923 // Stow a pointer to this object onto the window handle so that we can get at 1924 // it later when all we have is a native view. 1925 GetWidget()->SetNativeWindowProperty(kBrowserViewKey, this); 1926 1927 // Stow a pointer to the browser's profile onto the window handle so that we 1928 // can get it later when all we have is a native view. 1929 GetWidget()->SetNativeWindowProperty(Profile::kProfileKey, 1930 browser_->profile()); 1931 1932 // Start a hung plugin window detector for this browser object (as long as 1933 // hang detection is not disabled). 1934 if (!CommandLine::ForCurrentProcess()->HasSwitch( 1935 switches::kDisableHangMonitor)) { 1936 InitHangMonitor(); 1937 } 1938 1939 LoadAccelerators(); 1940 1941 infobar_container_ = new InfoBarContainerView(this); 1942 AddChildView(infobar_container_); 1943 1944 contents_web_view_ = new views::WebView(browser_->profile()); 1945 contents_web_view_->set_id(VIEW_ID_TAB_CONTAINER); 1946 contents_web_view_->SetEmbedFullscreenWidgetMode( 1947 implicit_cast<content::WebContentsDelegate*>(browser_.get())-> 1948 EmbedsFullscreenWidget()); 1949 contents_container_ = new ContentsContainer(contents_web_view_); 1950 1951 SkColor bg_color = GetWidget()->GetThemeProvider()-> 1952 GetColor(ThemeProperties::COLOR_TOOLBAR); 1953 1954 devtools_container_ = new views::WebView(browser_->profile()); 1955 devtools_container_->set_id(VIEW_ID_DEV_TOOLS_DOCKED); 1956 devtools_container_->SetVisible(false); 1957 1958 views::View* contents_container_view = contents_container_; 1959 1960 contents_split_ = new views::SingleSplitView( 1961 contents_container_view, 1962 devtools_container_, 1963 views::SingleSplitView::VERTICAL_SPLIT, 1964 this); 1965 contents_split_->set_id(VIEW_ID_CONTENTS_SPLIT); 1966 contents_split_->SetAccessibleName( 1967 l10n_util::GetStringUTF16(IDS_ACCNAME_WEB_CONTENTS)); 1968 contents_split_->set_background( 1969 views::Background::CreateSolidBackground(bg_color)); 1970 AddChildView(contents_split_); 1971 set_contents_view(contents_split_); 1972 1973 InitStatusBubble(); 1974 1975 // Top container holds tab strip and toolbar and lives at the front of the 1976 // view hierarchy. 1977 top_container_ = new TopContainerView(this); 1978 AddChildView(top_container_); 1979 1980 // TabStrip takes ownership of the controller. 1981 BrowserTabStripController* tabstrip_controller = 1982 new BrowserTabStripController(browser_.get(), 1983 browser_->tab_strip_model()); 1984 tabstrip_ = new TabStrip(tabstrip_controller); 1985 top_container_->AddChildView(tabstrip_); 1986 tabstrip_controller->InitFromModel(tabstrip_); 1987 1988 toolbar_ = new ToolbarView(browser_.get()); 1989 top_container_->AddChildView(toolbar_); 1990 toolbar_->Init(); 1991 1992 // Create do-nothing view for the sake of controlling the z-order of the find 1993 // bar widget. 1994 find_bar_host_view_ = new View(); 1995 AddChildView(find_bar_host_view_); 1996 1997 if (window_switcher_button_) 1998 AddChildView(window_switcher_button_); 1999 2000 immersive_mode_controller_->Init(this, GetWidget(), top_container_); 2001 2002 BrowserViewLayout* browser_view_layout = new BrowserViewLayout; 2003 browser_view_layout->Init(new BrowserViewLayoutDelegateImpl(this), 2004 browser(), 2005 this, 2006 top_container_, 2007 tabstrip_, 2008 toolbar_, 2009 infobar_container_, 2010 contents_split_, 2011 contents_container_, 2012 immersive_mode_controller_.get()); 2013 SetLayoutManager(browser_view_layout); 2014 2015#if defined(OS_WIN) && !defined(USE_AURA) 2016 // Create a custom JumpList and add it to an observer of TabRestoreService 2017 // so we can update the custom JumpList when a tab is added or removed. 2018 if (JumpList::Enabled()) { 2019 load_complete_listener_.reset(new LoadCompleteListener(this)); 2020 } 2021#endif 2022 2023 GetLocationBar()->GetLocationEntry()->model()->popup_model()->AddObserver( 2024 this); 2025 2026 // We're now initialized and ready to process Layout requests. 2027 ignore_layout_ = false; 2028} 2029 2030void BrowserView::LoadingAnimationCallback() { 2031 base::TimeTicks now = base::TimeTicks::Now(); 2032 if (!last_animation_time_.is_null()) { 2033 UMA_HISTOGRAM_TIMES( 2034 "Tabs.LoadingAnimationTime", 2035 now - last_animation_time_); 2036 } 2037 last_animation_time_ = now; 2038 if (browser_->is_type_tabbed()) { 2039 // Loading animations are shown in the tab for tabbed windows. We check the 2040 // browser type instead of calling IsTabStripVisible() because the latter 2041 // will return false for fullscreen windows, but we still need to update 2042 // their animations (so that when they come out of fullscreen mode they'll 2043 // be correct). 2044 tabstrip_->UpdateLoadingAnimations(); 2045 } else if (ShouldShowWindowIcon()) { 2046 // ... or in the window icon area for popups and app windows. 2047 WebContents* web_contents = 2048 browser_->tab_strip_model()->GetActiveWebContents(); 2049 // GetActiveWebContents can return NULL for example under Purify when 2050 // the animations are running slowly and this function is called on a timer 2051 // through LoadingAnimationCallback. 2052 frame_->UpdateThrobber(web_contents && web_contents->IsLoading()); 2053 } 2054} 2055 2056void BrowserView::OnLoadCompleted() { 2057#if defined(OS_WIN) && !defined(USE_AURA) 2058 DCHECK(!jumplist_); 2059 jumplist_ = new JumpList(); 2060 jumplist_->AddObserver(browser_->profile()); 2061#endif 2062} 2063 2064BrowserViewLayout* BrowserView::GetBrowserViewLayout() const { 2065 return static_cast<BrowserViewLayout*>(GetLayoutManager()); 2066} 2067 2068void BrowserView::LayoutStatusBubble() { 2069 // In restored mode, the client area has a client edge between it and the 2070 // frame. 2071 int overlap = StatusBubbleViews::kShadowThickness; 2072 // The extra pixels defined by kClientEdgeThickness is only drawn in frame 2073 // content border on windows for non-aura build. 2074#if !defined(USE_ASH) 2075 overlap += 2076 IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness; 2077#endif 2078 int height = status_bubble_->GetPreferredSize().height(); 2079 int contents_height = status_bubble_->base_view()->bounds().height(); 2080 gfx::Point origin(-overlap, contents_height - height + overlap); 2081 status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height); 2082} 2083 2084bool BrowserView::MaybeShowBookmarkBar(WebContents* contents) { 2085 bool show_bookmark_bar = contents && 2086 browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR); 2087 if (!show_bookmark_bar && !bookmark_bar_view_.get()) 2088 return false; 2089 if (!bookmark_bar_view_.get()) { 2090 bookmark_bar_view_.reset(new BookmarkBarView(browser_.get(), this)); 2091 bookmark_bar_view_->set_owned_by_client(); 2092 bookmark_bar_view_->set_background( 2093 new BookmarkExtensionBackground(this, 2094 bookmark_bar_view_.get(), 2095 browser_.get())); 2096 bookmark_bar_view_->SetBookmarkBarState( 2097 browser_->bookmark_bar_state(), 2098 BookmarkBar::DONT_ANIMATE_STATE_CHANGE); 2099 GetBrowserViewLayout()->set_bookmark_bar(bookmark_bar_view_.get()); 2100 } 2101 bookmark_bar_view_->SetVisible(show_bookmark_bar); 2102 bookmark_bar_view_->SetPageNavigator(contents); 2103 2104 // Update parenting for the bookmark bar. This may detach it from all views. 2105 bool needs_layout = false; 2106 views::View* new_parent = NULL; 2107 if (show_bookmark_bar) { 2108 if (bookmark_bar_view_->IsDetached()) 2109 new_parent = this; 2110 else 2111 new_parent = top_container_; 2112 } 2113 if (new_parent != bookmark_bar_view_->parent()) { 2114 SetBookmarkBarParent(new_parent); 2115 needs_layout = true; 2116 } 2117 2118 // Check for updates to the desired size. 2119 if (bookmark_bar_view_->GetPreferredSize().height() != 2120 bookmark_bar_view_->height()) 2121 needs_layout = true; 2122 2123 return needs_layout; 2124} 2125 2126void BrowserView::SetBookmarkBarParent(views::View* new_parent) { 2127 if (new_parent == this) { 2128 // Add it underneath |top_container_| or at the end if top container isn't 2129 // found. 2130 int top_container_index = GetIndexOf(top_container_); 2131 if (top_container_index >= 0) 2132 AddChildViewAt(bookmark_bar_view_.get(), top_container_index); 2133 else 2134 AddChildView(bookmark_bar_view_.get()); 2135 } else if (new_parent) { 2136 // No special stacking is required for other parents. 2137 new_parent->AddChildView(bookmark_bar_view_.get()); 2138 } else { 2139 // Bookmark bar is being detached from all views because it is hidden. 2140 bookmark_bar_view_->parent()->RemoveChildView(bookmark_bar_view_.get()); 2141 } 2142} 2143 2144bool BrowserView::MaybeShowInfoBar(WebContents* contents) { 2145 // TODO(beng): Remove this function once the interface between 2146 // InfoBarContainer, DownloadShelfView and WebContents and this 2147 // view is sorted out. 2148 return true; 2149} 2150 2151void BrowserView::UpdateDevToolsForContents(WebContents* web_contents) { 2152 DevToolsWindow* new_devtools_window = web_contents ? 2153 DevToolsWindow::GetDockedInstanceForInspectedTab(web_contents) : NULL; 2154 // Fast return in case of the same window having same orientation. 2155 if (devtools_window_ == new_devtools_window) { 2156 if (!new_devtools_window || 2157 (new_devtools_window->dock_side() == devtools_dock_side_)) { 2158 return; 2159 } 2160 } 2161 2162 // Replace tab contents. 2163 if (devtools_window_ != new_devtools_window) { 2164 devtools_container_->SetWebContents( 2165 new_devtools_window ? new_devtools_window->web_contents() : NULL); 2166 } 2167 2168 // Store last used position. 2169 if (devtools_window_) { 2170 int split_size = contents_split_->GetDividerSize(); 2171 if (devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT) { 2172 devtools_window_->SetWidth(contents_split_->width() - 2173 split_size - contents_split_->divider_offset()); 2174 } else if (devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_BOTTOM) { 2175 devtools_window_->SetHeight(contents_split_->height() - 2176 split_size - contents_split_->divider_offset()); 2177 } 2178 } 2179 2180 // Show / hide container if necessary. Changing dock orientation is 2181 // hide + show. 2182 bool should_hide = devtools_window_ && (!new_devtools_window || 2183 devtools_dock_side_ != new_devtools_window->dock_side()); 2184 bool should_show = new_devtools_window && (!devtools_window_ || should_hide); 2185 2186 if (should_hide) 2187 HideDevToolsContainer(); 2188 2189 devtools_window_ = new_devtools_window; 2190 2191 if (should_show) { 2192 devtools_dock_side_ = new_devtools_window->dock_side(); 2193 ShowDevToolsContainer(); 2194 } else if (new_devtools_window) { 2195 UpdateDevToolsSplitPosition(); 2196 contents_split_->Layout(); 2197 } 2198} 2199 2200void BrowserView::ShowDevToolsContainer() { 2201 if (!devtools_focus_tracker_.get()) { 2202 // Install devtools focus tracker when dev tools window is shown for the 2203 // first time. 2204 devtools_focus_tracker_.reset( 2205 new views::ExternalFocusTracker(devtools_container_, 2206 GetFocusManager())); 2207 } 2208 2209 gfx::Size min_devtools_size(devtools_window_->GetMinimumWidth(), 2210 devtools_window_->GetMinimumHeight()); 2211 devtools_container_->SetPreferredSize(min_devtools_size); 2212 2213 devtools_container_->SetVisible(true); 2214 devtools_dock_side_ = devtools_window_->dock_side(); 2215 bool dock_to_right = devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT; 2216 contents_split_->set_orientation( 2217 dock_to_right ? views::SingleSplitView::HORIZONTAL_SPLIT 2218 : views::SingleSplitView::VERTICAL_SPLIT); 2219 UpdateDevToolsSplitPosition(); 2220 contents_split_->InvalidateLayout(); 2221 Layout(); 2222} 2223 2224void BrowserView::HideDevToolsContainer() { 2225 // Restore focus to the last focused view when hiding devtools window. 2226 devtools_focus_tracker_->FocusLastFocusedExternalView(); 2227 devtools_container_->SetVisible(false); 2228 contents_split_->InvalidateLayout(); 2229 Layout(); 2230} 2231 2232void BrowserView::UpdateDevToolsSplitPosition() { 2233 contents_split_->set_resize_disabled( 2234 devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED); 2235 int split_size = contents_split_->GetDividerSize(); 2236 if (devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) { 2237 int split_offset = contents_split_->width() - split_size - 2238 devtools_window_->GetWidth(contents_split_->width()); 2239 contents_split_->set_divider_offset(split_offset); 2240 } else { 2241 int height = devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED ? 2242 devtools_window_->GetMinimizedHeight() : 2243 devtools_window_->GetHeight(contents_split_->height()); 2244 int split_offset = contents_split_->height() - split_size - height; 2245 contents_split_->set_divider_offset(split_offset); 2246 } 2247} 2248 2249void BrowserView::UpdateUIForContents(WebContents* contents) { 2250 bool needs_layout = MaybeShowBookmarkBar(contents); 2251 // TODO(jamescook): This function always returns true. Remove it and figure 2252 // out when layout is actually required. 2253 needs_layout |= MaybeShowInfoBar(contents); 2254 if (needs_layout) 2255 Layout(); 2256} 2257 2258void BrowserView::ProcessFullscreen(bool fullscreen, 2259 FullscreenType type, 2260 const GURL& url, 2261 FullscreenExitBubbleType bubble_type) { 2262 // Reduce jankiness during the following position changes by: 2263 // * Hiding the window until it's in the final position 2264 // * Ignoring all intervening Layout() calls, which resize the webpage and 2265 // thus are slow and look ugly 2266 ignore_layout_ = true; 2267 LocationBarView* location_bar = GetLocationBarView(); 2268#if defined(OS_WIN) && !defined(USE_AURA) 2269 OmniboxViewWin* omnibox_win = 2270 GetOmniboxViewWin(location_bar->GetLocationEntry()); 2271#endif 2272 2273 if (type == FOR_METRO || !fullscreen) { 2274 // Hide the fullscreen bubble as soon as possible, since the mode toggle can 2275 // take enough time for the user to notice. 2276 fullscreen_bubble_.reset(); 2277 } 2278 2279 if (fullscreen) { 2280 // Move focus out of the location bar if necessary. 2281 views::FocusManager* focus_manager = GetFocusManager(); 2282 DCHECK(focus_manager); 2283 // Look for focus in the location bar itself or any child view. 2284 if (location_bar->Contains(focus_manager->GetFocusedView())) 2285 focus_manager->ClearFocus(); 2286 2287#if defined(OS_WIN) && !defined(USE_AURA) 2288 if (omnibox_win) { 2289 // If we don't hide the edit and force it to not show until we come out of 2290 // fullscreen, then if the user was on the New Tab Page, the edit contents 2291 // will appear atop the web contents once we go into fullscreen mode. This 2292 // has something to do with how we move the main window while it's hidden; 2293 // if we don't hide the main window below, we don't get this problem. 2294 omnibox_win->set_force_hidden(true); 2295 ShowWindow(omnibox_win->m_hWnd, SW_HIDE); 2296 } 2297#endif 2298 } 2299#if defined(OS_WIN) && !defined(USE_AURA) 2300 views::ScopedFullscreenVisibility visibility(frame_->GetNativeView()); 2301#endif 2302 2303 if (type == FOR_METRO) { 2304#if defined(OS_WIN) && !defined(USE_AURA) 2305 // Enter metro snap mode. 2306 static_cast<views::NativeWidgetWin*>( 2307 frame_->native_widget())->SetMetroSnapFullscreen(fullscreen); 2308#endif 2309 } else { 2310 // Toggle fullscreen mode. 2311 frame_->SetFullscreen(fullscreen); 2312 } 2313 2314 // Enable immersive before the browser refreshes its list of enabled commands. 2315 if (ShouldUseImmersiveFullscreenForUrl(url)) 2316 immersive_mode_controller_->SetEnabled(fullscreen); 2317 2318 browser_->WindowFullscreenStateChanged(); 2319 2320 if (fullscreen) { 2321 if (!chrome::IsRunningInAppMode() && type != FOR_METRO) 2322 UpdateFullscreenExitBubbleContent(url, bubble_type); 2323 } else { 2324#if defined(OS_WIN) && !defined(USE_AURA) 2325 if (omnibox_win) { 2326 // Show the edit again since we're no longer in fullscreen mode. 2327 omnibox_win->set_force_hidden(false); 2328 ShowWindow(omnibox_win->m_hWnd, SW_SHOW); 2329 } 2330#endif 2331 } 2332 2333 // Undo our anti-jankiness hacks and force a re-layout. We also need to 2334 // recompute the height of the infobar top arrow because toggling in and out 2335 // of fullscreen changes it. Calling ToolbarSizeChanged() will do both these 2336 // things since it computes the arrow height directly and forces a layout 2337 // indirectly via UpdateUIForContents(). 2338 ignore_layout_ = false; 2339 ToolbarSizeChanged(false); 2340} 2341 2342bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const { 2343 bool is_browser_fullscreen = url.is_empty(); 2344 return ImmersiveFullscreenConfiguration::UseImmersiveFullscreen() && 2345 is_browser_fullscreen && IsBrowserTypeNormal(); 2346} 2347 2348void BrowserView::LoadAccelerators() { 2349#if defined(OS_WIN) && !defined(USE_AURA) 2350 HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME); 2351 DCHECK(accelerator_table); 2352 2353 // We have to copy the table to access its contents. 2354 int count = CopyAcceleratorTable(accelerator_table, 0, 0); 2355 if (count == 0) { 2356 // Nothing to do in that case. 2357 return; 2358 } 2359 2360 ACCEL* accelerators = static_cast<ACCEL*>(malloc(sizeof(ACCEL) * count)); 2361 CopyAcceleratorTable(accelerator_table, accelerators, count); 2362 2363 views::FocusManager* focus_manager = GetFocusManager(); 2364 DCHECK(focus_manager); 2365 2366 // Let's fill our own accelerator table. 2367 for (int i = 0; i < count; ++i) { 2368 ui::Accelerator accelerator( 2369 static_cast<ui::KeyboardCode>(accelerators[i].key), 2370 ui::GetModifiersFromACCEL(accelerators[i])); 2371 accelerator_table_[accelerator] = accelerators[i].cmd; 2372 2373 // Also register with the focus manager. 2374 focus_manager->RegisterAccelerator( 2375 accelerator, ui::AcceleratorManager::kNormalPriority, this); 2376 } 2377 2378 // We don't need the Windows accelerator table anymore. 2379 free(accelerators); 2380#else 2381 views::FocusManager* focus_manager = GetFocusManager(); 2382 DCHECK(focus_manager); 2383 2384 // Let's fill our own accelerator table. 2385 const bool is_app_mode = chrome::IsRunningInForcedAppMode(); 2386 const std::vector<chrome::AcceleratorMapping> accelerator_list( 2387 chrome::GetAcceleratorList()); 2388 for (std::vector<chrome::AcceleratorMapping>::const_iterator it = 2389 accelerator_list.begin(); it != accelerator_list.end(); ++it) { 2390 // In app mode, only allow accelerators of white listed commands to pass 2391 // through. 2392 if (is_app_mode && !chrome::IsCommandAllowedInAppMode(it->command_id)) 2393 continue; 2394 2395 ui::Accelerator accelerator(it->keycode, it->modifiers); 2396 accelerator_table_[accelerator] = it->command_id; 2397 2398 // Also register with the focus manager. 2399 focus_manager->RegisterAccelerator( 2400 accelerator, ui::AcceleratorManager::kNormalPriority, this); 2401 } 2402#endif 2403} 2404 2405int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const { 2406#if defined(OS_WIN) 2407 switch (app_command_id) { 2408 // NOTE: The order here matches the APPCOMMAND declaration order in the 2409 // Windows headers. 2410 case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK; 2411 case APPCOMMAND_BROWSER_FORWARD: return IDC_FORWARD; 2412 case APPCOMMAND_BROWSER_REFRESH: return IDC_RELOAD; 2413 case APPCOMMAND_BROWSER_HOME: return IDC_HOME; 2414 case APPCOMMAND_BROWSER_STOP: return IDC_STOP; 2415 case APPCOMMAND_BROWSER_SEARCH: return IDC_FOCUS_SEARCH; 2416 case APPCOMMAND_HELP: return IDC_HELP_PAGE_VIA_KEYBOARD; 2417 case APPCOMMAND_NEW: return IDC_NEW_TAB; 2418 case APPCOMMAND_OPEN: return IDC_OPEN_FILE; 2419 case APPCOMMAND_CLOSE: return IDC_CLOSE_TAB; 2420 case APPCOMMAND_SAVE: return IDC_SAVE_PAGE; 2421 case APPCOMMAND_PRINT: return IDC_PRINT; 2422 case APPCOMMAND_COPY: return IDC_COPY; 2423 case APPCOMMAND_CUT: return IDC_CUT; 2424 case APPCOMMAND_PASTE: return IDC_PASTE; 2425 2426 // TODO(pkasting): http://b/1113069 Handle these. 2427 case APPCOMMAND_UNDO: 2428 case APPCOMMAND_REDO: 2429 case APPCOMMAND_SPELL_CHECK: 2430 default: return -1; 2431 } 2432#else 2433 // App commands are Windows-specific so there's nothing to do here. 2434 return -1; 2435#endif 2436} 2437 2438void BrowserView::InitHangMonitor() { 2439#if defined(OS_WIN) && !defined(USE_AURA) 2440 PrefService* pref_service = g_browser_process->local_state(); 2441 if (!pref_service) 2442 return; 2443 2444 int plugin_message_response_timeout = 2445 pref_service->GetInteger(prefs::kPluginMessageResponseTimeout); 2446 int hung_plugin_detect_freq = 2447 pref_service->GetInteger(prefs::kHungPluginDetectFrequency); 2448 if ((hung_plugin_detect_freq > 0) && 2449 hung_window_detector_.Initialize(GetWidget()->GetNativeView(), 2450 plugin_message_response_timeout)) { 2451 ticker_.set_tick_interval(hung_plugin_detect_freq); 2452 ticker_.RegisterTickHandler(&hung_window_detector_); 2453 ticker_.Start(); 2454 2455 pref_service->SetInteger(prefs::kPluginMessageResponseTimeout, 2456 plugin_message_response_timeout); 2457 pref_service->SetInteger(prefs::kHungPluginDetectFrequency, 2458 hung_plugin_detect_freq); 2459 } 2460#endif 2461} 2462 2463void BrowserView::UpdateAcceleratorMetrics(const ui::Accelerator& accelerator, 2464 int command_id) { 2465 const ui::KeyboardCode key_code = accelerator.key_code(); 2466 if (command_id == IDC_HELP_PAGE_VIA_KEYBOARD && key_code == ui::VKEY_F1) 2467 content::RecordAction(UserMetricsAction("ShowHelpTabViaF1")); 2468 2469 if (command_id == IDC_BOOKMARK_PAGE) 2470 UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint", 2471 BOOKMARK_ENTRY_POINT_ACCELERATOR, 2472 BOOKMARK_ENTRY_POINT_LIMIT); 2473 2474#if defined(OS_CHROMEOS) 2475 // Collect information about the relative popularity of various accelerators 2476 // on Chrome OS. 2477 switch (command_id) { 2478 case IDC_BACK: 2479 if (key_code == ui::VKEY_BACK) 2480 content::RecordAction(UserMetricsAction("Accel_Back_Backspace")); 2481 else if (key_code == ui::VKEY_BROWSER_BACK) 2482 content::RecordAction(UserMetricsAction("Accel_Back_F1")); 2483 else if (key_code == ui::VKEY_LEFT) 2484 content::RecordAction(UserMetricsAction("Accel_Back_Left")); 2485 break; 2486 case IDC_FORWARD: 2487 if (key_code == ui::VKEY_BACK) 2488 content::RecordAction(UserMetricsAction("Accel_Forward_Backspace")); 2489 else if (key_code == ui::VKEY_BROWSER_FORWARD) 2490 content::RecordAction(UserMetricsAction("Accel_Forward_F2")); 2491 else if (key_code == ui::VKEY_RIGHT) 2492 content::RecordAction(UserMetricsAction("Accel_Forward_Right")); 2493 break; 2494 case IDC_RELOAD: 2495 case IDC_RELOAD_IGNORING_CACHE: 2496 if (key_code == ui::VKEY_R) 2497 content::RecordAction(UserMetricsAction("Accel_Reload_R")); 2498 else if (key_code == ui::VKEY_BROWSER_REFRESH) 2499 content::RecordAction(UserMetricsAction("Accel_Reload_F3")); 2500 break; 2501 case IDC_FOCUS_LOCATION: 2502 if (key_code == ui::VKEY_D) 2503 content::RecordAction(UserMetricsAction("Accel_FocusLocation_D")); 2504 else if (key_code == ui::VKEY_L) 2505 content::RecordAction(UserMetricsAction("Accel_FocusLocation_L")); 2506 break; 2507 case IDC_FOCUS_SEARCH: 2508 if (key_code == ui::VKEY_E) 2509 content::RecordAction(UserMetricsAction("Accel_FocusSearch_E")); 2510 else if (key_code == ui::VKEY_K) 2511 content::RecordAction(UserMetricsAction("Accel_FocusSearch_K")); 2512 break; 2513 default: 2514 // Do nothing. 2515 break; 2516 } 2517#endif 2518} 2519 2520// static 2521BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { 2522 // Create the view and the frame. The frame will attach itself via the view 2523 // so we don't need to do anything with the pointer. 2524 BrowserView* view = new BrowserView(); 2525 view->Init(browser); 2526 (new BrowserFrame(view))->InitBrowserFrame(); 2527 view->GetWidget()->non_client_view()->SetAccessibleName( 2528 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 2529 return view; 2530} 2531 2532void BrowserView::ShowAvatarBubble(WebContents* web_contents, 2533 const gfx::Rect& rect) { 2534 gfx::Point origin(rect.origin()); 2535 views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin); 2536 gfx::Rect bounds(origin, rect.size()); 2537 2538 AvatarMenuBubbleView::ShowBubble(this, views::BubbleBorder::TOP_RIGHT, 2539 views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds, browser_.get()); 2540} 2541 2542void BrowserView::ShowAvatarBubbleFromAvatarButton() { 2543 AvatarMenuButton* button = frame_->GetAvatarMenuButton(); 2544 if (button) 2545 button->ShowAvatarBubble(); 2546} 2547 2548void BrowserView::ShowPasswordGenerationBubble( 2549 const gfx::Rect& rect, 2550 const autofill::PasswordForm& form, 2551 autofill::PasswordGenerator* password_generator) { 2552 // Create a rect in the content bounds that the bubble will point to. 2553 gfx::Point origin(rect.origin()); 2554 views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin); 2555 gfx::Rect bounds(origin, rect.size()); 2556 2557 // Create the bubble. 2558 WebContents* web_contents = GetActiveWebContents(); 2559 if (!web_contents) 2560 return; 2561 2562 PasswordGenerationBubbleView* bubble = 2563 new PasswordGenerationBubbleView( 2564 form, 2565 bounds, 2566 this, 2567 web_contents->GetRenderViewHost(), 2568 PasswordManager::FromWebContents(web_contents), 2569 password_generator, 2570 browser_.get(), 2571 GetWidget()->GetThemeProvider()); 2572 2573 views::BubbleDelegateView::CreateBubble(bubble); 2574 bubble->SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR); 2575 bubble->GetWidget()->Show(); 2576} 2577 2578void BrowserView::OverscrollUpdate(int delta_y) { 2579 if (scroll_end_effect_controller_) 2580 scroll_end_effect_controller_->OverscrollUpdate(delta_y); 2581} 2582 2583int BrowserView::GetRenderViewHeightInsetWithDetachedBookmarkBar() { 2584 if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED || 2585 !bookmark_bar_view_.get() || !bookmark_bar_view_->IsDetached()) { 2586 return 0; 2587 } 2588 // Don't use bookmark_bar_view_->height() which won't be the final height if 2589 // the bookmark bar is animating. 2590 return chrome::kNTPBookmarkBarHeight - 2591 bookmark_bar_view_->GetFullyDetachedToolbarOverlap(); 2592} 2593 2594void BrowserView::DoCutCopyPaste(void (content::RenderWidgetHost::*method)(), 2595#if defined(OS_WIN) 2596 int windows_msg_id, 2597#endif 2598 int command_id) { 2599 WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents(); 2600 if (!contents) 2601 return; 2602 if (DoCutCopyPasteForWebContents(contents, method)) 2603 return; 2604 2605 DevToolsWindow* devtools_window = 2606 DevToolsWindow::GetDockedInstanceForInspectedTab(contents); 2607 if (devtools_window && 2608 DoCutCopyPasteForWebContents(devtools_window->web_contents(), method)) { 2609 return; 2610 } 2611 2612 views::FocusManager* focus_manager = GetFocusManager(); 2613 views::View* focused = focus_manager->GetFocusedView(); 2614 if (focused && 2615 (!strcmp(focused->GetClassName(), views::Textfield::kViewClassName) || 2616 !strcmp(focused->GetClassName(), OmniboxViewViews::kViewClassName))) { 2617 views::Textfield* textfield = static_cast<views::Textfield*>(focused); 2618 textfield->ExecuteCommand(command_id); 2619 return; 2620 } 2621 2622#if defined(OS_WIN) && !defined(USE_AURA) 2623 OmniboxView* omnibox_view = GetLocationBarView()->GetLocationEntry(); 2624 if (omnibox_view->model()->has_focus()) { 2625 OmniboxViewWin* omnibox_win = GetOmniboxViewWin(omnibox_view); 2626 ::SendMessage(omnibox_win->GetNativeView(), windows_msg_id, 0, 0); 2627 } 2628#endif 2629} 2630 2631bool BrowserView::DoCutCopyPasteForWebContents( 2632 WebContents* contents, 2633 void (content::RenderWidgetHost::*method)()) { 2634 gfx::NativeView native_view = contents->GetView()->GetContentNativeView(); 2635 if (!native_view) 2636 return false; 2637#if defined(USE_AURA) 2638 if (native_view->HasFocus()) { 2639#elif defined(OS_WIN) 2640 if (native_view == ::GetFocus()) { 2641#endif 2642 (contents->GetRenderViewHost()->*method)(); 2643 return true; 2644 } 2645 2646 return false; 2647} 2648 2649void BrowserView::ActivateAppModalDialog() const { 2650 // If another browser is app modal, flash and activate the modal browser. 2651 AppModalDialog* active_dialog = 2652 AppModalDialogQueue::GetInstance()->active_dialog(); 2653 if (!active_dialog) 2654 return; 2655 2656 Browser* modal_browser = 2657 chrome::FindBrowserWithWebContents(active_dialog->web_contents()); 2658 if (modal_browser && (browser_ != modal_browser)) { 2659 modal_browser->window()->FlashFrame(true); 2660 modal_browser->window()->Activate(); 2661 } 2662 2663 AppModalDialogQueue::GetInstance()->ActivateModalDialog(); 2664} 2665 2666int BrowserView::GetMaxTopInfoBarArrowHeight() { 2667 int top_arrow_height = 0; 2668 // Only show the arrows when not in fullscreen and when there's no omnibox 2669 // popup. 2670 if (!IsFullscreen() && 2671 !GetLocationBar()->GetLocationEntry()->model()->popup_model()->IsOpen()) { 2672 const LocationIconView* location_icon_view = 2673 toolbar_->location_bar()->location_icon_view(); 2674 // The +1 in the next line creates a 1-px gap between icon and arrow tip. 2675 gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() - 2676 LocationBarView::kIconInternalPadding + 1); 2677 ConvertPointToTarget(location_icon_view, this, &icon_bottom); 2678 gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL)); 2679 ConvertPointToTarget(infobar_container_, this, &infobar_top); 2680 top_arrow_height = infobar_top.y() - icon_bottom.y(); 2681 } 2682 return top_arrow_height; 2683} 2684