Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / frame / browser_desktop_window_tree_host_win.cc
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.
4
5 #include "chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h"
6
7 #include <dwmapi.h>
8
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"
23
24 #pragma comment(lib, "dwmapi.lib")
25
26 namespace {
27
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;
32
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) {
40   }
41
42   virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE {
43     return delegate_->GetImageSkiaNamed(
44         chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
45   }
46   virtual SkColor GetColor(int id) const OVERRIDE {
47     return delegate_->GetColor(id);
48   }
49   virtual int GetDisplayProperty(int id) const OVERRIDE {
50     return delegate_->GetDisplayProperty(id);
51   }
52   virtual bool ShouldUseNativeFrame() const OVERRIDE {
53     return delegate_->ShouldUseNativeFrame();
54   }
55   virtual bool HasCustomImage(int id) const OVERRIDE {
56     return delegate_->HasCustomImage(
57         chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
58
59   }
60   virtual base::RefCountedMemory* GetRawData(
61       int id,
62       ui::ScaleFactor scale_factor) const OVERRIDE {
63     return delegate_->GetRawData(id, scale_factor);
64   }
65
66  private:
67   ui::ThemeProvider* delegate_;
68
69   DISALLOW_COPY_AND_ASSIGN(DesktopThemeProvider);
70 };
71
72 }  // namespace
73
74 ////////////////////////////////////////////////////////////////////////////////
75 // BrowserDesktopWindowTreeHostWin, public:
76
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());
91 }
92
93 BrowserDesktopWindowTreeHostWin::~BrowserDesktopWindowTreeHostWin() {
94 }
95
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);
103   }
104   return system_menu_.get();
105 }
106
107 ////////////////////////////////////////////////////////////////////////////////
108 // BrowserDesktopWindowTreeHostWin, BrowserDesktopWindowTreeHost implementation:
109
110 views::DesktopWindowTreeHost*
111     BrowserDesktopWindowTreeHostWin::AsDesktopWindowTreeHost() {
112   return this;
113 }
114
115 int BrowserDesktopWindowTreeHostWin::GetMinimizeButtonOffset() const {
116   return minimize_button_metrics_.GetMinimizeButtonOffsetX();
117 }
118
119 bool BrowserDesktopWindowTreeHostWin::UsesNativeSystemMenu() const {
120   return true;
121 }
122
123 ////////////////////////////////////////////////////////////////////////////////
124 // BrowserDesktopWindowTreeHostWin, views::DesktopWindowTreeHostWin overrides:
125
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;
132 }
133
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;
141   }
142
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;
152 }
153
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());
161 }
162
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();
167
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();
172 }
173
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;
189   }
190   return DesktopWindowTreeHostWin::PreHandleMSG(
191       message, w_param, l_param, result);
192 }
193
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();
203
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();
219     }
220     break;
221   }
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;
236     }
237     break;
238   }
239 }
240
241
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;
249   }
250
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();
254 }
255
256 bool BrowserDesktopWindowTreeHostWin::ShouldUseNativeFrame() const {
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());
265 }
266
267 void BrowserDesktopWindowTreeHostWin::FrameTypeChanged() {
268   views::DesktopWindowTreeHostWin::FrameTypeChanged();
269   did_gdi_clear_ = false;
270 }
271
272 ////////////////////////////////////////////////////////////////////////////////
273 // BrowserDesktopWindowTreeHostWin, private:
274
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;
287
288   MARGINS margins = GetDWMFrameMargins();
289
290   DwmExtendFrameIntoClientArea(GetHWND(), &margins);
291 }
292
293 MARGINS BrowserDesktopWindowTreeHostWin::GetDWMFrameMargins() const {
294   MARGINS margins = { 0 };
295
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;
307     }
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;
315     }
316   }
317   return margins;
318 }
319
320 ////////////////////////////////////////////////////////////////////////////////
321 // BrowserDesktopWindowTreeHost, public:
322
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);
334 }