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