Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / views / frame / browser_desktop_root_window_host_win.cc
blob43375ae3b5cf43679c2fb54916d5c9b26c1920e9
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h"
7 #include <dwmapi.h>
9 #include "chrome/browser/lifetime/application_lifetime.h"
10 #include "chrome/browser/themes/theme_service.h"
11 #include "chrome/browser/themes/theme_service_factory.h"
12 #include "chrome/browser/ui/views/frame/browser_frame.h"
13 #include "chrome/browser/ui/views/frame/browser_frame_common_win.h"
14 #include "chrome/browser/ui/views/frame/browser_view.h"
15 #include "chrome/browser/ui/views/frame/browser_window_property_manager_win.h"
16 #include "chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h"
17 #include "chrome/browser/ui/views/tabs/tab_strip.h"
18 #include "chrome/browser/ui/views/theme_image_mapper.h"
19 #include "grit/theme_resources.h"
20 #include "ui/base/theme_provider.h"
21 #include "ui/gfx/win/dpi.h"
22 #include "ui/views/controls/menu/native_menu_win.h"
24 #pragma comment(lib, "dwmapi.lib")
26 namespace {
28 const int kClientEdgeThickness = 3;
29 // We need to offset the DWMFrame into the toolbar so that the blackness
30 // doesn't show up on our rounded corners.
31 const int kDWMFrameTopOffset = 3;
33 // DesktopThemeProvider maps resource ids using MapThemeImage(). This is
34 // necessary for BrowserDesktopWindowTreeHostWin so that it uses the windows
35 // theme images rather than the ash theme images.
36 class DesktopThemeProvider : public ui::ThemeProvider {
37 public:
38 explicit DesktopThemeProvider(ui::ThemeProvider* delegate)
39 : delegate_(delegate) {
42 virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE {
43 return delegate_->GetImageSkiaNamed(
44 chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
46 virtual SkColor GetColor(int id) const OVERRIDE {
47 return delegate_->GetColor(id);
49 virtual int GetDisplayProperty(int id) const OVERRIDE {
50 return delegate_->GetDisplayProperty(id);
52 virtual bool ShouldUseNativeFrame() const OVERRIDE {
53 return delegate_->ShouldUseNativeFrame();
55 virtual bool HasCustomImage(int id) const OVERRIDE {
56 return delegate_->HasCustomImage(
57 chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
60 virtual base::RefCountedMemory* GetRawData(
61 int id,
62 ui::ScaleFactor scale_factor) const OVERRIDE {
63 return delegate_->GetRawData(id, scale_factor);
66 private:
67 ui::ThemeProvider* delegate_;
69 DISALLOW_COPY_AND_ASSIGN(DesktopThemeProvider);
72 } // namespace
74 ////////////////////////////////////////////////////////////////////////////////
75 // BrowserDesktopWindowTreeHostWin, public:
77 BrowserDesktopWindowTreeHostWin::BrowserDesktopWindowTreeHostWin(
78 views::internal::NativeWidgetDelegate* native_widget_delegate,
79 views::DesktopNativeWidgetAura* desktop_native_widget_aura,
80 BrowserView* browser_view,
81 BrowserFrame* browser_frame)
82 : DesktopWindowTreeHostWin(native_widget_delegate,
83 desktop_native_widget_aura),
84 browser_view_(browser_view),
85 browser_frame_(browser_frame),
86 did_gdi_clear_(false) {
87 scoped_ptr<ui::ThemeProvider> theme_provider(
88 new DesktopThemeProvider(ThemeServiceFactory::GetForProfile(
89 browser_view->browser()->profile())));
90 browser_frame->SetThemeProvider(theme_provider.Pass());
93 BrowserDesktopWindowTreeHostWin::~BrowserDesktopWindowTreeHostWin() {
96 views::NativeMenuWin* BrowserDesktopWindowTreeHostWin::GetSystemMenu() {
97 if (!system_menu_.get()) {
98 SystemMenuInsertionDelegateWin insertion_delegate;
99 system_menu_.reset(
100 new views::NativeMenuWin(browser_frame_->GetSystemMenuModel(),
101 GetHWND()));
102 system_menu_->Rebuild(&insertion_delegate);
104 return system_menu_.get();
107 ////////////////////////////////////////////////////////////////////////////////
108 // BrowserDesktopWindowTreeHostWin, BrowserDesktopWindowTreeHost implementation:
110 views::DesktopWindowTreeHost*
111 BrowserDesktopWindowTreeHostWin::AsDesktopWindowTreeHost() {
112 return this;
115 int BrowserDesktopWindowTreeHostWin::GetMinimizeButtonOffset() const {
116 return minimize_button_metrics_.GetMinimizeButtonOffsetX();
119 bool BrowserDesktopWindowTreeHostWin::UsesNativeSystemMenu() const {
120 return true;
123 ////////////////////////////////////////////////////////////////////////////////
124 // BrowserDesktopWindowTreeHostWin, views::DesktopWindowTreeHostWin overrides:
126 int BrowserDesktopWindowTreeHostWin::GetInitialShowState() const {
127 STARTUPINFO si = {0};
128 si.cb = sizeof(si);
129 si.dwFlags = STARTF_USESHOWWINDOW;
130 GetStartupInfo(&si);
131 return si.wShowWindow;
134 bool BrowserDesktopWindowTreeHostWin::GetClientAreaInsets(
135 gfx::Insets* insets) const {
136 // Use the default client insets for an opaque frame or a glass popup/app
137 // frame.
138 if (!GetWidget()->ShouldUseNativeFrame() ||
139 !browser_view_->IsBrowserTypeNormal()) {
140 return false;
143 int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
144 // In fullscreen mode, we have no frame. In restored mode, we draw our own
145 // client edge over part of the default frame.
146 if (GetWidget()->IsFullscreen())
147 border_thickness = 0;
148 else if (!IsMaximized())
149 border_thickness -= kClientEdgeThickness;
150 insets->Set(0, border_thickness, border_thickness, border_thickness);
151 return true;
154 void BrowserDesktopWindowTreeHostWin::HandleCreate() {
155 DesktopWindowTreeHostWin::HandleCreate();
156 browser_window_property_manager_ =
157 BrowserWindowPropertyManager::CreateBrowserWindowPropertyManager(
158 browser_view_);
159 if (browser_window_property_manager_)
160 browser_window_property_manager_->UpdateWindowProperties(GetHWND());
163 void BrowserDesktopWindowTreeHostWin::HandleFrameChanged() {
164 // Reinitialize the status bubble, since it needs to be initialized
165 // differently depending on whether or not DWM composition is enabled
166 browser_view_->InitStatusBubble();
168 // We need to update the glass region on or off before the base class adjusts
169 // the window region.
170 UpdateDWMFrame();
171 DesktopWindowTreeHostWin::HandleFrameChanged();
174 bool BrowserDesktopWindowTreeHostWin::PreHandleMSG(UINT message,
175 WPARAM w_param,
176 LPARAM l_param,
177 LRESULT* result) {
178 switch (message) {
179 case WM_ACTIVATE:
180 if (LOWORD(w_param) != WA_INACTIVE)
181 minimize_button_metrics_.OnHWNDActivated();
182 return false;
183 case WM_ENDSESSION:
184 chrome::SessionEnding();
185 return true;
186 case WM_INITMENUPOPUP:
187 GetSystemMenu()->UpdateStates();
188 return true;
190 return DesktopWindowTreeHostWin::PreHandleMSG(
191 message, w_param, l_param, result);
194 void BrowserDesktopWindowTreeHostWin::PostHandleMSG(UINT message,
195 WPARAM w_param,
196 LPARAM l_param) {
197 switch (message) {
198 case WM_CREATE:
199 minimize_button_metrics_.Init(GetHWND());
200 break;
201 case WM_WINDOWPOSCHANGED: {
202 UpdateDWMFrame();
204 // Windows lies to us about the position of the minimize button before a
205 // window is visible. We use this position to place the OTR avatar in RTL
206 // mode, so when the window is shown, we need to re-layout and schedule a
207 // paint for the non-client frame view so that the icon top has the correct
208 // position when the window becomes visible. This fixes bugs where the icon
209 // appears to overlay the minimize button.
210 // Note that we will call Layout every time SetWindowPos is called with
211 // SWP_SHOWWINDOW, however callers typically are careful about not
212 // specifying this flag unless necessary to avoid flicker.
213 // This may be invoked during creation on XP and before the non_client_view
214 // has been created.
215 WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(l_param);
216 if (window_pos->flags & SWP_SHOWWINDOW && GetWidget()->non_client_view()) {
217 GetWidget()->non_client_view()->Layout();
218 GetWidget()->non_client_view()->SchedulePaint();
220 break;
222 case WM_ERASEBKGND:
223 if (!did_gdi_clear_ && DesktopWindowTreeHostWin::ShouldUseNativeFrame()) {
224 // This is necessary to avoid white flashing in the titlebar area around
225 // the minimize/maximize/close buttons.
226 HDC dc = GetDC(GetHWND());
227 MARGINS margins = GetDWMFrameMargins();
228 RECT client_rect;
229 GetClientRect(GetHWND(), &client_rect);
230 HBRUSH brush = CreateSolidBrush(0);
231 RECT rect = { 0, 0, client_rect.right, margins.cyTopHeight };
232 FillRect(dc, &rect, brush);
233 DeleteObject(brush);
234 ReleaseDC(GetHWND(), dc);
235 did_gdi_clear_ = true;
237 break;
242 bool BrowserDesktopWindowTreeHostWin::IsUsingCustomFrame() const {
243 // We don't theme popup or app windows, so regardless of whether or not a
244 // theme is active for normal browser windows, we don't want to use the custom
245 // frame for popups/apps.
246 if (!browser_view_->IsBrowserTypeNormal() &&
247 !DesktopWindowTreeHostWin::IsUsingCustomFrame()) {
248 return false;
251 // Otherwise, we use the native frame when we're told we should by the theme
252 // provider (e.g. no custom theme is active).
253 return !GetWidget()->GetThemeProvider()->ShouldUseNativeFrame();
256 bool BrowserDesktopWindowTreeHostWin::ShouldUseNativeFrame() {
257 if (!views::DesktopWindowTreeHostWin::ShouldUseNativeFrame())
258 return false;
259 // This function can get called when the Browser window is closed i.e. in the
260 // context of the BrowserView destructor.
261 if (!browser_view_->browser())
262 return false;
263 return chrome::ShouldUseNativeFrame(browser_view_,
264 GetWidget()->GetThemeProvider());
267 void BrowserDesktopWindowTreeHostWin::FrameTypeChanged() {
268 views::DesktopWindowTreeHostWin::FrameTypeChanged();
269 did_gdi_clear_ = false;
272 ////////////////////////////////////////////////////////////////////////////////
273 // BrowserDesktopWindowTreeHostWin, private:
275 void BrowserDesktopWindowTreeHostWin::UpdateDWMFrame() {
276 // For "normal" windows on Aero, we always need to reset the glass area
277 // correctly, even if we're not currently showing the native frame (e.g.
278 // because a theme is showing), so we explicitly check for that case rather
279 // than checking browser_frame_->ShouldUseNativeFrame() here. Using that here
280 // would mean we wouldn't reset the glass area to zero when moving from the
281 // native frame to an opaque frame, leading to graphical glitches behind the
282 // opaque frame. Instead, we use that function below to tell us whether the
283 // frame is currently native or opaque.
284 if (!GetWidget()->client_view() || !browser_view_->IsBrowserTypeNormal() ||
285 !DesktopWindowTreeHostWin::ShouldUseNativeFrame())
286 return;
288 MARGINS margins = GetDWMFrameMargins();
290 DwmExtendFrameIntoClientArea(GetHWND(), &margins);
293 MARGINS BrowserDesktopWindowTreeHostWin::GetDWMFrameMargins() const {
294 MARGINS margins = { 0 };
296 // If the opaque frame is visible, we use the default (zero) margins.
297 // Otherwise, we need to figure out how to extend the glass in.
298 if (GetWidget()->ShouldUseNativeFrame()) {
299 // In fullscreen mode, we don't extend glass into the client area at all,
300 // because the GDI-drawn text in the web content composited over it will
301 // become semi-transparent over any glass area.
302 if (!IsMaximized() && !GetWidget()->IsFullscreen()) {
303 margins.cxLeftWidth = kClientEdgeThickness + 1;
304 margins.cxRightWidth = kClientEdgeThickness + 1;
305 margins.cyBottomHeight = kClientEdgeThickness + 1;
306 margins.cyTopHeight = kClientEdgeThickness + 1;
308 // In maximized mode, we only have a titlebar strip of glass, no side/bottom
309 // borders.
310 if (!browser_view_->IsFullscreen()) {
311 gfx::Rect tabstrip_bounds(
312 browser_frame_->GetBoundsForTabStrip(browser_view_->tabstrip()));
313 tabstrip_bounds = gfx::win::DIPToScreenRect(tabstrip_bounds);
314 margins.cyTopHeight = tabstrip_bounds.bottom() + kDWMFrameTopOffset;
317 return margins;
320 ////////////////////////////////////////////////////////////////////////////////
321 // BrowserDesktopWindowTreeHost, public:
323 // static
324 BrowserDesktopWindowTreeHost*
325 BrowserDesktopWindowTreeHost::CreateBrowserDesktopWindowTreeHost(
326 views::internal::NativeWidgetDelegate* native_widget_delegate,
327 views::DesktopNativeWidgetAura* desktop_native_widget_aura,
328 BrowserView* browser_view,
329 BrowserFrame* browser_frame) {
330 return new BrowserDesktopWindowTreeHostWin(native_widget_delegate,
331 desktop_native_widget_aura,
332 browser_view,
333 browser_frame);