| // Copyright (c) 2012 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_frame_win.h" |
| |
| #include <dwmapi.h> |
| #include <shellapi.h> |
| #include <set> |
| |
| #include "base/command_line.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/win/metro.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/lifetime/application_lifetime.h" |
| #include "chrome/browser/search_engines/template_url.h" |
| #include "chrome/browser/search_engines/template_url_service.h" |
| #include "chrome/browser/search_engines/template_url_service_factory.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/toolbar/wrench_menu_model.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "chrome/browser/ui/views/frame/system_menu_model.h" |
| #include "chrome/browser/ui/views/frame/system_menu_model_delegate.h" |
| #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "content/public/browser/browser_accessibility_state.h" |
| #include "content/public/browser/page_navigator.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/page_transition_types.h" |
| #include "googleurl/src/gurl.h" |
| #include "grit/generated_resources.h" |
| #include "grit/theme_resources.h" |
| #include "ui/base/layout.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/models/simple_menu_model.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/base/theme_provider.h" |
| #include "ui/gfx/font.h" |
| #include "ui/views/controls/menu/native_menu_win.h" |
| #include "ui/views/views_delegate.h" |
| #include "ui/views/widget/native_widget_win.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/window/non_client_view.h" |
| #include "webkit/glue/window_open_disposition.h" |
| |
| #pragma comment(lib, "dwmapi.lib") |
| |
| // static |
| static const int kClientEdgeThickness = 3; |
| static const int kTabDragWindowAlpha = 200; |
| // We need to offset the DWMFrame into the toolbar so that the blackness |
| // doesn't show up on our rounded corners. |
| static const int kDWMFrameTopOffset = 3; |
| // If not -1, windows are shown with this state. |
| static int explicit_show_state = -1; |
| |
| using content::OpenURLParams; |
| using content::Referrer; |
| using content::WebContents; |
| |
| #if !defined(USE_AURA) |
| extern "C" { |
| // Windows metro exported functions from metro_driver. |
| typedef void (*SetFrameWindow)(HWND window); |
| typedef void (*CloseFrameWindow)(HWND window); |
| typedef void (*FlipFrameWindows)(); |
| typedef void (*MetroSetFullscreen)(bool fullscreen); |
| } |
| #endif // USE_AURA |
| |
| views::Button* MakeWindowSwitcherButton(views::ButtonListener* listener, |
| bool is_off_the_record) { |
| views::ImageButton* switcher_button = new views::ImageButton(listener); |
| // The button in the incognito window has the hot-cold images inverted |
| // with respect to the regular browser window. |
| switcher_button->SetImage( |
| views::ImageButton::BS_NORMAL, |
| ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| is_off_the_record ? IDR_INCOGNITO_SWITCH_ON : |
| IDR_INCOGNITO_SWITCH_OFF)); |
| switcher_button->SetImage( |
| views::ImageButton::BS_HOT, |
| ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| is_off_the_record ? IDR_INCOGNITO_SWITCH_OFF : |
| IDR_INCOGNITO_SWITCH_ON)); |
| switcher_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER, |
| views::ImageButton::ALIGN_MIDDLE); |
| return switcher_button; |
| } |
| |
| static int GetMinimizeButtonOffsetForWindow(gfx::NativeView window) { |
| // The WM_GETTITLEBARINFOEX message can fail if we are not active/visible. |
| TITLEBARINFOEX titlebar_info = {0}; |
| titlebar_info.cbSize = sizeof(TITLEBARINFOEX); |
| SendMessage(window, WM_GETTITLEBARINFOEX, 0, |
| reinterpret_cast<WPARAM>(&titlebar_info)); |
| |
| CPoint minimize_button_corner(titlebar_info.rgrect[2].left, |
| titlebar_info.rgrect[2].top); |
| MapWindowPoints(HWND_DESKTOP, window, &minimize_button_corner, 1); |
| return minimize_button_corner.x; |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserFrameWin, public: |
| |
| BrowserFrameWin::BrowserFrameWin(BrowserFrame* browser_frame, |
| BrowserView* browser_view) |
| : views::NativeWidgetWin(browser_frame), |
| browser_view_(browser_view), |
| browser_frame_(browser_frame), |
| system_menu_delegate_(new SystemMenuModelDelegate(browser_view, |
| browser_view->browser())), |
| cached_minimize_button_x_delta_(0) { |
| if (base::win::IsMetroProcess()) { |
| browser_view->SetWindowSwitcherButton( |
| MakeWindowSwitcherButton(this, browser_view->IsOffTheRecord())); |
| } |
| } |
| |
| BrowserFrameWin::~BrowserFrameWin() { |
| } |
| |
| // static |
| void BrowserFrameWin::SetShowState(int state) { |
| explicit_show_state = state; |
| } |
| |
| void BrowserFrameWin::AdjustFrameForImmersiveMode() { |
| #if defined(USE_AURA) |
| return; |
| #endif // USE_AURA |
| HMODULE metro = base::win::GetMetroModule(); |
| if (!metro) |
| return; |
| // We are in metro mode. |
| browser_frame_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM); |
| SetFrameWindow set_frame_window = reinterpret_cast<SetFrameWindow>( |
| ::GetProcAddress(metro, "SetFrameWindow")); |
| set_frame_window(browser_frame_->GetNativeWindow()); |
| } |
| |
| void BrowserFrameWin::CloseImmersiveFrame() { |
| #if defined(USE_AURA) |
| return; |
| #endif // USE_AURA |
| HMODULE metro = base::win::GetMetroModule(); |
| if (!metro) |
| return; |
| CloseFrameWindow close_frame_window = reinterpret_cast<CloseFrameWindow>( |
| ::GetProcAddress(metro, "CloseFrameWindow")); |
| close_frame_window(browser_frame_->GetNativeWindow()); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserFrameWin, views::NativeWidgetWin overrides: |
| |
| int BrowserFrameWin::GetInitialShowState() const { |
| if (explicit_show_state != -1) |
| return explicit_show_state; |
| |
| STARTUPINFO si = {0}; |
| si.cb = sizeof(si); |
| si.dwFlags = STARTF_USESHOWWINDOW; |
| GetStartupInfo(&si); |
| return si.wShowWindow; |
| } |
| |
| bool BrowserFrameWin::GetClientAreaInsets(gfx::Insets* insets) const { |
| // Use the default client insets for an opaque frame or a glass popup/app |
| // frame. |
| if (!GetWidget()->ShouldUseNativeFrame() || |
| !browser_view_->IsBrowserTypeNormal()) { |
| return false; |
| } |
| |
| int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); |
| // In fullscreen mode, we have no frame. In restored mode, we draw our own |
| // client edge over part of the default frame. |
| if (IsFullscreen()) |
| border_thickness = 0; |
| else if (!IsMaximized()) |
| border_thickness -= kClientEdgeThickness; |
| insets->Set(0, border_thickness, border_thickness, border_thickness); |
| return true; |
| } |
| |
| void BrowserFrameWin::HandleFrameChanged() { |
| // We need to update the glass region on or off before the base class adjusts |
| // the window region. |
| UpdateDWMFrame(); |
| NativeWidgetWin::HandleFrameChanged(); |
| } |
| |
| bool BrowserFrameWin::PreHandleMSG(UINT message, |
| WPARAM w_param, |
| LPARAM l_param, |
| LRESULT* result) { |
| static const UINT metro_navigation_search_message = |
| RegisterWindowMessage(chrome::kMetroNavigationAndSearchMessage); |
| |
| static const UINT metro_get_current_tab_info_message = |
| RegisterWindowMessage(chrome::kMetroGetCurrentTabInfoMessage); |
| |
| if (message == metro_navigation_search_message) { |
| HandleMetroNavSearchRequest(w_param, l_param); |
| return false; |
| } else if (message == metro_get_current_tab_info_message) { |
| GetMetroCurrentTabInfo(w_param); |
| return false; |
| } |
| |
| switch (message) { |
| case WM_ACTIVATE: |
| if (LOWORD(w_param) != WA_INACTIVE) |
| CacheMinimizeButtonDelta(); |
| return false; |
| case WM_PRINT: |
| if (base::win::IsMetroProcess()) { |
| // This message is sent by the AnimateWindow API which is used in metro |
| // mode to flip between active chrome windows. |
| RECT client_rect = {0}; |
| ::GetClientRect(GetNativeView(), &client_rect); |
| HDC dest_dc = reinterpret_cast<HDC>(w_param); |
| DCHECK(dest_dc); |
| HDC src_dc = ::GetDC(GetNativeView()); |
| ::BitBlt(dest_dc, 0, 0, client_rect.right - client_rect.left, |
| client_rect.bottom - client_rect.top, src_dc, 0, 0, |
| SRCCOPY); |
| ::ReleaseDC(GetNativeView(), src_dc); |
| *result = 0; |
| return true; |
| } |
| return false; |
| case WM_ENDSESSION: |
| browser::SessionEnding(); |
| return true; |
| case WM_INITMENUPOPUP: |
| system_menu_->UpdateStates(); |
| return true; |
| } |
| return false; |
| } |
| |
| void BrowserFrameWin::PostHandleMSG(UINT message, |
| WPARAM w_param, |
| LPARAM l_param) { |
| switch (message) { |
| case WM_WINDOWPOSCHANGED: |
| UpdateDWMFrame(); |
| |
| // Windows lies to us about the position of the minimize button before a |
| // window is visible. We use this position to place the OTR avatar in RTL |
| // mode, so when the window is shown, we need to re-layout and schedule a |
| // paint for the non-client frame view so that the icon top has the correct |
| // position when the window becomes visible. This fixes bugs where the icon |
| // appears to overlay the minimize button. |
| // Note that we will call Layout every time SetWindowPos is called with |
| // SWP_SHOWWINDOW, however callers typically are careful about not |
| // specifying this flag unless necessary to avoid flicker. |
| // This may be invoked during creation on XP and before the non_client_view |
| // has been created. |
| WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(l_param); |
| if (window_pos->flags & SWP_SHOWWINDOW && GetWidget()->non_client_view()) { |
| GetWidget()->non_client_view()->Layout(); |
| GetWidget()->non_client_view()->SchedulePaint(); |
| } |
| break; |
| } |
| } |
| |
| void BrowserFrameWin::OnScreenReaderDetected() { |
| BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected(); |
| NativeWidgetWin::OnScreenReaderDetected(); |
| } |
| |
| bool BrowserFrameWin::ShouldUseNativeFrame() const { |
| // App panel windows draw their own frame. |
| if (browser_view_->IsPanel()) |
| return false; |
| |
| // We don't theme popup or app windows, so regardless of whether or not a |
| // theme is active for normal browser windows, we don't want to use the custom |
| // frame for popups/apps. |
| if (!browser_view_->IsBrowserTypeNormal() && |
| NativeWidgetWin::ShouldUseNativeFrame()) { |
| return true; |
| } |
| |
| // Otherwise, we use the native frame when we're told we should by the theme |
| // provider (e.g. no custom theme is active). |
| return GetWidget()->GetThemeProvider()->ShouldUseNativeFrame(); |
| } |
| |
| void BrowserFrameWin::Show() { |
| AdjustFrameForImmersiveMode(); |
| views::NativeWidgetWin::Show(); |
| } |
| |
| void BrowserFrameWin::ShowMaximizedWithBounds( |
| const gfx::Rect& restored_bounds) { |
| AdjustFrameForImmersiveMode(); |
| views::NativeWidgetWin::ShowMaximizedWithBounds(restored_bounds); |
| } |
| |
| void BrowserFrameWin::ShowWithWindowState(ui::WindowShowState show_state) { |
| AdjustFrameForImmersiveMode(); |
| views::NativeWidgetWin::ShowWithWindowState(show_state); |
| } |
| |
| void BrowserFrameWin::Close() { |
| CloseImmersiveFrame(); |
| views::NativeWidgetWin::Close(); |
| } |
| |
| void BrowserFrameWin::FrameTypeChanged() { |
| // In Windows 8 metro mode the frame type is set to FRAME_TYPE_FORCE_CUSTOM |
| // by default. We reset it back to FRAME_TYPE_DEFAULT to ensure that we |
| // don't end up defaulting to BrowserNonClientFrameView in all cases. |
| if (base::win::IsMetroProcess()) |
| browser_frame_->set_frame_type(views::Widget::FRAME_TYPE_DEFAULT); |
| |
| views::NativeWidgetWin::FrameTypeChanged(); |
| |
| // In Windows 8 metro mode we call Show on the BrowserFrame instance to |
| // ensure that the window can be styled appropriately, i.e. no sysmenu, |
| // etc. |
| if (base::win::IsMetroProcess()) |
| Show(); |
| } |
| |
| void BrowserFrameWin::SetFullscreen(bool fullscreen) { |
| if (base::win::IsMetroProcess()) { |
| HMODULE metro = base::win::GetMetroModule(); |
| if (metro) { |
| MetroSetFullscreen set_full_screen = reinterpret_cast<MetroSetFullscreen>( |
| ::GetProcAddress(metro, "SetFullscreen")); |
| DCHECK(set_full_screen); |
| if (set_full_screen) |
| set_full_screen(fullscreen); |
| } else { |
| NOTREACHED() << "Failed to get metro driver module"; |
| } |
| } |
| views::NativeWidgetWin::SetFullscreen(fullscreen); |
| } |
| |
| void BrowserFrameWin::Activate() { |
| // In Windows 8 metro mode we have only one window visible at any given time. |
| // The Activate code path is typically called when a new browser window is |
| // being activated. In metro we need to ensure that the window currently |
| // being displayed is hidden and the new window being activated becomes |
| // visible. This is achieved by calling Show. |
| if (base::win::IsMetroProcess()) { |
| Show(); |
| } else { |
| views::NativeWidgetWin::Activate(); |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // BrowserFrameWin, NativeBrowserFrame implementation: |
| |
| views::NativeWidget* BrowserFrameWin::AsNativeWidget() { |
| return this; |
| } |
| |
| const views::NativeWidget* BrowserFrameWin::AsNativeWidget() const { |
| return this; |
| } |
| |
| void BrowserFrameWin::InitSystemContextMenu() { |
| system_menu_contents_.reset(new SystemMenuModel(system_menu_delegate_.get())); |
| // We add the menu items in reverse order so that insertion_index never needs |
| // to change. |
| if (browser_view_->IsBrowserTypeNormal()) |
| BuildSystemMenuForBrowserWindow(); |
| else |
| BuildSystemMenuForAppOrPopupWindow(); |
| system_menu_.reset( |
| new views::NativeMenuWin(system_menu_contents_.get(), GetNativeWindow())); |
| system_menu_->Rebuild(); |
| } |
| |
| int BrowserFrameWin::GetMinimizeButtonOffset() const { |
| int minimize_button_offset = |
| GetMinimizeButtonOffsetForWindow(GetNativeView()); |
| |
| if (minimize_button_offset > 0) |
| return minimize_button_offset; |
| |
| // If we fail to get the minimize button offset via the WM_GETTITLEBARINFOEX |
| // message then calculate and return this via the |
| // cached_minimize_button_x_delta_ member value. Please see |
| // CacheMinimizeButtonDelta() for more details. |
| DCHECK(cached_minimize_button_x_delta_); |
| |
| RECT client_rect = {0}; |
| GetClientRect(GetNativeView(), &client_rect); |
| |
| if (base::i18n::IsRTL()) |
| return cached_minimize_button_x_delta_; |
| else |
| return client_rect.right - cached_minimize_button_x_delta_; |
| } |
| |
| void BrowserFrameWin::TabStripDisplayModeChanged() { |
| UpdateDWMFrame(); |
| } |
| |
| void BrowserFrameWin::ButtonPressed(views::Button* sender, |
| const ui::Event& event) { |
| HMODULE metro = base::win::GetMetroModule(); |
| if (!metro) |
| return; |
| // Tell the metro_driver to flip our window. This causes the current |
| // browser window to be hidden and the next window to be shown. |
| static FlipFrameWindows flip_window_fn = reinterpret_cast<FlipFrameWindows>( |
| ::GetProcAddress(metro, "FlipFrameWindows")); |
| if (flip_window_fn) |
| flip_window_fn(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserFrameWin, private: |
| |
| void BrowserFrameWin::UpdateDWMFrame() { |
| // For "normal" windows on Aero, we always need to reset the glass area |
| // correctly, even if we're not currently showing the native frame (e.g. |
| // because a theme is showing), so we explicitly check for that case rather |
| // than checking browser_frame_->ShouldUseNativeFrame() here. Using that here |
| // would mean we wouldn't reset the glass area to zero when moving from the |
| // native frame to an opaque frame, leading to graphical glitches behind the |
| // opaque frame. Instead, we use that function below to tell us whether the |
| // frame is currently native or opaque. |
| if (!GetWidget()->client_view() || !browser_view_->IsBrowserTypeNormal() || |
| !NativeWidgetWin::ShouldUseNativeFrame()) |
| return; |
| |
| MARGINS margins = { 0 }; |
| |
| // If the opaque frame is visible, we use the default (zero) margins. |
| // Otherwise, we need to figure out how to extend the glass in. |
| if (browser_frame_->ShouldUseNativeFrame()) { |
| // In fullscreen mode, we don't extend glass into the client area at all, |
| // because the GDI-drawn text in the web content composited over it will |
| // become semi-transparent over any glass area. |
| if (!IsMaximized() && !IsFullscreen()) { |
| margins.cxLeftWidth = kClientEdgeThickness + 1; |
| margins.cxRightWidth = kClientEdgeThickness + 1; |
| margins.cyBottomHeight = kClientEdgeThickness + 1; |
| margins.cyTopHeight = kClientEdgeThickness + 1; |
| } |
| // In maximized mode, we only have a titlebar strip of glass, no side/bottom |
| // borders. |
| if (!browser_view_->IsFullscreen()) { |
| gfx::Rect tabstrip_bounds( |
| browser_frame_->GetBoundsForTabStrip(browser_view_->tabstrip())); |
| margins.cyTopHeight = tabstrip_bounds.bottom() + kDWMFrameTopOffset; |
| } |
| } |
| |
| DwmExtendFrameIntoClientArea(GetNativeView(), &margins); |
| } |
| |
| void BrowserFrameWin::BuildSystemMenuForBrowserWindow() { |
| system_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); |
| |
| if (chrome::CanOpenTaskManager()) { |
| system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER, |
| IDS_TASK_MANAGER); |
| } |
| system_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); |
| system_menu_contents_->AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); |
| system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB); |
| AddFrameToggleItems(); |
| // If it's a regular browser window with tabs, we don't add any more items, |
| // since it already has menus (Page, Chrome). |
| } |
| |
| void BrowserFrameWin::BuildSystemMenuForAppOrPopupWindow() { |
| Browser* browser = browser_view()->browser(); |
| if (browser->is_app() && chrome::CanOpenTaskManager()) { |
| system_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); |
| system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER, |
| IDS_TASK_MANAGER); |
| } |
| system_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); |
| encoding_menu_contents_.reset(new EncodingMenuModel(browser)); |
| system_menu_contents_->AddSubMenuWithStringId(IDC_ENCODING_MENU, |
| IDS_ENCODING_MENU, |
| encoding_menu_contents_.get()); |
| zoom_menu_contents_.reset(new ZoomMenuModel(system_menu_delegate_.get())); |
| 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(ui::NORMAL_SEPARATOR); |
| 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(ui::NORMAL_SEPARATOR); |
| if (browser->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_->AddSeparator(ui::NORMAL_SEPARATOR); |
| 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); |
| AddFrameToggleItems(); |
| } |
| |
| void BrowserFrameWin::AddFrameToggleItems() { |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDebugEnableFrameToggle)) { |
| system_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); |
| system_menu_contents_->AddItem(IDC_DEBUG_FRAME_TOGGLE, |
| L"Toggle Frame Type"); |
| } |
| } |
| |
| void BrowserFrameWin::HandleMetroNavSearchRequest(WPARAM w_param, |
| LPARAM l_param) { |
| if (!base::win::IsMetroProcess()) { |
| NOTREACHED() << "Received unexpected metro navigation request"; |
| return; |
| } |
| |
| if (!w_param && !l_param) { |
| NOTREACHED() << "Invalid metro request parameters"; |
| return; |
| } |
| |
| Browser* browser = browser_view()->browser(); |
| DCHECK(browser); |
| |
| GURL request_url; |
| |
| if (w_param) { |
| const wchar_t* url = reinterpret_cast<const wchar_t*>(w_param); |
| request_url = GURL(url); |
| } else if (l_param) { |
| const wchar_t* search_string = |
| reinterpret_cast<const wchar_t*>(l_param); |
| const TemplateURL* default_provider = |
| TemplateURLServiceFactory::GetForProfile(browser->profile())-> |
| GetDefaultSearchProvider(); |
| if (default_provider) { |
| const TemplateURLRef& search_url = default_provider->url_ref(); |
| DCHECK(search_url.SupportsReplacement()); |
| request_url = GURL(search_url.ReplaceSearchTerms( |
| TemplateURLRef::SearchTermsArgs(search_string))); |
| } |
| } |
| if (request_url.is_valid()) { |
| browser->OpenURL(OpenURLParams(request_url, Referrer(), NEW_FOREGROUND_TAB, |
| content::PAGE_TRANSITION_TYPED, false)); |
| } |
| } |
| |
| void BrowserFrameWin::GetMetroCurrentTabInfo(WPARAM w_param) { |
| if (!base::win::IsMetroProcess()) { |
| NOTREACHED() << "Received unexpected metro request"; |
| return; |
| } |
| |
| if (!w_param) { |
| NOTREACHED() << "Invalid metro request parameter"; |
| return; |
| } |
| |
| base::win::CurrentTabInfo* current_tab_info = |
| reinterpret_cast<base::win::CurrentTabInfo*>(w_param); |
| |
| Browser* browser = browser_view()->browser(); |
| DCHECK(browser); |
| |
| // We allocate memory for the title and url via LocalAlloc. The caller has to |
| // free the memory via LocalFree. |
| current_tab_info->title = base::win::LocalAllocAndCopyString( |
| browser->GetWindowTitleForCurrentTab()); |
| |
| WebContents* current_tab = chrome::GetActiveWebContents(browser); |
| DCHECK(current_tab); |
| |
| current_tab_info->url = base::win::LocalAllocAndCopyString( |
| UTF8ToWide(current_tab->GetURL().spec())); |
| } |
| |
| void BrowserFrameWin::CacheMinimizeButtonDelta() { |
| int minimize_offset = GetMinimizeButtonOffsetForWindow(GetNativeView()); |
| if (!minimize_offset) |
| return; |
| |
| RECT rect = {0}; |
| GetClientRect(GetNativeView(), &rect); |
| // Calculate and cache the value of the minimize button delta, i.e. the |
| // offset to be applied to the left or right edge of the client rect |
| // depending on whether the language is RTL or not. |
| // This cached value is only used if the WM_GETTITLEBARINFOEX message fails |
| // to get the offset of the minimize button. |
| if (base::i18n::IsRTL()) |
| cached_minimize_button_x_delta_ = minimize_offset; |
| else |
| cached_minimize_button_x_delta_ = rect.right - minimize_offset; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // BrowserFrame, public: |
| |
| // static |
| const gfx::Font& BrowserFrame::GetTitleFont() { |
| static gfx::Font* title_font = |
| new gfx::Font(views::NativeWidgetWin::GetWindowTitleFont()); |
| return *title_font; |
| } |
| |
| bool BrowserFrame::ShouldLeaveOffsetNearTopBorder() { |
| if (base::win::IsMetroProcess()) { |
| if (ui::GetDisplayLayout() == ui::LAYOUT_DESKTOP) |
| return false; |
| } |
| return !IsMaximized(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeBrowserFrame, public: |
| |
| // static |
| NativeBrowserFrame* NativeBrowserFrame::CreateNativeBrowserFrame( |
| BrowserFrame* browser_frame, |
| BrowserView* browser_view) { |
| return new BrowserFrameWin(browser_frame, browser_view); |
| } |