browser_frame_win.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/views/frame/browser_frame_win.h" 6 7#include <dwmapi.h> 8#include <shellapi.h> 9 10#include <set> 11 12#include "app/win/hwnd_util.h" 13#include "app/win/win_util.h" 14#include "chrome/browser/accessibility/browser_accessibility_state.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/browser_list.h" 17#include "chrome/browser/themes/browser_theme_provider.h" 18#include "chrome/browser/views/frame/browser_non_client_frame_view.h" 19#include "chrome/browser/views/frame/browser_root_view.h" 20#include "chrome/browser/views/frame/browser_view.h" 21#include "chrome/browser/views/frame/glass_browser_frame_view.h" 22#include "gfx/font.h" 23#include "grit/theme_resources.h" 24#include "views/screen.h" 25#include "views/window/window_delegate.h" 26 27// static 28static const int kClientEdgeThickness = 3; 29static const int kTabDragWindowAlpha = 200; 30// We need to offset the DWMFrame into the toolbar so that the blackness 31// doesn't show up on our rounded corners. 32static const int kDWMFrameTopOffset = 3; 33 34// static (Factory method.) 35BrowserFrame* BrowserFrame::Create(BrowserView* browser_view, 36 Profile* profile) { 37 BrowserFrameWin* frame = new BrowserFrameWin(browser_view, profile); 38 frame->Init(); 39 return frame; 40} 41 42// static 43const gfx::Font& BrowserFrame::GetTitleFont() { 44 static gfx::Font* title_font = new gfx::Font(app::win::GetWindowTitleFont()); 45 return *title_font; 46} 47 48/////////////////////////////////////////////////////////////////////////////// 49// BrowserFrame, public: 50 51BrowserFrameWin::BrowserFrameWin(BrowserView* browser_view, Profile* profile) 52 : WindowWin(browser_view), 53 browser_view_(browser_view), 54 root_view_(NULL), 55 frame_initialized_(false), 56 profile_(profile) { 57 browser_view_->set_frame(this); 58 GetNonClientView()->SetFrameView(CreateFrameViewForWindow()); 59 // Don't focus anything on creation, selecting a tab will set the focus. 60 set_focus_on_creation(false); 61} 62 63void BrowserFrameWin::Init() { 64 WindowWin::Init(NULL, gfx::Rect()); 65} 66 67BrowserFrameWin::~BrowserFrameWin() { 68} 69 70views::Window* BrowserFrameWin::GetWindow() { 71 return this; 72} 73 74int BrowserFrameWin::GetMinimizeButtonOffset() const { 75 TITLEBARINFOEX titlebar_info; 76 titlebar_info.cbSize = sizeof(TITLEBARINFOEX); 77 SendMessage(GetNativeView(), WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info); 78 79 CPoint minimize_button_corner(titlebar_info.rgrect[2].left, 80 titlebar_info.rgrect[2].top); 81 MapWindowPoints(HWND_DESKTOP, GetNativeView(), &minimize_button_corner, 1); 82 83 return minimize_button_corner.x; 84} 85 86gfx::Rect BrowserFrameWin::GetBoundsForTabStrip(BaseTabStrip* tabstrip) const { 87 return browser_frame_view_->GetBoundsForTabStrip(tabstrip); 88} 89 90int BrowserFrameWin::GetHorizontalTabStripVerticalOffset(bool restored) const { 91 return browser_frame_view_->GetHorizontalTabStripVerticalOffset(restored); 92} 93 94void BrowserFrameWin::UpdateThrobber(bool running) { 95 browser_frame_view_->UpdateThrobber(running); 96} 97 98ThemeProvider* BrowserFrameWin::GetThemeProviderForFrame() const { 99 // This is implemented for a different interface than GetThemeProvider is, 100 // but they mean the same things. 101 return GetThemeProvider(); 102} 103 104bool BrowserFrameWin::AlwaysUseNativeFrame() const { 105 // App panel windows draw their own frame. 106 if (browser_view_->IsBrowserTypePanel()) 107 return false; 108 109 // We don't theme popup or app windows, so regardless of whether or not a 110 // theme is active for normal browser windows, we don't want to use the custom 111 // frame for popups/apps. 112 if (!browser_view_->IsBrowserTypeNormal() && app::win::ShouldUseVistaFrame()) 113 return true; 114 115 // Otherwise, we use the native frame when we're told we should by the theme 116 // provider (e.g. no custom theme is active). 117 return GetThemeProvider()->ShouldUseNativeFrame(); 118} 119 120views::View* BrowserFrameWin::GetFrameView() const { 121 return browser_frame_view_; 122} 123 124void BrowserFrameWin::TabStripDisplayModeChanged() { 125 if (GetRootView()->GetChildViewCount() > 0) { 126 // Make sure the child of the root view gets Layout again. 127 GetRootView()->GetChildViewAt(0)->InvalidateLayout(); 128 } 129 GetRootView()->Layout(); 130 131 UpdateDWMFrame(); 132} 133 134/////////////////////////////////////////////////////////////////////////////// 135// BrowserFrame, views::WindowWin overrides: 136 137gfx::Insets BrowserFrameWin::GetClientAreaInsets() const { 138 // Use the default client insets for an opaque frame or a glass popup/app 139 // frame. 140 if (!GetNonClientView()->UseNativeFrame() || 141 !browser_view_->IsBrowserTypeNormal()) { 142 return WindowWin::GetClientAreaInsets(); 143 } 144 145 int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); 146 // In fullscreen mode, we have no frame. In restored mode, we draw our own 147 // client edge over part of the default frame. 148 if (IsFullscreen()) 149 border_thickness = 0; 150 else if (!IsMaximized()) 151 border_thickness -= kClientEdgeThickness; 152 return gfx::Insets(0, border_thickness, border_thickness, border_thickness); 153} 154 155bool BrowserFrameWin::GetAccelerator(int cmd_id, 156 menus::Accelerator* accelerator) { 157 return browser_view_->GetAccelerator(cmd_id, accelerator); 158} 159 160void BrowserFrameWin::OnEndSession(BOOL ending, UINT logoff) { 161 BrowserList::SessionEnding(); 162} 163 164void BrowserFrameWin::OnEnterSizeMove() { 165 browser_view_->WindowMoveOrResizeStarted(); 166} 167 168void BrowserFrameWin::OnExitSizeMove() { 169 WidgetWin::OnExitSizeMove(); 170} 171 172void BrowserFrameWin::OnInitMenuPopup(HMENU menu, UINT position, 173 BOOL is_system_menu) { 174 browser_view_->PrepareToRunSystemMenu(menu); 175} 176 177LRESULT BrowserFrameWin::OnMouseActivate(HWND window, UINT hittest_code, 178 UINT message) { 179 return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT 180 : MA_ACTIVATE; 181} 182 183void BrowserFrameWin::OnMove(const CPoint& point) { 184 browser_view_->WindowMoved(); 185} 186 187void BrowserFrameWin::OnMoving(UINT param, LPRECT new_bounds) { 188 browser_view_->WindowMoved(); 189} 190 191LRESULT BrowserFrameWin::OnNCActivate(BOOL active) { 192 if (browser_view_->ActivateAppModalDialog()) 193 return TRUE; 194 195 browser_view_->ActivationChanged(!!active); 196 return WindowWin::OnNCActivate(active); 197} 198 199LRESULT BrowserFrameWin::OnNCHitTest(const CPoint& pt) { 200 // Only do DWM hit-testing when we are using the native frame. 201 if (GetNonClientView()->UseNativeFrame()) { 202 LRESULT result; 203 if (DwmDefWindowProc(GetNativeView(), WM_NCHITTEST, 0, 204 MAKELPARAM(pt.x, pt.y), &result)) { 205 return result; 206 } 207 } 208 return WindowWin::OnNCHitTest(pt); 209} 210 211void BrowserFrameWin::OnWindowPosChanged(WINDOWPOS* window_pos) { 212 WindowWin::OnWindowPosChanged(window_pos); 213 UpdateDWMFrame(); 214 215 // Windows lies to us about the position of the minimize button before a 216 // window is visible. We use this position to place the OTR avatar in RTL 217 // mode, so when the window is shown, we need to re-layout and schedule a 218 // paint for the non-client frame view so that the icon top has the correct 219 // position when the window becomes visible. This fixes bugs where the icon 220 // appears to overlay the minimize button. 221 // Note that we will call Layout every time SetWindowPos is called with 222 // SWP_SHOWWINDOW, however callers typically are careful about not specifying 223 // this flag unless necessary to avoid flicker. 224 if (window_pos->flags & SWP_SHOWWINDOW) { 225 GetNonClientView()->Layout(); 226 GetNonClientView()->SchedulePaint(); 227 } 228} 229 230ThemeProvider* BrowserFrameWin::GetThemeProvider() const { 231 return profile_->GetThemeProvider(); 232} 233 234ThemeProvider* BrowserFrameWin::GetDefaultThemeProvider() const { 235 return profile_->GetThemeProvider(); 236} 237 238void BrowserFrameWin::OnScreenReaderDetected() { 239 BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected(); 240 WindowWin::OnScreenReaderDetected(); 241} 242 243/////////////////////////////////////////////////////////////////////////////// 244// BrowserFrame, views::CustomFrameWindow overrides: 245 246int BrowserFrameWin::GetShowState() const { 247 return browser_view_->GetShowState(); 248} 249 250void BrowserFrameWin::Activate() { 251 // When running under remote desktop, if the remote desktop client is not 252 // active on the users desktop, then none of the windows contained in the 253 // remote desktop will be activated. However, WindowWin::Activate will still 254 // bring this browser window to the foreground. We explicitly set ourselves 255 // as the last active browser window to ensure that we get treated as such by 256 // the rest of Chrome. 257 BrowserList::SetLastActive(browser_view_->browser()); 258 259 WindowWin::Activate(); 260} 261 262views::NonClientFrameView* BrowserFrameWin::CreateFrameViewForWindow() { 263 if (AlwaysUseNativeFrame()) 264 browser_frame_view_ = new GlassBrowserFrameView(this, browser_view_); 265 else 266 browser_frame_view_ = 267 browser::CreateBrowserNonClientFrameView(this, browser_view_); 268 return browser_frame_view_; 269} 270 271void BrowserFrameWin::UpdateFrameAfterFrameChange() { 272 // We need to update the glass region on or off before the base class adjusts 273 // the window region. 274 UpdateDWMFrame(); 275 WindowWin::UpdateFrameAfterFrameChange(); 276} 277 278views::RootView* BrowserFrameWin::CreateRootView() { 279 root_view_ = new BrowserRootView(browser_view_, this); 280 return root_view_; 281} 282 283/////////////////////////////////////////////////////////////////////////////// 284// BrowserFrame, private: 285 286void BrowserFrameWin::UpdateDWMFrame() { 287 // Nothing to do yet, or we're not showing a DWM frame. 288 if (!GetClientView() || !AlwaysUseNativeFrame()) 289 return; 290 291 MARGINS margins = { 0 }; 292 if (browser_view_->IsBrowserTypeNormal()) { 293 // In fullscreen mode, we don't extend glass into the client area at all, 294 // because the GDI-drawn text in the web content composited over it will 295 // become semi-transparent over any glass area. 296 if (!IsMaximized() && !IsFullscreen()) { 297 margins.cxLeftWidth = kClientEdgeThickness + 1; 298 margins.cxRightWidth = kClientEdgeThickness + 1; 299 margins.cyBottomHeight = kClientEdgeThickness + 1; 300 margins.cyTopHeight = kClientEdgeThickness + 1; 301 } 302 // In maximized mode, we only have a titlebar strip of glass, no side/bottom 303 // borders. 304 if (!browser_view_->IsFullscreen()) { 305 gfx::Rect tabstrip_bounds( 306 GetBoundsForTabStrip(browser_view_->tabstrip())); 307 margins.cyTopHeight = (browser_view_->UseVerticalTabs() ? 308 tabstrip_bounds.y() : tabstrip_bounds.bottom()) + kDWMFrameTopOffset; 309 } 310 } else { 311 // For popup and app windows we want to use the default margins. 312 } 313 DwmExtendFrameIntoClientArea(GetNativeView(), &margins); 314} 315