| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| |
| #if defined(OS_LINUX) |
| #include <gtk/gtk.h> |
| #endif |
| |
| #include "base/auto_reset.h" |
| #include "base/command_line.h" |
| #include "base/i18n/rtl.h" |
| #include "base/metrics/histogram.h" |
| #include "base/string_number_conversions.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/app/chrome_dll_resource.h" |
| #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| #include "chrome/browser/autocomplete/autocomplete_popup_view.h" |
| #include "chrome/browser/automation/ui_controls.h" |
| #include "chrome/browser/bookmarks/bookmark_utils.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/debugger/devtools_window.h" |
| #include "chrome/browser/download/download_manager.h" |
| #include "chrome/browser/extensions/extension_tab_helper.h" |
| #include "chrome/browser/extensions/extension_tts_api.h" |
| #include "chrome/browser/instant/instant_controller.h" |
| #include "chrome/browser/metrics/user_metrics.h" |
| #include "chrome/browser/ntp_background_util.h" |
| #include "chrome/browser/page_info_window.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/sessions/tab_restore_service.h" |
| #include "chrome/browser/sidebar/sidebar_container.h" |
| #include "chrome/browser/sidebar/sidebar_manager.h" |
| #include "chrome/browser/tabs/tab_strip_model.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/browser/ui/toolbar/wrench_menu_model.h" |
| #include "chrome/browser/ui/view_ids.h" |
| #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" |
| #include "chrome/browser/ui/views/browser_dialogs.h" |
| #include "chrome/browser/ui/views/default_search_view.h" |
| #include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h" |
| #include "chrome/browser/ui/views/download/download_shelf_view.h" |
| #include "chrome/browser/ui/views/frame/browser_view_layout.h" |
| #include "chrome/browser/ui/views/frame/contents_container.h" |
| #include "chrome/browser/ui/views/fullscreen_exit_bubble.h" |
| #include "chrome/browser/ui/views/infobars/infobar_container_view.h" |
| #include "chrome/browser/ui/views/location_bar/location_icon_view.h" |
| #include "chrome/browser/ui/views/status_bubble_views.h" |
| #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h" |
| #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" |
| #include "chrome/browser/ui/views/tabs/tab_strip_factory.h" |
| #include "chrome/browser/ui/views/theme_install_bubble_view.h" |
| #include "chrome/browser/ui/views/toolbar_view.h" |
| #include "chrome/browser/ui/views/update_recommended_message_box.h" |
| #include "chrome/browser/ui/views/window.h" |
| #include "chrome/browser/ui/webui/bug_report_ui.h" |
| #include "chrome/browser/ui/window_sizer.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension_resource.h" |
| #include "chrome/common/native_window_notification_source.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/browser/renderer_host/render_widget_host_view.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "content/browser/tab_contents/tab_contents_view.h" |
| #include "content/common/notification_service.h" |
| #include "grit/app_resources.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/locale_settings.h" |
| #include "grit/theme_resources.h" |
| #include "grit/webkit_resources.h" |
| #include "ui/base/accessibility/accessible_view_state.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/canvas_skia.h" |
| #include "views/controls/single_split_view.h" |
| #include "views/events/event.h" |
| #include "views/focus/external_focus_tracker.h" |
| #include "views/focus/view_storage.h" |
| #include "views/layout/grid_layout.h" |
| #include "views/widget/root_view.h" |
| #include "views/window/dialog_delegate.h" |
| #include "views/window/window.h" |
| |
| #if defined(OS_WIN) |
| #include "chrome/browser/aeropeek_manager.h" |
| #include "chrome/browser/jumplist_win.h" |
| #include "ui/base/message_box_win.h" |
| #include "ui/base/view_prop.h" |
| #include "views/window/window_win.h" |
| #elif defined(OS_LINUX) |
| #include "chrome/browser/ui/views/accelerator_table_gtk.h" |
| #include "views/window/hit_test.h" |
| #include "views/window/window_gtk.h" |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/ui/views/keyboard_overlay_dialog_view.h" |
| #endif |
| |
| using base::TimeDelta; |
| using views::ColumnSet; |
| using views::GridLayout; |
| |
| // The height of the status bubble. |
| static const int kStatusBubbleHeight = 20; |
| // The name of a key to store on the window handle so that other code can |
| // locate this object using just the handle. |
| static const char* const kBrowserViewKey = "__BROWSER_VIEW__"; |
| // How frequently we check for hung plugin windows. |
| static const int kDefaultHungPluginDetectFrequency = 2000; |
| // How long do we wait before we consider a window hung (in ms). |
| static const int kDefaultPluginMessageResponseTimeout = 30000; |
| // The number of milliseconds between loading animation frames. |
| static const int kLoadingAnimationFrameTimeMs = 30; |
| // The amount of space we expect the window border to take up. |
| static const int kWindowBorderWidth = 5; |
| |
| // How round the 'new tab' style bookmarks bar is. |
| static const int kNewtabBarRoundness = 5; |
| // ------------ |
| |
| // Returned from BrowserView::GetClassName. |
| const char BrowserView::kViewClassName[] = "browser/ui/views/BrowserView"; |
| |
| #if defined(OS_CHROMEOS) |
| // Get a normal browser window of given |profile| to use as dialog parent |
| // if given |browser| is not one. Otherwise, returns browser window of |
| // |browser|. If |profile| is NULL, |browser|'s profile is used to find the |
| // normal browser. |
| static gfx::NativeWindow GetNormalBrowserWindowForBrowser(Browser* browser, |
| Profile* profile) { |
| if (browser->type() != Browser::TYPE_NORMAL) { |
| Browser* normal_browser = BrowserList::FindBrowserWithType( |
| profile ? profile : browser->profile(), |
| Browser::TYPE_NORMAL, true); |
| if (normal_browser && normal_browser->window()) |
| return normal_browser->window()->GetNativeHandle(); |
| } |
| |
| return browser->window()->GetNativeHandle(); |
| } |
| #endif // defined(OS_CHROMEOS) |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BookmarkExtensionBackground, private: |
| // This object serves as the views::Background object which is used to layout |
| // and paint the bookmark bar. |
| class BookmarkExtensionBackground : public views::Background { |
| public: |
| explicit BookmarkExtensionBackground(BrowserView* browser_view, |
| DetachableToolbarView* host_view, |
| Browser* browser); |
| |
| // View methods overridden from views:Background. |
| virtual void Paint(gfx::Canvas* canvas, views::View* view) const; |
| |
| private: |
| BrowserView* browser_view_; |
| |
| // The view hosting this background. |
| DetachableToolbarView* host_view_; |
| |
| Browser* browser_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground); |
| }; |
| |
| BookmarkExtensionBackground::BookmarkExtensionBackground( |
| BrowserView* browser_view, |
| DetachableToolbarView* host_view, |
| Browser* browser) |
| : browser_view_(browser_view), |
| host_view_(host_view), |
| browser_(browser) { |
| } |
| |
| void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas, |
| views::View* view) const { |
| ui::ThemeProvider* tp = host_view_->GetThemeProvider(); |
| int toolbar_overlap = host_view_->GetToolbarOverlap(); |
| // The client edge is drawn below the toolbar bounds. |
| if (toolbar_overlap) |
| toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness; |
| if (host_view_->IsDetached()) { |
| // Draw the background to match the new tab page. |
| int height = 0; |
| TabContents* contents = browser_->GetSelectedTabContents(); |
| if (contents && contents->view()) |
| height = contents->view()->GetContainerSize().height(); |
| NtpBackgroundUtil::PaintBackgroundDetachedMode( |
| host_view_->GetThemeProvider(), canvas, |
| gfx::Rect(0, toolbar_overlap, host_view_->width(), |
| host_view_->height() - toolbar_overlap), height); |
| |
| // As 'hidden' according to the animation is the full in-tab state, |
| // we invert the value - when current_state is at '0', we expect the |
| // bar to be docked. |
| double current_state = 1 - host_view_->GetAnimationValue(); |
| double h_padding = |
| static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) * |
| current_state; |
| double v_padding = |
| static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) * |
| current_state; |
| |
| SkRect rect; |
| double roundness = 0; |
| DetachableToolbarView::CalculateContentArea(current_state, h_padding, |
| v_padding, &rect, &roundness, host_view_); |
| DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect, |
| roundness); |
| DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness); |
| if (!toolbar_overlap) |
| DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_); |
| } else { |
| DetachableToolbarView::PaintBackgroundAttachedMode(canvas, host_view_, |
| browser_view_->OffsetPointForToolbarBackgroundImage( |
| gfx::Point(host_view_->GetMirroredX(), host_view_->y()))); |
| if (host_view_->height() >= toolbar_overlap) |
| DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // ResizeCorner, private: |
| |
| class ResizeCorner : public views::View { |
| public: |
| ResizeCorner() { |
| EnableCanvasFlippingForRTLUI(true); |
| } |
| |
| virtual void OnPaint(gfx::Canvas* canvas) { |
| views::Window* window = GetWindow(); |
| if (!window || (window->IsMaximized() || window->IsFullscreen())) |
| return; |
| |
| SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| IDR_TEXTAREA_RESIZER); |
| bitmap->buildMipMap(false); |
| canvas->DrawBitmapInt(*bitmap, width() - bitmap->width(), |
| height() - bitmap->height()); |
| } |
| |
| static gfx::Size GetSize() { |
| // This is disabled until we find what makes us slower when we let |
| // WebKit know that we have a resizer rect... |
| // int scrollbar_thickness = gfx::scrollbar_size(); |
| // return gfx::Size(scrollbar_thickness, scrollbar_thickness); |
| return gfx::Size(); |
| } |
| |
| virtual gfx::Size GetPreferredSize() { |
| views::Window* window = GetWindow(); |
| return (!window || window->IsMaximized() || window->IsFullscreen()) ? |
| gfx::Size() : GetSize(); |
| } |
| |
| virtual void Layout() { |
| if (parent()) { |
| gfx::Size ps = GetPreferredSize(); |
| // No need to handle Right to left text direction here, |
| // our parent must take care of it for us... |
| // TODO(alekseys): fix it. |
| SetBounds(parent()->width() - ps.width(), |
| parent()->height() - ps.height(), ps.width(), ps.height()); |
| } |
| } |
| |
| private: |
| // Returns the WindowWin we're displayed in. Returns NULL if we're not |
| // currently in a window. |
| views::Window* GetWindow() { |
| views::Widget* widget = GetWidget(); |
| return widget ? widget->GetWindow() : NULL; |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(ResizeCorner); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, public: |
| |
| BrowserView::BrowserView(Browser* browser) |
| : views::ClientView(NULL, NULL), |
| last_focused_view_storage_id_( |
| views::ViewStorage::GetInstance()->CreateStorageID()), |
| frame_(NULL), |
| browser_(browser), |
| active_bookmark_bar_(NULL), |
| tabstrip_(NULL), |
| toolbar_(NULL), |
| infobar_container_(NULL), |
| sidebar_container_(NULL), |
| sidebar_split_(NULL), |
| contents_container_(NULL), |
| devtools_container_(NULL), |
| preview_container_(NULL), |
| contents_(NULL), |
| contents_split_(NULL), |
| initialized_(false), |
| ignore_layout_(true) |
| #if defined(OS_WIN) |
| , hung_window_detector_(&hung_plugin_action_), |
| ticker_(0) |
| #endif |
| { |
| browser_->tabstrip_model()->AddObserver(this); |
| |
| registrar_.Add(this, |
| NotificationType::SIDEBAR_CHANGED, |
| Source<SidebarManager>(SidebarManager::GetInstance())); |
| } |
| |
| BrowserView::~BrowserView() { |
| browser_->tabstrip_model()->RemoveObserver(this); |
| |
| #if defined(OS_WIN) |
| // Remove this observer. |
| if (aeropeek_manager_.get()) |
| browser_->tabstrip_model()->RemoveObserver(aeropeek_manager_.get()); |
| |
| // Stop hung plugin monitoring. |
| ticker_.Stop(); |
| ticker_.UnregisterTickHandler(&hung_window_detector_); |
| #endif |
| |
| // We destroy the download shelf before |browser_| to remove its child |
| // download views from the set of download observers (since the observed |
| // downloads can be destroyed along with |browser_| and the observer |
| // notifications will call back into deleted objects). |
| download_shelf_.reset(); |
| |
| // The TabStrip attaches a listener to the model. Make sure we shut down the |
| // TabStrip first so that it can cleanly remove the listener. |
| if (tabstrip_) { |
| tabstrip_->parent()->RemoveChildView(tabstrip_); |
| delete tabstrip_; |
| tabstrip_ = NULL; |
| } |
| // Child views maintain PrefMember attributes that point to |
| // OffTheRecordProfile's PrefService which gets deleted by ~Browser. |
| RemoveAllChildViews(true); |
| // Explicitly set browser_ to NULL. |
| browser_.reset(); |
| } |
| |
| // static |
| BrowserView* BrowserView::GetBrowserViewForNativeWindow( |
| gfx::NativeWindow window) { |
| #if defined(OS_WIN) |
| if (IsWindow(window)) { |
| return reinterpret_cast<BrowserView*>( |
| ui::ViewProp::GetValue(window, kBrowserViewKey)); |
| } |
| #else |
| if (window) { |
| return static_cast<BrowserView*>( |
| g_object_get_data(G_OBJECT(window), kBrowserViewKey)); |
| } |
| #endif |
| return NULL; |
| } |
| |
| gfx::Rect BrowserView::GetToolbarBounds() const { |
| gfx::Rect toolbar_bounds(toolbar_->bounds()); |
| if (toolbar_bounds.IsEmpty()) |
| return toolbar_bounds; |
| // When using vertical tabs, the toolbar appears to extend behind the tab |
| // column. |
| if (UseVerticalTabs()) |
| toolbar_bounds.Inset(tabstrip_->x() - toolbar_bounds.x(), 0, 0, 0); |
| // The apparent toolbar edges are outside the "real" toolbar edges. |
| toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0); |
| return toolbar_bounds; |
| } |
| |
| gfx::Rect BrowserView::GetClientAreaBounds() const { |
| gfx::Rect container_bounds = contents_->bounds(); |
| gfx::Point container_origin = container_bounds.origin(); |
| ConvertPointToView(this, parent(), &container_origin); |
| container_bounds.set_origin(container_origin); |
| return container_bounds; |
| } |
| |
| gfx::Rect BrowserView::GetFindBarBoundingBox() const { |
| return GetBrowserViewLayout()->GetFindBarBoundingBox(); |
| } |
| |
| int BrowserView::GetTabStripHeight() const { |
| // We want to return tabstrip_->height(), but we might be called in the midst |
| // of layout, when that hasn't yet been updated to reflect the current state. |
| // So return what the tabstrip height _ought_ to be right now. |
| return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0; |
| } |
| |
| gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage( |
| const gfx::Point& point) const { |
| // The background image starts tiling horizontally at the window left edge and |
| // vertically at the top edge of the horizontal tab strip (or where it would |
| // be). We expect our parent's origin to be the window origin. |
| gfx::Point window_point(point.Add(GetMirroredPosition())); |
| window_point.Offset(0, -frame_->GetHorizontalTabStripVerticalOffset(false)); |
| return window_point; |
| } |
| |
| int BrowserView::GetSidebarWidth() const { |
| if (!sidebar_container_ || !sidebar_container_->IsVisible()) |
| return 0; |
| return sidebar_split_->divider_offset(); |
| } |
| |
| bool BrowserView::IsTabStripVisible() const { |
| return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); |
| } |
| |
| bool BrowserView::UseVerticalTabs() const { |
| return browser_->tabstrip_model()->delegate()->UseVerticalTabs(); |
| } |
| |
| bool BrowserView::IsOffTheRecord() const { |
| return browser_->profile()->IsOffTheRecord(); |
| } |
| |
| bool BrowserView::ShouldShowOffTheRecordAvatar() const { |
| return IsOffTheRecord() && IsBrowserTypeNormal(); |
| } |
| |
| bool BrowserView::AcceleratorPressed(const views::Accelerator& accelerator) { |
| #if defined(OS_CHROMEOS) |
| // If accessibility is enabled, stop speech and return false so that key |
| // combinations involving Search can be used for extra accessibility |
| // functionality. |
| if (accelerator.GetKeyCode() == ui::VKEY_LWIN && |
| g_browser_process->local_state()->GetBoolean( |
| prefs::kAccessibilityEnabled)) { |
| ExtensionTtsController::GetInstance()->Stop(); |
| return false; |
| } |
| #endif |
| |
| std::map<views::Accelerator, int>::const_iterator iter = |
| accelerator_table_.find(accelerator); |
| DCHECK(iter != accelerator_table_.end()); |
| int command_id = iter->second; |
| |
| if (!browser_->block_command_execution()) |
| UpdateAcceleratorMetrics(accelerator, command_id); |
| return browser_->ExecuteCommandIfEnabled(command_id); |
| } |
| |
| bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { |
| // The standard Ctrl-X, Ctrl-V and Ctrl-C are not defined as accelerators |
| // anywhere so we need to check for them explicitly here. |
| switch (cmd_id) { |
| case IDC_CUT: |
| *accelerator = views::Accelerator(ui::VKEY_X, false, true, false); |
| return true; |
| case IDC_COPY: |
| *accelerator = views::Accelerator(ui::VKEY_C, false, true, false); |
| return true; |
| case IDC_PASTE: |
| *accelerator = views::Accelerator(ui::VKEY_V, false, true, false); |
| return true; |
| } |
| // Else, we retrieve the accelerator information from the accelerator table. |
| std::map<views::Accelerator, int>::iterator it = |
| accelerator_table_.begin(); |
| for (; it != accelerator_table_.end(); ++it) { |
| if (it->second == cmd_id) { |
| *accelerator = it->first; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool BrowserView::ActivateAppModalDialog() const { |
| // If another browser is app modal, flash and activate the modal browser. |
| if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) { |
| Browser* active_browser = BrowserList::GetLastActive(); |
| if (active_browser && (browser_ != active_browser)) { |
| active_browser->window()->FlashFrame(); |
| active_browser->window()->Activate(); |
| } |
| AppModalDialogQueue::GetInstance()->ActivateModalDialog(); |
| return true; |
| } |
| return false; |
| } |
| |
| TabContents* BrowserView::GetSelectedTabContents() const { |
| return browser_->GetSelectedTabContents(); |
| } |
| |
| TabContentsWrapper* BrowserView::GetSelectedTabContentsWrapper() const { |
| return browser_->GetSelectedTabContentsWrapper(); |
| } |
| |
| SkBitmap BrowserView::GetOTRAvatarIcon() { |
| static SkBitmap* otr_avatar_ = new SkBitmap(); |
| |
| if (otr_avatar_->isNull()) { |
| ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| *otr_avatar_ = *rb.GetBitmapNamed(IDR_OTR_ICON); |
| } |
| return *otr_avatar_; |
| } |
| |
| #if defined(OS_WIN) |
| void BrowserView::PrepareToRunSystemMenu(HMENU menu) { |
| system_menu_->UpdateStates(); |
| } |
| #endif |
| |
| // static |
| void BrowserView::RegisterBrowserViewPrefs(PrefService* prefs) { |
| prefs->RegisterIntegerPref(prefs::kPluginMessageResponseTimeout, |
| kDefaultPluginMessageResponseTimeout); |
| prefs->RegisterIntegerPref(prefs::kHungPluginDetectFrequency, |
| kDefaultHungPluginDetectFrequency); |
| } |
| |
| bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) { |
| return GetBrowserViewLayout()->IsPositionInWindowCaption(point); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, BrowserWindow implementation: |
| |
| void BrowserView::Show() { |
| // If the window is already visible, just activate it. |
| if (frame_->GetWindow()->IsVisible()) { |
| frame_->GetWindow()->Activate(); |
| return; |
| } |
| |
| // Setting the focus doesn't work when the window is invisible, so any focus |
| // initialization that happened before this will be lost. |
| // |
| // We really "should" restore the focus whenever the window becomes unhidden, |
| // but I think initializing is the only time where this can happen where |
| // there is some focus change we need to pick up, and this is easier than |
| // plumbing through an un-hide message all the way from the frame. |
| // |
| // If we do find there are cases where we need to restore the focus on show, |
| // that should be added and this should be removed. |
| RestoreFocus(); |
| |
| frame_->GetWindow()->Show(); |
| } |
| |
| void BrowserView::ShowInactive() { |
| views::Window* window = frame_->GetWindow(); |
| if (!window->IsVisible()) |
| window->ShowInactive(); |
| } |
| |
| void BrowserView::SetBounds(const gfx::Rect& bounds) { |
| SetFullscreen(false); |
| GetWidget()->SetBounds(bounds); |
| } |
| |
| void BrowserView::Close() { |
| BrowserBubbleHost::Close(); |
| |
| frame_->GetWindow()->CloseWindow(); |
| } |
| |
| void BrowserView::Activate() { |
| frame_->GetWindow()->Activate(); |
| } |
| |
| void BrowserView::Deactivate() { |
| frame_->GetWindow()->Deactivate(); |
| } |
| |
| bool BrowserView::IsActive() const { |
| return frame_->GetWindow()->IsActive(); |
| } |
| |
| void BrowserView::FlashFrame() { |
| #if defined(OS_WIN) |
| FLASHWINFO fwi; |
| fwi.cbSize = sizeof(fwi); |
| fwi.hwnd = frame_->GetWindow()->GetNativeWindow(); |
| fwi.dwFlags = FLASHW_ALL; |
| fwi.uCount = 4; |
| fwi.dwTimeout = 0; |
| FlashWindowEx(&fwi); |
| #else |
| // Doesn't matter for chrome os. |
| #endif |
| } |
| |
| gfx::NativeWindow BrowserView::GetNativeHandle() { |
| return GetWidget()->GetWindow()->GetNativeWindow(); |
| } |
| |
| BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() { |
| return this; |
| } |
| |
| StatusBubble* BrowserView::GetStatusBubble() { |
| return status_bubble_.get(); |
| } |
| |
| namespace { |
| // Only used by ToolbarSizeChanged() below, but placed here because template |
| // arguments (to AutoReset<>) must have external linkage. |
| enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE }; |
| } |
| |
| void BrowserView::ToolbarSizeChanged(bool is_animating) { |
| // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in |
| // reentrancy; |call_state| tracks whether we're reentrant. We can't just |
| // early-return in this case because we need to layout again so the infobar |
| // container's bounds are set correctly. |
| static CallState call_state = NORMAL; |
| |
| // A reentrant call can (and should) use the fast resize path unless both it |
| // and the normal call are both non-animating. |
| bool use_fast_resize = |
| is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE); |
| if (use_fast_resize) |
| contents_container_->SetFastResize(true); |
| UpdateUIForContents(browser_->GetSelectedTabContentsWrapper()); |
| if (use_fast_resize) |
| contents_container_->SetFastResize(false); |
| |
| // Inform the InfoBarContainer that the distance to the location icon may have |
| // changed. We have to do this after the block above so that the toolbars are |
| // laid out correctly for calculating the maximum arrow height below. |
| { |
| const LocationIconView* location_icon_view = |
| toolbar_->location_bar()->location_icon_view(); |
| // The +1 in the next line creates a 1-px gap between icon and arrow tip. |
| gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() - |
| LocationBarView::kIconInternalPadding + 1); |
| ConvertPointToView(location_icon_view, this, &icon_bottom); |
| gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL)); |
| ConvertPointToView(infobar_container_, this, &infobar_top); |
| |
| AutoReset<CallState> resetter(&call_state, |
| is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT); |
| infobar_container_->SetMaxTopArrowHeight(infobar_top.y() - icon_bottom.y()); |
| } |
| |
| // When transitioning from animating to not animating we need to make sure the |
| // contents_container_ gets layed out. If we don't do this and the bounds |
| // haven't changed contents_container_ won't get a Layout out and we'll end up |
| // with a gray rect because the clip wasn't updated. Note that a reentrant |
| // call never needs to do this, because after it returns, the normal call |
| // wrapping it will do it. |
| if ((call_state == NORMAL) && !is_animating) { |
| contents_container_->InvalidateLayout(); |
| contents_split_->Layout(); |
| } |
| } |
| |
| void BrowserView::UpdateTitleBar() { |
| frame_->GetWindow()->UpdateWindowTitle(); |
| if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning()) |
| frame_->GetWindow()->UpdateWindowIcon(); |
| } |
| |
| void BrowserView::ShelfVisibilityChanged() { |
| Layout(); |
| } |
| |
| void BrowserView::UpdateDevTools() { |
| UpdateDevToolsForContents(GetSelectedTabContentsWrapper()); |
| Layout(); |
| } |
| |
| void BrowserView::UpdateLoadingAnimations(bool should_animate) { |
| if (should_animate) { |
| if (!loading_animation_timer_.IsRunning()) { |
| // Loads are happening, and the timer isn't running, so start it. |
| last_animation_time_ = base::TimeTicks::Now(); |
| loading_animation_timer_.Start( |
| TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this, |
| &BrowserView::LoadingAnimationCallback); |
| } |
| } else { |
| if (loading_animation_timer_.IsRunning()) { |
| last_animation_time_ = base::TimeTicks(); |
| loading_animation_timer_.Stop(); |
| // Loads are now complete, update the state if a task was scheduled. |
| LoadingAnimationCallback(); |
| } |
| } |
| } |
| |
| void BrowserView::SetStarredState(bool is_starred) { |
| toolbar_->location_bar()->SetStarToggled(is_starred); |
| } |
| |
| gfx::Rect BrowserView::GetRestoredBounds() const { |
| return frame_->GetWindow()->GetNormalBounds(); |
| } |
| |
| gfx::Rect BrowserView::GetBounds() const { |
| return frame_->GetWindow()->GetBounds(); |
| } |
| |
| bool BrowserView::IsMaximized() const { |
| return frame_->GetWindow()->IsMaximized(); |
| } |
| |
| void BrowserView::SetFullscreen(bool fullscreen) { |
| if (IsFullscreen() == fullscreen) |
| return; // Nothing to do. |
| |
| #if defined(OS_WIN) |
| ProcessFullscreen(fullscreen); |
| #else |
| // On Linux changing fullscreen is async. Ask the window to change it's |
| // fullscreen state, and when done invoke ProcessFullscreen. |
| frame_->GetWindow()->SetFullscreen(fullscreen); |
| #endif |
| } |
| |
| bool BrowserView::IsFullscreen() const { |
| return frame_->GetWindow()->IsFullscreen(); |
| } |
| |
| bool BrowserView::IsFullscreenBubbleVisible() const { |
| return fullscreen_bubble_.get() ? true : false; |
| } |
| |
| void BrowserView::FullScreenStateChanged() { |
| ProcessFullscreen(IsFullscreen()); |
| } |
| |
| void BrowserView::RestoreFocus() { |
| TabContents* selected_tab_contents = GetSelectedTabContents(); |
| if (selected_tab_contents) |
| selected_tab_contents->view()->RestoreFocus(); |
| } |
| |
| LocationBar* BrowserView::GetLocationBar() const { |
| return toolbar_->location_bar(); |
| } |
| |
| void BrowserView::SetFocusToLocationBar(bool select_all) { |
| LocationBarView* location_bar = toolbar_->location_bar(); |
| if (location_bar->IsFocusableInRootView()) { |
| // Location bar got focus. |
| location_bar->FocusLocation(select_all); |
| } else { |
| // If none of location bar/compact navigation bar got focus, |
| // then clear focus. |
| views::FocusManager* focus_manager = GetFocusManager(); |
| DCHECK(focus_manager); |
| focus_manager->ClearFocus(); |
| } |
| } |
| |
| void BrowserView::UpdateReloadStopState(bool is_loading, bool force) { |
| toolbar_->reload_button()->ChangeMode( |
| is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force); |
| } |
| |
| void BrowserView::UpdateToolbar(TabContentsWrapper* contents, |
| bool should_restore_state) { |
| toolbar_->Update(contents->tab_contents(), should_restore_state); |
| } |
| |
| void BrowserView::FocusToolbar() { |
| // Start the traversal within the main toolbar, passing it the storage id |
| // of the view where focus should be returned if the user exits the toolbar. |
| SaveFocusedView(); |
| toolbar_->SetPaneFocus(last_focused_view_storage_id_, NULL); |
| } |
| |
| void BrowserView::FocusBookmarksToolbar() { |
| if (active_bookmark_bar_ && bookmark_bar_view_->IsVisible()) { |
| SaveFocusedView(); |
| bookmark_bar_view_->SetPaneFocus(last_focused_view_storage_id_, NULL); |
| } |
| } |
| |
| void BrowserView::FocusAppMenu() { |
| // Chrome doesn't have a traditional menu bar, but it has a menu button in the |
| // main toolbar that plays the same role. If the user presses a key that |
| // would typically focus the menu bar, tell the toolbar to focus the menu |
| // button. If the user presses the key again, return focus to the previous |
| // location. |
| // |
| // Not used on the Mac, which has a normal menu bar. |
| if (toolbar_->IsAppMenuFocused()) { |
| RestoreFocus(); |
| } else { |
| SaveFocusedView(); |
| toolbar_->SetPaneFocusAndFocusAppMenu(last_focused_view_storage_id_); |
| } |
| } |
| |
| void BrowserView::RotatePaneFocus(bool forwards) { |
| // This gets called when the user presses F6 (forwards) or Shift+F6 |
| // (backwards) to rotate to the next pane. Here, our "panes" are the |
| // tab contents and each of our accessible toolbars, infobars, downloads |
| // shelf, etc. When a pane has focus, all of its controls are accessible |
| // in the tab traversal, and the tab traversal is "trapped" within that pane. |
| // |
| // Get a vector of all panes in the order we want them to be focused, |
| // with NULL to represent the tab contents getting focus. If one of these |
| // is currently invisible or has no focusable children it will be |
| // automatically skipped. |
| std::vector<AccessiblePaneView*> accessible_panes; |
| GetAccessiblePanes(&accessible_panes); |
| int pane_count = static_cast<int>(accessible_panes.size()); |
| |
| std::vector<views::View*> accessible_views( |
| accessible_panes.begin(), accessible_panes.end()); |
| accessible_views.push_back(GetTabContentsContainerView()); |
| if (sidebar_container_ && sidebar_container_->IsVisible()) |
| accessible_views.push_back(GetSidebarContainerView()); |
| if (devtools_container_->IsVisible()) |
| accessible_views.push_back(devtools_container_->GetFocusView()); |
| int count = static_cast<int>(accessible_views.size()); |
| |
| // Figure out which view (if any) currently has the focus. |
| views::View* focused_view = GetFocusManager()->GetFocusedView(); |
| int index = -1; |
| if (focused_view) { |
| for (int i = 0; i < count; ++i) { |
| if (accessible_views[i] == focused_view || |
| accessible_views[i]->Contains(focused_view)) { |
| index = i; |
| break; |
| } |
| } |
| } |
| |
| // If the focus isn't currently in a pane, save the focus so we |
| // can restore it if the user presses Escape. |
| if (focused_view && index >= pane_count) |
| SaveFocusedView(); |
| |
| // Try to focus the next pane; if SetPaneFocusAndFocusDefault returns |
| // false it means the pane didn't have any focusable controls, so skip |
| // it and try the next one. |
| for (;;) { |
| if (forwards) |
| index = (index + 1) % count; |
| else |
| index = ((index - 1) + count) % count; |
| |
| if (index < pane_count) { |
| if (accessible_panes[index]->SetPaneFocusAndFocusDefault( |
| last_focused_view_storage_id_)) { |
| break; |
| } |
| } else { |
| accessible_views[index]->RequestFocus(); |
| break; |
| } |
| } |
| } |
| |
| void BrowserView::SaveFocusedView() { |
| views::ViewStorage* view_storage = views::ViewStorage::GetInstance(); |
| if (view_storage->RetrieveView(last_focused_view_storage_id_)) |
| view_storage->RemoveView(last_focused_view_storage_id_); |
| views::View* focused_view = GetFocusManager()->GetFocusedView(); |
| if (focused_view) |
| view_storage->StoreView(last_focused_view_storage_id_, focused_view); |
| } |
| |
| void BrowserView::DestroyBrowser() { |
| // Explicitly delete the BookmarkBarView now. That way we don't have to |
| // worry about the BookmarkBarView potentially outliving the Browser & |
| // Profile. |
| bookmark_bar_view_.reset(); |
| browser_.reset(); |
| } |
| |
| bool BrowserView::IsBookmarkBarVisible() const { |
| return browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) && |
| active_bookmark_bar_ && |
| (active_bookmark_bar_->GetPreferredSize().height() != 0); |
| } |
| |
| bool BrowserView::IsBookmarkBarAnimating() const { |
| return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating(); |
| } |
| |
| bool BrowserView::IsTabStripEditable() const { |
| return tabstrip_->IsTabStripEditable(); |
| } |
| |
| bool BrowserView::IsToolbarVisible() const { |
| return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) || |
| browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); |
| } |
| |
| void BrowserView::DisableInactiveFrame() { |
| #if defined(OS_WIN) |
| frame_->GetWindow()->DisableInactiveRendering(); |
| #endif // No tricks are needed to get the right behavior on Linux. |
| } |
| |
| void BrowserView::ConfirmSetDefaultSearchProvider( |
| TabContents* tab_contents, |
| TemplateURL* template_url, |
| TemplateURLModel* template_url_model) { |
| #if defined(OS_WIN) |
| DefaultSearchView::Show(tab_contents, template_url, template_url_model); |
| #else |
| // TODO(levin): Implement for other platforms. Right now this is behind |
| // a command line flag which is off. http://crbug.com/38475 |
| #endif |
| } |
| |
| void BrowserView::ConfirmAddSearchProvider(const TemplateURL* template_url, |
| Profile* profile) { |
| browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url, NULL, |
| profile); |
| } |
| |
| void BrowserView::ToggleBookmarkBar() { |
| bookmark_utils::ToggleWhenVisible(browser_->profile()); |
| } |
| |
| void BrowserView::ShowAboutChromeDialog() { |
| DoShowAboutChromeDialog(); |
| } |
| |
| views::Window* BrowserView::DoShowAboutChromeDialog() { |
| return browser::ShowAboutChromeView(GetWindow()->GetNativeWindow(), |
| browser_->profile()); |
| } |
| |
| void BrowserView::ShowUpdateChromeDialog() { |
| UpdateRecommendedMessageBox::ShowMessageBox(GetWindow()->GetNativeWindow()); |
| } |
| |
| void BrowserView::ShowTaskManager() { |
| browser::ShowTaskManager(); |
| } |
| |
| void BrowserView::ShowBackgroundPages() { |
| browser::ShowBackgroundPages(); |
| } |
| |
| void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { |
| toolbar_->location_bar()->ShowStarBubble(url, !already_bookmarked); |
| } |
| |
| void BrowserView::SetDownloadShelfVisible(bool visible) { |
| // This can be called from the superclass destructor, when it destroys our |
| // child views. At that point, browser_ is already gone. |
| if (browser_ == NULL) |
| return; |
| |
| if (visible && IsDownloadShelfVisible() != visible) { |
| // Invoke GetDownloadShelf to force the shelf to be created. |
| GetDownloadShelf(); |
| } |
| |
| if (browser_ != NULL) |
| browser_->UpdateDownloadShelfVisibility(visible); |
| |
| // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out |
| // everything correctly, as if the animation had finished. This doesn't |
| // matter for showing the shelf, as the show animation will do it. |
| ToolbarSizeChanged(false); |
| } |
| |
| bool BrowserView::IsDownloadShelfVisible() const { |
| return download_shelf_.get() && download_shelf_->IsShowing(); |
| } |
| |
| DownloadShelf* BrowserView::GetDownloadShelf() { |
| if (!download_shelf_.get()) { |
| download_shelf_.reset(new DownloadShelfView(browser_.get(), this)); |
| download_shelf_->set_parent_owned(false); |
| } |
| return download_shelf_.get(); |
| } |
| |
| void BrowserView::ShowRepostFormWarningDialog(TabContents* tab_contents) { |
| browser::ShowRepostFormWarningDialog(GetNativeHandle(), tab_contents); |
| } |
| |
| void BrowserView::ShowCollectedCookiesDialog(TabContents* tab_contents) { |
| browser::ShowCollectedCookiesDialog(GetNativeHandle(), tab_contents); |
| } |
| |
| void BrowserView::ShowThemeInstallBubble() { |
| TabContents* tab_contents = browser_->GetSelectedTabContents(); |
| if (!tab_contents) |
| return; |
| ThemeInstallBubbleView::Show(tab_contents); |
| } |
| |
| void BrowserView::ConfirmBrowserCloseWithPendingDownloads() { |
| DownloadInProgressDialogView* view = |
| new DownloadInProgressDialogView(browser_.get()); |
| browser::CreateViewsWindow(GetNativeHandle(), gfx::Rect(), view)->Show(); |
| } |
| |
| void BrowserView::ShowHTMLDialog(HtmlDialogUIDelegate* delegate, |
| gfx::NativeWindow parent_window) { |
| // Default to using our window as the parent if the argument is not specified. |
| gfx::NativeWindow parent = parent_window ? parent_window |
| : GetNativeHandle(); |
| #if defined(OS_CHROMEOS) |
| parent = GetNormalBrowserWindowForBrowser(browser(), NULL); |
| #endif // defined(OS_CHROMEOS) |
| |
| browser::ShowHtmlDialog(parent, browser_.get()->profile(), delegate); |
| } |
| |
| void BrowserView::ShowCreateWebAppShortcutsDialog( |
| TabContentsWrapper* tab_contents) { |
| browser::ShowCreateWebAppShortcutsDialog(GetNativeHandle(), tab_contents); |
| } |
| |
| void BrowserView::ShowCreateChromeAppShortcutsDialog(Profile* profile, |
| const Extension* app) { |
| browser::ShowCreateChromeAppShortcutsDialog(GetNativeHandle(), profile, app); |
| } |
| |
| void BrowserView::UserChangedTheme() { |
| frame_->GetWindow()->FrameTypeChanged(); |
| } |
| |
| int BrowserView::GetExtraRenderViewHeight() const { |
| // Currently this is only used on linux. |
| return 0; |
| } |
| |
| void BrowserView::TabContentsFocused(TabContents* tab_contents) { |
| contents_container_->TabContentsFocused(tab_contents); |
| } |
| |
| void BrowserView::ShowPageInfo(Profile* profile, |
| const GURL& url, |
| const NavigationEntry::SSLStatus& ssl, |
| bool show_history) { |
| gfx::NativeWindow parent = GetWindow()->GetNativeWindow(); |
| |
| browser::ShowPageInfoBubble(parent, profile, url, ssl, show_history); |
| } |
| |
| void BrowserView::ShowAppMenu() { |
| toolbar_->app_menu()->Activate(); |
| } |
| |
| bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, |
| bool* is_keyboard_shortcut) { |
| if (event.type != WebKit::WebInputEvent::RawKeyDown) |
| return false; |
| |
| #if defined(OS_WIN) |
| // As Alt+F4 is the close-app keyboard shortcut, it needs processing |
| // immediately. |
| if (event.windowsKeyCode == ui::VKEY_F4 && |
| event.modifiers == NativeWebKeyboardEvent::AltKey) { |
| DefWindowProc(event.os_event.hwnd, event.os_event.message, |
| event.os_event.wParam, event.os_event.lParam); |
| return true; |
| } |
| #endif |
| |
| views::FocusManager* focus_manager = GetFocusManager(); |
| DCHECK(focus_manager); |
| |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) |
| // Views and WebKit use different tables for GdkEventKey -> views::KeyEvent |
| // conversion. We need to use View's conversion table here to keep consistent |
| // behavior with views::FocusManager::OnKeyEvent() method. |
| // TODO(suzhe): We need to check if Windows code also has this issue, and |
| // it'll be best if we can unify these conversion tables. |
| // See http://crbug.com/54315 |
| views::KeyEvent views_event(reinterpret_cast<GdkEvent*>(event.os_event)); |
| views::Accelerator accelerator(views_event.key_code(), |
| views_event.IsShiftDown(), |
| views_event.IsControlDown(), |
| views_event.IsAltDown()); |
| #else |
| views::Accelerator accelerator( |
| static_cast<ui::KeyboardCode>(event.windowsKeyCode), |
| (event.modifiers & NativeWebKeyboardEvent::ShiftKey) == |
| NativeWebKeyboardEvent::ShiftKey, |
| (event.modifiers & NativeWebKeyboardEvent::ControlKey) == |
| NativeWebKeyboardEvent::ControlKey, |
| (event.modifiers & NativeWebKeyboardEvent::AltKey) == |
| NativeWebKeyboardEvent::AltKey); |
| #endif |
| |
| // We first find out the browser command associated to the |event|. |
| // Then if the command is a reserved one, and should be processed |
| // immediately according to the |event|, the command will be executed |
| // immediately. Otherwise we just set |*is_keyboard_shortcut| properly and |
| // return false. |
| |
| // This piece of code is based on the fact that accelerators registered |
| // into the |focus_manager| may only trigger a browser command execution. |
| // |
| // Here we need to retrieve the command id (if any) associated to the |
| // keyboard event. Instead of looking up the command id in the |
| // |accelerator_table_| by ourselves, we block the command execution of |
| // the |browser_| object then send the keyboard event to the |
| // |focus_manager| as if we are activating an accelerator key. |
| // Then we can retrieve the command id from the |browser_| object. |
| browser_->SetBlockCommandExecution(true); |
| focus_manager->ProcessAccelerator(accelerator); |
| int id = browser_->GetLastBlockedCommand(NULL); |
| browser_->SetBlockCommandExecution(false); |
| |
| if (id == -1) |
| return false; |
| |
| // Executing the command may cause |this| object to be destroyed. |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) |
| if (browser_->IsReservedCommandOrKey(id, event) && |
| !event.match_edit_command) { |
| #else |
| if (browser_->IsReservedCommandOrKey(id, event)) { |
| #endif |
| UpdateAcceleratorMetrics(accelerator, id); |
| return browser_->ExecuteCommandIfEnabled(id); |
| } |
| |
| DCHECK(is_keyboard_shortcut != NULL); |
| *is_keyboard_shortcut = true; |
| |
| return false; |
| } |
| |
| void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { |
| #if defined(OS_LINUX) && !defined(TOUCH_UI) |
| views::Window* window = GetWidget()->GetWindow(); |
| if (window && event.os_event && !event.skip_in_browser) { |
| views::KeyEvent views_event(reinterpret_cast<GdkEvent*>(event.os_event)); |
| static_cast<views::WindowGtk*>(window)->HandleKeyboardEvent(views_event); |
| } |
| #else |
| unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, |
| GetFocusManager()); |
| #endif |
| } |
| |
| // TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always |
| // enabled in the page menu regardless of whether the command will do |
| // anything. When someone selects the menu item, we just act as if they hit |
| // the keyboard shortcut for the command by sending the associated key press |
| // to windows. The real fix to this bug is to disable the commands when they |
| // won't do anything. We'll need something like an overall clipboard command |
| // manager to do that. |
| void BrowserView::Cut() { |
| ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_X, |
| true, false, false, false); |
| } |
| |
| void BrowserView::Copy() { |
| ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_C, |
| true, false, false, false); |
| } |
| |
| void BrowserView::Paste() { |
| ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_V, |
| true, false, false, false); |
| } |
| |
| void BrowserView::ToggleTabStripMode() { |
| InitTabStrip(browser_->tabstrip_model()); |
| frame_->TabStripDisplayModeChanged(); |
| } |
| |
| void BrowserView::PrepareForInstant() { |
| contents_->FadeActiveContents(); |
| } |
| |
| void BrowserView::ShowInstant(TabContentsWrapper* preview) { |
| if (!preview_container_) |
| preview_container_ = new TabContentsContainer(); |
| contents_->SetPreview(preview_container_, preview->tab_contents()); |
| preview_container_->ChangeTabContents(preview->tab_contents()); |
| |
| #if defined(OS_WIN) |
| // Removing the fade is instant (on windows). We need to force the preview to |
| // draw, otherwise the current page flickers before the new page appears. |
| RedrawWindow(preview->tab_contents()->view()->GetContentNativeView(), NULL, |
| NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); |
| #endif |
| |
| contents_->RemoveFade(); |
| } |
| |
| void BrowserView::HideInstant(bool instant_is_active) { |
| if (instant_is_active) |
| contents_->ShowFade(); |
| else |
| contents_->RemoveFade(); |
| |
| if (!preview_container_) |
| return; |
| |
| // The contents must be changed before SetPreview is invoked. |
| preview_container_->ChangeTabContents(NULL); |
| contents_->SetPreview(NULL, NULL); |
| delete preview_container_; |
| preview_container_ = NULL; |
| } |
| |
| gfx::Rect BrowserView::GetInstantBounds() { |
| return contents_->GetPreviewBounds(); |
| } |
| |
| #if defined(OS_CHROMEOS) |
| void BrowserView::ShowKeyboardOverlay(gfx::NativeWindow owning_window) { |
| KeyboardOverlayDialogView::ShowDialog(owning_window, this); |
| } |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, BrowserWindowTesting implementation: |
| |
| BookmarkBarView* BrowserView::GetBookmarkBarView() const { |
| return bookmark_bar_view_.get(); |
| } |
| |
| LocationBarView* BrowserView::GetLocationBarView() const { |
| return toolbar_->location_bar(); |
| } |
| |
| views::View* BrowserView::GetTabContentsContainerView() const { |
| return contents_container_->GetFocusView(); |
| } |
| |
| views::View* BrowserView::GetSidebarContainerView() const { |
| if (!sidebar_container_) |
| return NULL; |
| return sidebar_container_->GetFocusView(); |
| } |
| |
| ToolbarView* BrowserView::GetToolbarView() const { |
| return toolbar_; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, NotificationObserver implementation: |
| |
| void BrowserView::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type.value) { |
| case NotificationType::PREF_CHANGED: |
| if (*Details<std::string>(details).ptr() == prefs::kShowBookmarkBar && |
| MaybeShowBookmarkBar(browser_->GetSelectedTabContentsWrapper())) { |
| Layout(); |
| } |
| break; |
| |
| case NotificationType::SIDEBAR_CHANGED: |
| if (Details<SidebarContainer>(details)->tab_contents() == |
| browser_->GetSelectedTabContents()) { |
| UpdateSidebar(); |
| } |
| break; |
| |
| default: |
| NOTREACHED() << "Got a notification we didn't register for!"; |
| break; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, TabStripModelObserver implementation: |
| |
| void BrowserView::TabDetachedAt(TabContentsWrapper* contents, int index) { |
| // We use index here rather than comparing |contents| because by this time |
| // the model has already removed |contents| from its list, so |
| // browser_->GetSelectedTabContents() will return NULL or something else. |
| if (index == browser_->tabstrip_model()->active_index()) { |
| // We need to reset the current tab contents to NULL before it gets |
| // freed. This is because the focus manager performs some operations |
| // on the selected TabContents when it is removed. |
| contents_container_->ChangeTabContents(NULL); |
| infobar_container_->ChangeTabContents(NULL); |
| UpdateSidebarForContents(NULL); |
| UpdateDevToolsForContents(NULL); |
| } |
| } |
| |
| void BrowserView::TabDeselected(TabContentsWrapper* contents) { |
| // We do not store the focus when closing the tab to work-around bug 4633. |
| // Some reports seem to show that the focus manager and/or focused view can |
| // be garbage at that point, it is not clear why. |
| if (!contents->tab_contents()->is_being_destroyed()) |
| contents->view()->StoreFocus(); |
| } |
| |
| void BrowserView::TabSelectedAt(TabContentsWrapper* old_contents, |
| TabContentsWrapper* new_contents, |
| int index, |
| bool user_gesture) { |
| if (old_contents == new_contents) |
| return; |
| |
| ProcessTabSelected(new_contents, true); |
| } |
| |
| void BrowserView::TabReplacedAt(TabStripModel* tab_strip_model, |
| TabContentsWrapper* old_contents, |
| TabContentsWrapper* new_contents, |
| int index) { |
| if (index != browser_->tabstrip_model()->active_index()) |
| return; |
| |
| // Swap the 'active' and 'preview' and delete what was the active. |
| contents_->MakePreviewContentsActiveContents(); |
| TabContentsContainer* old_container = contents_container_; |
| contents_container_ = preview_container_; |
| old_container->ChangeTabContents(NULL); |
| delete old_container; |
| preview_container_ = NULL; |
| |
| // Update the UI for what was the preview contents and is now active. Pass in |
| // false to ProcessTabSelected as new_contents is already parented correctly. |
| ProcessTabSelected(new_contents, false); |
| } |
| |
| void BrowserView::TabStripEmpty() { |
| // Make sure all optional UI is removed before we are destroyed, otherwise |
| // there will be consequences (since our view hierarchy will still have |
| // references to freed views). |
| UpdateUIForContents(NULL); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, ui::SimpleMenuModel::Delegate implementation: |
| |
| bool BrowserView::IsCommandIdChecked(int command_id) const { |
| // TODO(beng): encoding menu. |
| // No items in our system menu are check-able. |
| return false; |
| } |
| |
| bool BrowserView::IsCommandIdEnabled(int command_id) const { |
| return browser_->command_updater()->IsCommandEnabled(command_id); |
| } |
| |
| bool BrowserView::GetAcceleratorForCommandId(int command_id, |
| ui::Accelerator* accelerator) { |
| // Let's let the ToolbarView own the canonical implementation of this method. |
| return toolbar_->GetAcceleratorForCommandId(command_id, accelerator); |
| } |
| |
| bool BrowserView::IsItemForCommandIdDynamic(int command_id) const { |
| return command_id == IDC_RESTORE_TAB; |
| } |
| |
| string16 BrowserView::GetLabelForCommandId(int command_id) const { |
| DCHECK(command_id == IDC_RESTORE_TAB); |
| |
| int string_id = IDS_RESTORE_TAB; |
| if (IsCommandIdEnabled(command_id)) { |
| TabRestoreService* trs = browser_->profile()->GetTabRestoreService(); |
| if (trs && trs->entries().front()->type == TabRestoreService::WINDOW) |
| string_id = IDS_RESTORE_WINDOW; |
| } |
| return l10n_util::GetStringUTF16(string_id); |
| } |
| |
| void BrowserView::ExecuteCommand(int command_id) { |
| browser_->ExecuteCommandIfEnabled(command_id); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, views::WindowDelegate implementation: |
| |
| bool BrowserView::CanResize() const { |
| return true; |
| } |
| |
| bool BrowserView::CanMaximize() const { |
| return true; |
| } |
| |
| bool BrowserView::CanActivate() const { |
| return !ActivateAppModalDialog(); |
| } |
| |
| bool BrowserView::IsModal() const { |
| return false; |
| } |
| |
| std::wstring BrowserView::GetWindowTitle() const { |
| return UTF16ToWideHack(browser_->GetWindowTitleForCurrentTab()); |
| } |
| |
| std::wstring BrowserView::GetAccessibleWindowTitle() const { |
| if (IsOffTheRecord()) { |
| return UTF16ToWide(l10n_util::GetStringFUTF16( |
| IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, |
| WideToUTF16(GetWindowTitle()))); |
| } |
| return GetWindowTitle(); |
| } |
| |
| views::View* BrowserView::GetInitiallyFocusedView() { |
| // We set the frame not focus on creation so this should never be called. |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| bool BrowserView::ShouldShowWindowTitle() const { |
| return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); |
| } |
| |
| SkBitmap BrowserView::GetWindowAppIcon() { |
| if (browser_->type() & Browser::TYPE_APP) { |
| TabContentsWrapper* contents = browser_->GetSelectedTabContentsWrapper(); |
| if (contents && contents->extension_tab_helper()->GetExtensionAppIcon()) |
| return *contents->extension_tab_helper()->GetExtensionAppIcon(); |
| } |
| |
| return GetWindowIcon(); |
| } |
| |
| SkBitmap BrowserView::GetWindowIcon() { |
| if (browser_->type() & Browser::TYPE_APP) |
| return browser_->GetCurrentPageIcon(); |
| return SkBitmap(); |
| } |
| |
| bool BrowserView::ShouldShowWindowIcon() const { |
| return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); |
| } |
| |
| bool BrowserView::ExecuteWindowsCommand(int command_id) { |
| // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND. |
| |
| // Translate WM_APPCOMMAND command ids into a command id that the browser |
| // knows how to handle. |
| int command_id_from_app_command = GetCommandIDForAppCommandID(command_id); |
| if (command_id_from_app_command != -1) |
| command_id = command_id_from_app_command; |
| |
| return browser_->ExecuteCommandIfEnabled(command_id); |
| } |
| |
| std::wstring BrowserView::GetWindowName() const { |
| return UTF8ToWide(browser_->GetWindowPlacementKey()); |
| } |
| |
| void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds, |
| bool maximized) { |
| // If IsFullscreen() is true, we've just changed into fullscreen mode, and |
| // we're catching the going-into-fullscreen sizing and positioning calls, |
| // which we want to ignore. |
| if (!IsFullscreen() && browser_->ShouldSaveWindowPlacement()) { |
| WindowDelegate::SaveWindowPlacement(bounds, maximized); |
| browser_->SaveWindowPlacement(bounds, maximized); |
| } |
| } |
| |
| bool BrowserView::GetSavedWindowBounds(gfx::Rect* bounds) const { |
| *bounds = browser_->GetSavedWindowBounds(); |
| if (browser_->type() & Browser::TYPE_POPUP) { |
| // We are a popup window. The value passed in |bounds| represents two |
| // pieces of information: |
| // - the position of the window, in screen coordinates (outer position). |
| // - the size of the content area (inner size). |
| // We need to use these values to determine the appropriate size and |
| // position of the resulting window. |
| if (IsToolbarVisible()) { |
| // If we're showing the toolbar, we need to adjust |*bounds| to include |
| // its desired height, since the toolbar is considered part of the |
| // window's client area as far as GetWindowBoundsForClientBounds is |
| // concerned... |
| bounds->set_height( |
| bounds->height() + toolbar_->GetPreferredSize().height()); |
| } |
| |
| gfx::Rect window_rect = frame_->GetWindow()->non_client_view()-> |
| GetWindowBoundsForClientBounds(*bounds); |
| window_rect.set_origin(bounds->origin()); |
| |
| // When we are given x/y coordinates of 0 on a created popup window, |
| // assume none were given by the window.open() command. |
| if (window_rect.x() == 0 && window_rect.y() == 0) { |
| gfx::Size size = window_rect.size(); |
| window_rect.set_origin(WindowSizer::GetDefaultPopupOrigin(size)); |
| } |
| |
| *bounds = window_rect; |
| } |
| |
| // We return true because we can _always_ locate reasonable bounds using the |
| // WindowSizer, and we don't want to trigger the Window's built-in "size to |
| // default" handling because the browser window has no default preferred |
| // size. |
| return true; |
| } |
| |
| bool BrowserView::GetSavedMaximizedState(bool* maximized) const { |
| *maximized = browser_->GetSavedMaximizedState(); |
| return true; |
| } |
| |
| views::View* BrowserView::GetContentsView() { |
| return contents_container_; |
| } |
| |
| views::ClientView* BrowserView::CreateClientView(views::Window* window) { |
| set_window(window); |
| return this; |
| } |
| |
| void BrowserView::OnWindowActivationChanged(bool active) { |
| if (active) |
| BrowserList::SetLastActive(browser_.get()); |
| } |
| |
| void BrowserView::OnWindowBeginUserBoundsChange() { |
| TabContents* tab_contents = GetSelectedTabContents(); |
| if (tab_contents) |
| tab_contents->WindowMoveOrResizeStarted(); |
| } |
| |
| void BrowserView::OnWidgetMove() { |
| // Cancel any tabstrip animations, some of them may be invalidated by the |
| // window being repositioned. |
| // Comment out for one cycle to see if this fixes dist tests. |
| // tabstrip_->DestroyDragController(); |
| |
| status_bubble_->Reposition(); |
| |
| BrowserBubbleHost::WindowMoved(); |
| |
| browser::HideBookmarkBubbleView(); |
| |
| // Close the omnibox popup, if any. |
| if (toolbar_ && toolbar_->location_bar()) |
| toolbar_->location_bar()->location_entry()->ClosePopup(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, views::ClientView overrides: |
| |
| bool BrowserView::CanClose() { |
| // You cannot close a frame for which there is an active originating drag |
| // session. |
| if (tabstrip_ && !tabstrip_->IsTabStripCloseable()) |
| return false; |
| |
| // Give beforeunload handlers the chance to cancel the close before we hide |
| // the window below. |
| if (!browser_->ShouldCloseWindow()) |
| return false; |
| |
| if (!browser_->tabstrip_model()->empty()) { |
| // Tab strip isn't empty. Hide the frame (so it appears to have closed |
| // immediately) and close all the tabs, allowing the renderers to shut |
| // down. When the tab strip is empty we'll be called back again. |
| frame_->GetWindow()->HideWindow(); |
| browser_->OnWindowClosing(); |
| return false; |
| } |
| |
| // Empty TabStripModel, it's now safe to allow the Window to be closed. |
| NotificationService::current()->Notify( |
| NotificationType::WINDOW_CLOSED, |
| Source<gfx::NativeWindow>(frame_->GetWindow()->GetNativeWindow()), |
| NotificationService::NoDetails()); |
| return true; |
| } |
| |
| int BrowserView::NonClientHitTest(const gfx::Point& point) { |
| #if defined(OS_WIN) |
| // The following code is not in the LayoutManager because it's |
| // independent of layout and also depends on the ResizeCorner which |
| // is private. |
| if (!frame_->GetWindow()->IsMaximized() && |
| !frame_->GetWindow()->IsFullscreen()) { |
| CRect client_rect; |
| ::GetClientRect(frame_->GetWindow()->GetNativeWindow(), &client_rect); |
| gfx::Size resize_corner_size = ResizeCorner::GetSize(); |
| gfx::Rect resize_corner_rect(client_rect.right - resize_corner_size.width(), |
| client_rect.bottom - resize_corner_size.height(), |
| resize_corner_size.width(), resize_corner_size.height()); |
| bool rtl_dir = base::i18n::IsRTL(); |
| if (rtl_dir) |
| resize_corner_rect.set_x(0); |
| if (resize_corner_rect.Contains(point)) { |
| if (rtl_dir) |
| return HTBOTTOMLEFT; |
| return HTBOTTOMRIGHT; |
| } |
| } |
| #endif |
| |
| return GetBrowserViewLayout()->NonClientHitTest(point); |
| } |
| |
| gfx::Size BrowserView::GetMinimumSize() { |
| return GetBrowserViewLayout()->GetMinimumSize(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, protected |
| |
| void BrowserView::GetAccessiblePanes( |
| std::vector<AccessiblePaneView*>* panes) { |
| // This should be in the order of pane traversal of the panes using F6. |
| // If one of these is invisible or has no focusable children, it will be |
| // automatically skipped. |
| panes->push_back(toolbar_); |
| if (bookmark_bar_view_.get()) |
| panes->push_back(bookmark_bar_view_.get()); |
| if (infobar_container_) |
| panes->push_back(infobar_container_); |
| if (download_shelf_.get()) |
| panes->push_back(download_shelf_.get()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserView, views::View overrides: |
| |
| std::string BrowserView::GetClassName() const { |
| return kViewClassName; |
| } |
| |
| void BrowserView::Layout() { |
| if (ignore_layout_) |
| return; |
| views::View::Layout(); |
| |
| // The status bubble position requires that all other layout finish first. |
| LayoutStatusBubble(); |
| |
| #if defined(OS_WIN) |
| // Send the margins of the "user-perceived content area" of this |
| // browser window so AeroPeekManager can render a background-tab image in |
| // the area. |
| // TODO(pkasting) correct content inset?? |
| if (aeropeek_manager_.get()) { |
| gfx::Insets insets(GetFindBarBoundingBox().y() + 1, |
| 0, |
| 0, |
| 0); |
| aeropeek_manager_->SetContentInsets(insets); |
| } |
| #endif |
| } |
| |
| void BrowserView::PaintChildren(gfx::Canvas* canvas) { |
| // Paint the |infobar_container_| last so that it may paint its |
| // overlapping tabs. |
| for (int i = 0; i < child_count(); ++i) { |
| View* child = GetChildViewAt(i); |
| if (child != infobar_container_) |
| child->Paint(canvas); |
| } |
| |
| infobar_container_->Paint(canvas); |
| } |
| |
| void BrowserView::ViewHierarchyChanged(bool is_add, |
| views::View* parent, |
| views::View* child) { |
| if (is_add && child == this && GetWidget() && !initialized_) { |
| Init(); |
| initialized_ = true; |
| } |
| } |
| |
| void BrowserView::ChildPreferredSizeChanged(View* child) { |
| Layout(); |
| } |
| |
| void BrowserView::GetAccessibleState(ui::AccessibleViewState* state) { |
| state->name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); |
| state->role = ui::AccessibilityTypes::ROLE_CLIENT; |
| } |
| |
| SkColor BrowserView::GetInfoBarSeparatorColor() const { |
| // NOTE: Keep this in sync with ToolbarView::OnPaint()! |
| return (IsTabStripVisible() || |
| !frame_->GetWindow()->non_client_view()->UseNativeFrame()) ? |
| ResourceBundle::toolbar_separator_color : SK_ColorBLACK; |
| } |
| |
| void BrowserView::InfoBarContainerStateChanged(bool is_animating) { |
| ToolbarSizeChanged(is_animating); |
| } |
| |
| bool BrowserView::DrawInfoBarArrows(int* x) const { |
| if (x) { |
| const LocationIconView* location_icon_view = |
| toolbar_->location_bar()->location_icon_view(); |
| gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint()); |
| ConvertPointToView(location_icon_view, this, &icon_center); |
| *x = icon_center.x(); |
| } |
| return true; |
| } |
| |
| bool BrowserView::SplitHandleMoved(views::SingleSplitView* view) { |
| for (int i = 0; i < view->child_count(); ++i) |
| view->GetChildViewAt(i)->InvalidateLayout(); |
| SchedulePaint(); |
| Layout(); |
| return false; |
| } |
| |
| views::LayoutManager* BrowserView::CreateLayoutManager() const { |
| return new BrowserViewLayout; |
| } |
| |
| void BrowserView::InitTabStrip(TabStripModel* model) { |
| // Throw away the existing tabstrip if we're switching display modes. |
| scoped_ptr<AbstractTabStripView> old_strip(tabstrip_); |
| if (tabstrip_) |
| tabstrip_->parent()->RemoveChildView(tabstrip_); |
| |
| tabstrip_ = CreateTabStrip(browser_.get(), this, model, UseVerticalTabs()); |
| } |
| |
| ToolbarView* BrowserView::CreateToolbar() const { |
| return new ToolbarView(browser_.get()); |
| } |
| |
| void BrowserView::Init() { |
| SetLayoutManager(CreateLayoutManager()); |
| // Stow a pointer to this object onto the window handle so that we can get at |
| // it later when all we have is a native view. |
| GetWidget()->native_widget()->SetNativeWindowProperty(kBrowserViewKey, this); |
| |
| // Stow a pointer to the browser's profile onto the window handle so that we |
| // can get it later when all we have is a native view. |
| GetWidget()->native_widget()->SetNativeWindowProperty(Profile::kProfileKey, |
| browser_->profile()); |
| |
| // Start a hung plugin window detector for this browser object (as long as |
| // hang detection is not disabled). |
| if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableHangMonitor)) { |
| InitHangMonitor(); |
| } |
| |
| LoadAccelerators(); |
| |
| InitTabStrip(browser_->tabstrip_model()); |
| |
| SetToolbar(CreateToolbar()); |
| |
| infobar_container_ = new InfoBarContainerView(this); |
| AddChildView(infobar_container_); |
| |
| contents_container_ = new TabContentsContainer; |
| contents_ = new ContentsContainer(contents_container_); |
| |
| SkColor bg_color = GetWidget()->GetThemeProvider()-> |
| GetColor(ThemeService::COLOR_TOOLBAR); |
| |
| bool sidebar_allowed = SidebarManager::IsSidebarAllowed(); |
| if (sidebar_allowed) { |
| sidebar_container_ = new TabContentsContainer; |
| sidebar_container_->SetID(VIEW_ID_SIDE_BAR_CONTAINER); |
| sidebar_container_->SetVisible(false); |
| |
| sidebar_split_ = new views::SingleSplitView( |
| contents_, |
| sidebar_container_, |
| views::SingleSplitView::HORIZONTAL_SPLIT, |
| this); |
| sidebar_split_->SetID(VIEW_ID_SIDE_BAR_SPLIT); |
| sidebar_split_->SetAccessibleName( |
| l10n_util::GetStringUTF16(IDS_ACCNAME_SIDE_BAR)); |
| sidebar_split_->set_background( |
| views::Background::CreateSolidBackground(bg_color)); |
| } |
| |
| devtools_container_ = new TabContentsContainer; |
| devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED); |
| devtools_container_->SetVisible(false); |
| |
| views::View* contents_view = contents_; |
| if (sidebar_allowed) |
| contents_view = sidebar_split_; |
| |
| contents_split_ = new views::SingleSplitView( |
| contents_view, |
| devtools_container_, |
| views::SingleSplitView::VERTICAL_SPLIT, |
| this); |
| contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT); |
| contents_split_->SetAccessibleName( |
| l10n_util::GetStringUTF16(IDS_ACCNAME_WEB_CONTENTS)); |
| contents_split_->set_background( |
| views::Background::CreateSolidBackground(bg_color)); |
| AddChildView(contents_split_); |
| set_contents_view(contents_split_); |
| |
| status_bubble_.reset(new StatusBubbleViews(contents_)); |
| |
| #if defined(OS_WIN) |
| InitSystemMenu(); |
| |
| // Create a custom JumpList and add it to an observer of TabRestoreService |
| // so we can update the custom JumpList when a tab is added or removed. |
| if (JumpList::Enabled()) { |
| jumplist_.reset(new JumpList); |
| jumplist_->AddObserver(browser_->profile()); |
| } |
| |
| if (AeroPeekManager::Enabled()) { |
| aeropeek_manager_.reset(new AeroPeekManager( |
| frame_->GetWindow()->GetNativeWindow())); |
| browser_->tabstrip_model()->AddObserver(aeropeek_manager_.get()); |
| } |
| #endif |
| |
| // We're now initialized and ready to process Layout requests. |
| ignore_layout_ = false; |
| } |
| |
| void BrowserView::LoadingAnimationCallback() { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| if (!last_animation_time_.is_null()) { |
| UMA_HISTOGRAM_TIMES( |
| "Tabs.LoadingAnimationTime", |
| now - last_animation_time_); |
| } |
| last_animation_time_ = now; |
| if (browser_->type() == Browser::TYPE_NORMAL) { |
| // Loading animations are shown in the tab for tabbed windows. We check the |
| // browser type instead of calling IsTabStripVisible() because the latter |
| // will return false for fullscreen windows, but we still need to update |
| // their animations (so that when they come out of fullscreen mode they'll |
| // be correct). |
| tabstrip_->UpdateLoadingAnimations(); |
| } else if (ShouldShowWindowIcon()) { |
| // ... or in the window icon area for popups and app windows. |
| TabContents* tab_contents = browser_->GetSelectedTabContents(); |
| // GetSelectedTabContents can return NULL for example under Purify when |
| // the animations are running slowly and this function is called on a timer |
| // through LoadingAnimationCallback. |
| frame_->UpdateThrobber(tab_contents && tab_contents->is_loading()); |
| } |
| } |
| |
| // BrowserView, private -------------------------------------------------------- |
| |
| #if defined(OS_WIN) |
| void BrowserView::InitSystemMenu() { |
| system_menu_contents_.reset(new views::SystemMenuModel(this)); |
| // We add the menu items in reverse order so that insertion_index never needs |
| // to change. |
| if (IsBrowserTypeNormal()) |
| BuildSystemMenuForBrowserWindow(); |
| else |
| BuildSystemMenuForAppOrPopupWindow(browser_->type() == Browser::TYPE_APP); |
| system_menu_.reset( |
| new views::NativeMenuWin(system_menu_contents_.get(), |
| frame_->GetWindow()->GetNativeWindow())); |
| system_menu_->Rebuild(); |
| } |
| #endif |
| |
| BrowserViewLayout* BrowserView::GetBrowserViewLayout() const { |
| return static_cast<BrowserViewLayout*>(GetLayoutManager()); |
| } |
| |
| void BrowserView::LayoutStatusBubble() { |
| // In restored mode, the client area has a client edge between it and the |
| // frame. |
| int overlap = StatusBubbleViews::kShadowThickness + |
| (IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness); |
| int x = -overlap; |
| if (UseVerticalTabs() && IsTabStripVisible()) |
| x += tabstrip_->bounds().right(); |
| int height = status_bubble_->GetPreferredSize().height(); |
| int contents_height = status_bubble_->base_view()->bounds().height(); |
| gfx::Point origin(-overlap, contents_height - height + overlap); |
| status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height); |
| } |
| |
| bool BrowserView::MaybeShowBookmarkBar(TabContentsWrapper* contents) { |
| views::View* new_bookmark_bar_view = NULL; |
| if (browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) |
| && contents) { |
| if (!bookmark_bar_view_.get()) { |
| bookmark_bar_view_.reset(new BookmarkBarView(contents->profile(), |
| browser_.get())); |
| bookmark_bar_view_->set_parent_owned(false); |
| bookmark_bar_view_->set_background( |
| new BookmarkExtensionBackground(this, bookmark_bar_view_.get(), |
| browser_.get())); |
| } else { |
| bookmark_bar_view_->SetProfile(contents->profile()); |
| } |
| bookmark_bar_view_->SetPageNavigator(contents->tab_contents()); |
| new_bookmark_bar_view = bookmark_bar_view_.get(); |
| } |
| return UpdateChildViewAndLayout(new_bookmark_bar_view, &active_bookmark_bar_); |
| } |
| |
| bool BrowserView::MaybeShowInfoBar(TabContentsWrapper* contents) { |
| // TODO(beng): Remove this function once the interface between |
| // InfoBarContainer, DownloadShelfView and TabContents and this |
| // view is sorted out. |
| return true; |
| } |
| |
| void BrowserView::UpdateSidebar() { |
| UpdateSidebarForContents(GetSelectedTabContentsWrapper()); |
| Layout(); |
| } |
| |
| void BrowserView::UpdateSidebarForContents(TabContentsWrapper* tab_contents) { |
| if (!sidebar_container_) |
| return; // Happens when sidebar is not allowed. |
| if (!SidebarManager::GetInstance()) |
| return; // Happens only in tests. |
| |
| TabContents* sidebar_contents = NULL; |
| if (tab_contents) { |
| SidebarContainer* client_host = SidebarManager::GetInstance()-> |
| GetActiveSidebarContainerFor(tab_contents->tab_contents()); |
| if (client_host) |
| sidebar_contents = client_host->sidebar_contents(); |
| } |
| |
| bool visible = NULL != sidebar_contents && |
| browser_->SupportsWindowFeature(Browser::FEATURE_SIDEBAR); |
| |
| bool should_show = visible && !sidebar_container_->IsVisible(); |
| bool should_hide = !visible && sidebar_container_->IsVisible(); |
| |
| // Update sidebar content. |
| TabContents* old_contents = sidebar_container_->tab_contents(); |
| sidebar_container_->ChangeTabContents(sidebar_contents); |
| SidebarManager::GetInstance()-> |
| NotifyStateChanges(old_contents, sidebar_contents); |
| |
| // Update sidebar UI width. |
| if (should_show) { |
| // Restore split offset. |
| int sidebar_width = g_browser_process->local_state()->GetInteger( |
| prefs::kExtensionSidebarWidth); |
| if (sidebar_width < 0) { |
| // Initial load, set to default value. |
| sidebar_width = sidebar_split_->width() / 7; |
| } |
| // Make sure user can see both panes. |
| int min_sidebar_width = sidebar_split_->GetMinimumSize().width(); |
| sidebar_width = std::min(sidebar_split_->width() - min_sidebar_width, |
| std::max(min_sidebar_width, sidebar_width)); |
| |
| sidebar_split_->set_divider_offset( |
| sidebar_split_->width() - sidebar_width); |
| |
| sidebar_container_->SetVisible(true); |
| sidebar_split_->InvalidateLayout(); |
| Layout(); |
| } else if (should_hide) { |
| // Store split offset when hiding sidebar only. |
| g_browser_process->local_state()->SetInteger( |
| prefs::kExtensionSidebarWidth, |
| sidebar_split_->width() - sidebar_split_->divider_offset()); |
| |
| sidebar_container_->SetVisible(false); |
| sidebar_split_->InvalidateLayout(); |
| Layout(); |
| } |
| } |
| |
| void BrowserView::UpdateDevToolsForContents(TabContentsWrapper* wrapper) { |
| TabContents* devtools_contents = NULL; |
| if (wrapper) { |
| TabContentsWrapper* devtools_contents_wrapper = |
| DevToolsWindow::GetDevToolsContents(wrapper->tab_contents()); |
| if (devtools_contents_wrapper) |
| devtools_contents = devtools_contents_wrapper->tab_contents(); |
| } |
| |
| bool should_show = devtools_contents && !devtools_container_->IsVisible(); |
| bool should_hide = !devtools_contents && devtools_container_->IsVisible(); |
| |
| devtools_container_->ChangeTabContents(devtools_contents); |
| |
| if (should_show) { |
| if (!devtools_focus_tracker_.get()) { |
| // Install devtools focus tracker when dev tools window is shown for the |
| // first time. |
| devtools_focus_tracker_.reset( |
| new views::ExternalFocusTracker(devtools_container_, |
| GetFocusManager())); |
| } |
| |
| // Restore split offset. |
| int split_offset = browser_->profile()->GetPrefs()-> |
| GetInteger(prefs::kDevToolsSplitLocation); |
| if (split_offset == -1) { |
| // Initial load, set to default value. |
| split_offset = 2 * contents_split_->height() / 3; |
| } |
| // Make sure user can see both panes. |
| int min_split_size = contents_split_->height() / 10; |
| split_offset = std::min(contents_split_->height() - min_split_size, |
| std::max(min_split_size, split_offset)); |
| contents_split_->set_divider_offset(split_offset); |
| |
| devtools_container_->SetVisible(true); |
| contents_split_->InvalidateLayout(); |
| Layout(); |
| } else if (should_hide) { |
| // Store split offset when hiding devtools window only. |
| browser_->profile()->GetPrefs()->SetInteger(prefs::kDevToolsSplitLocation, |
| contents_split_->divider_offset()); |
| |
| // Restore focus to the last focused view when hiding devtools window. |
| devtools_focus_tracker_->FocusLastFocusedExternalView(); |
| |
| devtools_container_->SetVisible(false); |
| contents_split_->InvalidateLayout(); |
| Layout(); |
| } |
| } |
| |
| void BrowserView::UpdateUIForContents(TabContentsWrapper* contents) { |
| bool needs_layout = MaybeShowBookmarkBar(contents); |
| needs_layout |= MaybeShowInfoBar(contents); |
| if (needs_layout) |
| Layout(); |
| } |
| |
| bool BrowserView::UpdateChildViewAndLayout(views::View* new_view, |
| views::View** old_view) { |
| DCHECK(old_view); |
| if (*old_view == new_view) { |
| // The views haven't changed, if the views pref changed schedule a layout. |
| if (new_view) { |
| if (new_view->GetPreferredSize().height() != new_view->height()) |
| return true; |
| } |
| return false; |
| } |
| |
| // The views differ, and one may be null (but not both). Remove the old |
| // view (if it non-null), and add the new one (if it is non-null). If the |
| // height has changed, schedule a layout, otherwise reuse the existing |
| // bounds to avoid scheduling a layout. |
| |
| int current_height = 0; |
| if (*old_view) { |
| current_height = (*old_view)->height(); |
| RemoveChildView(*old_view); |
| } |
| |
| int new_height = 0; |
| if (new_view) { |
| new_height = new_view->GetPreferredSize().height(); |
| AddChildView(new_view); |
| } |
| bool changed = false; |
| if (new_height != current_height) { |
| changed = true; |
| } else if (new_view && *old_view) { |
| // The view changed, but the new view wants the same size, give it the |
| // bounds of the last view and have it repaint. |
| new_view->SetBoundsRect((*old_view)->bounds()); |
| new_view->SchedulePaint(); |
| } else if (new_view) { |
| DCHECK_EQ(0, new_height); |
| // The heights are the same, but the old view is null. This only happens |
| // when the height is zero. Zero out the bounds. |
| new_view->SetBounds(0, 0, 0, 0); |
| } |
| *old_view = new_view; |
| return changed; |
| } |
| |
| void BrowserView::ProcessFullscreen(bool fullscreen) { |
| // Reduce jankiness during the following position changes by: |
| // * Hiding the window until it's in the final position |
| // * Ignoring all intervening Layout() calls, which resize the webpage and |
| // thus are slow and look ugly |
| ignore_layout_ = true; |
| LocationBarView* location_bar = toolbar_->location_bar(); |
| #if defined(OS_WIN) |
| AutocompleteEditViewWin* edit_view = |
| static_cast<AutocompleteEditViewWin*>(location_bar->location_entry()); |
| #endif |
| if (!fullscreen) { |
| // Hide the fullscreen bubble as soon as possible, since the mode toggle can |
| // take enough time for the user to notice. |
| fullscreen_bubble_.reset(); |
| } else { |
| // Move focus out of the location bar if necessary. |
| views::FocusManager* focus_manager = GetFocusManager(); |
| DCHECK(focus_manager); |
| if (focus_manager->GetFocusedView() == location_bar) |
| focus_manager->ClearFocus(); |
| |
| #if defined(OS_WIN) |
| // If we don't hide the edit and force it to not show until we come out of |
| // fullscreen, then if the user was on the New Tab Page, the edit contents |
| // will appear atop the web contents once we go into fullscreen mode. This |
| // has something to do with how we move the main window while it's hidden; |
| // if we don't hide the main window below, we don't get this problem. |
| edit_view->set_force_hidden(true); |
| ShowWindow(edit_view->m_hWnd, SW_HIDE); |
| #endif |
| } |
| #if defined(OS_WIN) |
| static_cast<views::WindowWin*>( |
| frame_->GetWindow()->native_window())->PushForceHidden(); |
| #endif |
| |
| // Notify bookmark bar, so it can set itself to the appropriate drawing state. |
| if (bookmark_bar_view_.get()) |
| bookmark_bar_view_->OnFullscreenToggled(fullscreen); |
| |
| // Toggle fullscreen mode. |
| #if defined(OS_WIN) |
| frame_->GetWindow()->SetFullscreen(fullscreen); |
| #endif // No need to invoke SetFullscreen for linux as this code is executed |
| // once we're already fullscreen on linux. |
| |
| #if defined(OS_LINUX) |
| // Updating of commands for fullscreen mode is called from SetFullScreen on |
| // Wndows (see just above), but for ChromeOS, this method (ProcessFullScreen) |
| // is called after full screen has happened successfully (via GTK's |
| // window-state-change event), so we have to update commands here. |
| browser_->UpdateCommandsForFullscreenMode(fullscreen); |
| #endif |
| |
| if (fullscreen) { |
| bool is_kiosk = |
| CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode); |
| if (!is_kiosk) { |
| fullscreen_bubble_.reset(new FullscreenExitBubble(GetWidget(), |
| browser_.get())); |
| } |
| } else { |
| #if defined(OS_WIN) |
| // Show the edit again since we're no longer in fullscreen mode. |
| edit_view->set_force_hidden(false); |
| ShowWindow(edit_view->m_hWnd, SW_SHOW); |
| #endif |
| } |
| |
| // Undo our anti-jankiness hacks and force the window to relayout now that |
| // it's in its final position. |
| ignore_layout_ = false; |
| Layout(); |
| #if defined(OS_WIN) |
| static_cast<views::WindowWin*>( |
| frame_->GetWindow()->native_window())->PopForceHidden(); |
| #endif |
| } |
| |
| |
| void BrowserView::LoadAccelerators() { |
| #if defined(OS_WIN) |
| HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME); |
| DCHECK(accelerator_table); |
| |
| // We have to copy the table to access its contents. |
| int count = CopyAcceleratorTable(accelerator_table, 0, 0); |
| if (count == 0) { |
| // Nothing to do in that case. |
| return; |
| } |
| |
| ACCEL* accelerators = static_cast<ACCEL*>(malloc(sizeof(ACCEL) * count)); |
| CopyAcceleratorTable(accelerator_table, accelerators, count); |
| |
| views::FocusManager* focus_manager = GetFocusManager(); |
| DCHECK(focus_manager); |
| |
| // Let's fill our own accelerator table. |
| for (int i = 0; i < count; ++i) { |
| bool alt_down = (accelerators[i].fVirt & FALT) == FALT; |
| bool ctrl_down = (accelerators[i].fVirt & FCONTROL) == FCONTROL; |
| bool shift_down = (accelerators[i].fVirt & FSHIFT) == FSHIFT; |
| views::Accelerator accelerator( |
| static_cast<ui::KeyboardCode>(accelerators[i].key), |
| shift_down, ctrl_down, alt_down); |
| accelerator_table_[accelerator] = accelerators[i].cmd; |
| |
| // Also register with the focus manager. |
| focus_manager->RegisterAccelerator(accelerator, this); |
| } |
| |
| // We don't need the Windows accelerator table anymore. |
| free(accelerators); |
| #else |
| views::FocusManager* focus_manager = GetFocusManager(); |
| DCHECK(focus_manager); |
| // Let's fill our own accelerator table. |
| for (size_t i = 0; i < browser::kAcceleratorMapLength; ++i) { |
| views::Accelerator accelerator(browser::kAcceleratorMap[i].keycode, |
| browser::kAcceleratorMap[i].shift_pressed, |
| browser::kAcceleratorMap[i].ctrl_pressed, |
| browser::kAcceleratorMap[i].alt_pressed); |
| accelerator_table_[accelerator] = browser::kAcceleratorMap[i].command_id; |
| |
| // Also register with the focus manager. |
| focus_manager->RegisterAccelerator(accelerator, this); |
| } |
| #endif |
| } |
| |
| #if defined(OS_WIN) |
| void BrowserView::BuildSystemMenuForBrowserWindow() { |
| system_menu_contents_->AddSeparator(); |
| system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER, |
| IDS_TASK_MANAGER); |
| system_menu_contents_->AddSeparator(); |
| system_menu_contents_->AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); |
| system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB); |
| // If it's a regular browser window with tabs, we don't add any more items, |
| // since it already has menus (Page, Chrome). |
| } |
| |
| void BrowserView::BuildSystemMenuForAppOrPopupWindow(bool is_app) { |
| if (is_app) { |
| system_menu_contents_->AddSeparator(); |
| system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER, |
| IDS_TASK_MANAGER); |
| } |
| system_menu_contents_->AddSeparator(); |
| encoding_menu_contents_.reset(new EncodingMenuModel(browser_.get())); |
| system_menu_contents_->AddSubMenuWithStringId(IDC_ENCODING_MENU, |
| IDS_ENCODING_MENU, |
| encoding_menu_contents_.get()); |
| zoom_menu_contents_.reset(new ZoomMenuModel(this)); |
| system_menu_contents_->AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_ZOOM_MENU, |
| zoom_menu_contents_.get()); |
| system_menu_contents_->AddItemWithStringId(IDC_PRINT, IDS_PRINT); |
| system_menu_contents_->AddItemWithStringId(IDC_FIND, IDS_FIND); |
| system_menu_contents_->AddSeparator(); |
| system_menu_contents_->AddItemWithStringId(IDC_PASTE, IDS_PASTE); |
| system_menu_contents_->AddItemWithStringId(IDC_COPY, IDS_COPY); |
| system_menu_contents_->AddItemWithStringId(IDC_CUT, IDS_CUT); |
| system_menu_contents_->AddSeparator(); |
| if (is_app) { |
| system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, |
| IDS_APP_MENU_NEW_WEB_PAGE); |
| } else { |
| system_menu_contents_->AddItemWithStringId(IDC_SHOW_AS_TAB, |
| IDS_SHOW_AS_TAB); |
| } |
| system_menu_contents_->AddItemWithStringId(IDC_COPY_URL, |
| IDS_APP_MENU_COPY_URL); |
| system_menu_contents_->AddSeparator(); |
| system_menu_contents_->AddItemWithStringId(IDC_RELOAD, IDS_APP_MENU_RELOAD); |
| system_menu_contents_->AddItemWithStringId(IDC_FORWARD, |
| IDS_CONTENT_CONTEXT_FORWARD); |
| system_menu_contents_->AddItemWithStringId(IDC_BACK, |
| IDS_CONTENT_CONTEXT_BACK); |
| } |
| #endif |
| |
| int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const { |
| #if defined(OS_WIN) |
| switch (app_command_id) { |
| // NOTE: The order here matches the APPCOMMAND declaration order in the |
| // Windows headers. |
| case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK; |
| case APPCOMMAND_BROWSER_FORWARD: return IDC_FORWARD; |
| case APPCOMMAND_BROWSER_REFRESH: return IDC_RELOAD; |
| case APPCOMMAND_BROWSER_HOME: return IDC_HOME; |
| case APPCOMMAND_BROWSER_STOP: return IDC_STOP; |
| case APPCOMMAND_BROWSER_SEARCH: return IDC_FOCUS_SEARCH; |
| case APPCOMMAND_HELP: return IDC_HELP_PAGE; |
| case APPCOMMAND_NEW: return IDC_NEW_TAB; |
| case APPCOMMAND_OPEN: return IDC_OPEN_FILE; |
| case APPCOMMAND_CLOSE: return IDC_CLOSE_TAB; |
| case APPCOMMAND_SAVE: return IDC_SAVE_PAGE; |
| case APPCOMMAND_PRINT: return IDC_PRINT; |
| case APPCOMMAND_COPY: return IDC_COPY; |
| case APPCOMMAND_CUT: return IDC_CUT; |
| case APPCOMMAND_PASTE: return IDC_PASTE; |
| |
| // TODO(pkasting): http://b/1113069 Handle these. |
| case APPCOMMAND_UNDO: |
| case APPCOMMAND_REDO: |
| case APPCOMMAND_SPELL_CHECK: |
| default: return -1; |
| } |
| #else |
| // App commands are Windows-specific so there's nothing to do here. |
| return -1; |
| #endif |
| } |
| |
| void BrowserView::InitHangMonitor() { |
| #if defined(OS_WIN) |
| PrefService* pref_service = g_browser_process->local_state(); |
| if (!pref_service) |
| return; |
| |
| int plugin_message_response_timeout = |
| pref_service->GetInteger(prefs::kPluginMessageResponseTimeout); |
| int hung_plugin_detect_freq = |
| pref_service->GetInteger(prefs::kHungPluginDetectFrequency); |
| if ((hung_plugin_detect_freq > 0) && |
| hung_window_detector_.Initialize(GetWidget()->GetNativeView(), |
| plugin_message_response_timeout)) { |
| ticker_.set_tick_interval(hung_plugin_detect_freq); |
| ticker_.RegisterTickHandler(&hung_window_detector_); |
| ticker_.Start(); |
| |
| pref_service->SetInteger(prefs::kPluginMessageResponseTimeout, |
| plugin_message_response_timeout); |
| pref_service->SetInteger(prefs::kHungPluginDetectFrequency, |
| hung_plugin_detect_freq); |
| } |
| #endif |
| } |
| |
| void BrowserView::UpdateAcceleratorMetrics( |
| const views::Accelerator& accelerator, int command_id) { |
| #if defined(OS_CHROMEOS) |
| // Collect information about the relative popularity of various accelerators |
| // on Chrome OS. |
| const ui::KeyboardCode key_code = accelerator.GetKeyCode(); |
| switch (command_id) { |
| case IDC_BACK: |
| if (key_code == ui::VKEY_BACK) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Back_Backspace")); |
| else if (key_code == ui::VKEY_F1) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Back_F1")); |
| else if (key_code == ui::VKEY_LEFT) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Back_Left")); |
| break; |
| case IDC_FORWARD: |
| if (key_code == ui::VKEY_BACK) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_Backspace")); |
| else if (key_code == ui::VKEY_F2) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_F2")); |
| else if (key_code == ui::VKEY_RIGHT) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_Right")); |
| break; |
| case IDC_RELOAD: |
| case IDC_RELOAD_IGNORING_CACHE: |
| if (key_code == ui::VKEY_R) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Reload_R")); |
| else if (key_code == ui::VKEY_F3) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Reload_F3")); |
| break; |
| case IDC_FULLSCREEN: |
| if (key_code == ui::VKEY_F4) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Fullscreen_F4")); |
| break; |
| case IDC_NEW_TAB: |
| if (key_code == ui::VKEY_T) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_NewTab_T")); |
| break; |
| case IDC_SEARCH: |
| if (key_code == ui::VKEY_LWIN) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_Search_LWin")); |
| break; |
| case IDC_FOCUS_LOCATION: |
| if (key_code == ui::VKEY_D) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_FocusLocation_D")); |
| else if (key_code == ui::VKEY_L) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_FocusLocation_L")); |
| break; |
| case IDC_FOCUS_SEARCH: |
| if (key_code == ui::VKEY_E) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_FocusSearch_E")); |
| else if (key_code == ui::VKEY_K) |
| UserMetrics::RecordAction(UserMetricsAction("Accel_FocusSearch_K")); |
| break; |
| default: |
| // Do nothing. |
| break; |
| } |
| #endif |
| } |
| |
| void BrowserView::ProcessTabSelected(TabContentsWrapper* new_contents, |
| bool change_tab_contents) { |
| // Update various elements that are interested in knowing the current |
| // TabContents. |
| |
| // When we toggle the NTP floating bookmarks bar and/or the info bar, |
| // we don't want any TabContents to be attached, so that we |
| // avoid an unnecessary resize and re-layout of a TabContents. |
| if (change_tab_contents) |
| contents_container_->ChangeTabContents(NULL); |
| infobar_container_->ChangeTabContents(new_contents->tab_contents()); |
| UpdateUIForContents(new_contents); |
| if (change_tab_contents) |
| contents_container_->ChangeTabContents(new_contents->tab_contents()); |
| UpdateSidebarForContents(new_contents); |
| |
| UpdateDevToolsForContents(new_contents); |
| // TODO(beng): This should be called automatically by ChangeTabContents, but I |
| // am striving for parity now rather than cleanliness. This is |
| // required to make features like Duplicate Tab, Undo Close Tab, |
| // etc not result in sad tab. |
| new_contents->tab_contents()->DidBecomeSelected(); |
| if (BrowserList::GetLastActive() == browser_ && |
| !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) { |
| // We only restore focus if our window is visible, to avoid invoking blur |
| // handlers when we are eventually shown. |
| new_contents->view()->RestoreFocus(); |
| } |
| |
| // Update all the UI bits. |
| UpdateTitleBar(); |
| // No need to update Toolbar because it's already updated in |
| // browser.cc. |
| } |
| |
| gfx::Size BrowserView::GetResizeCornerSize() const { |
| return ResizeCorner::GetSize(); |
| } |
| |
| void BrowserView::SetToolbar(ToolbarView* toolbar) { |
| if (toolbar_) { |
| RemoveChildView(toolbar_); |
| delete toolbar_; |
| } |
| toolbar_ = toolbar; |
| if (toolbar) { |
| AddChildView(toolbar_); |
| toolbar_->Init(browser_->profile()); |
| } |
| } |
| |
| #if !defined(OS_CHROMEOS) |
| // static |
| BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { |
| // Create the view and the frame. The frame will attach itself via the view |
| // so we don't need to do anything with the pointer. |
| BrowserView* view = new BrowserView(browser); |
| BrowserFrame::Create(view, browser->profile()); |
| |
| view->GetWindow()->non_client_view()->SetAccessibleName( |
| l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); |
| |
| return view; |
| } |
| #endif |
| |
| // static |
| FindBar* BrowserWindow::CreateFindBar(Browser* browser) { |
| return browser::CreateFindBar(static_cast<BrowserView*>(browser->window())); |
| } |