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