• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.)
Create(BrowserView * browser_view,Profile * profile)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 
BrowserFrameWin(BrowserView * browser_view,Profile * profile)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 
~BrowserFrameWin()59 BrowserFrameWin::~BrowserFrameWin() {
60 }
61 
InitBrowserFrame()62 void BrowserFrameWin::InitBrowserFrame() {
63   WindowWin::Init(NULL, gfx::Rect());
64 }
65 
66 // static
SetShowState(int state)67 void BrowserFrameWin::SetShowState(int state) {
68   explicit_show_state = state;
69 }
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 // BrowserFrameWin, views::WindowWin overrides:
73 
GetShowState() const74 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 
GetClientAreaInsets() const85 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 
GetAccelerator(int cmd_id,ui::Accelerator * accelerator)103 bool BrowserFrameWin::GetAccelerator(int cmd_id,
104                                      ui::Accelerator* accelerator) {
105   return browser_view_->GetAccelerator(cmd_id, accelerator);
106 }
107 
OnEndSession(BOOL ending,UINT logoff)108 void BrowserFrameWin::OnEndSession(BOOL ending, UINT logoff) {
109   BrowserList::SessionEnding();
110 }
111 
OnInitMenuPopup(HMENU menu,UINT position,BOOL is_system_menu)112 void BrowserFrameWin::OnInitMenuPopup(HMENU menu, UINT position,
113                                       BOOL is_system_menu) {
114   browser_view_->PrepareToRunSystemMenu(menu);
115 }
116 
OnWindowPosChanged(WINDOWPOS * window_pos)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 
GetThemeProvider() const136 ThemeProvider* BrowserFrameWin::GetThemeProvider() const {
137   return ThemeServiceFactory::GetForProfile(
138       browser_view_->browser()->profile());
139 }
140 
OnScreenReaderDetected()141 void BrowserFrameWin::OnScreenReaderDetected() {
142   BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
143   WindowWin::OnScreenReaderDetected();
144 }
145 
146 ///////////////////////////////////////////////////////////////////////////////
147 // BrowserFrameWin, views::Window overrides:
148 
Activate()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 
UpdateFrameAfterFrameChange()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 
CreateRootView()168 views::RootView* BrowserFrameWin::CreateRootView() {
169   return delegate_->DelegateCreateRootView();
170 }
171 
CreateFrameViewForWindow()172 views::NonClientFrameView* BrowserFrameWin::CreateFrameViewForWindow() {
173   return delegate_->DelegateCreateFrameViewForWindow();
174 }
175 
ShouldUseNativeFrame() const176 bool BrowserFrameWin::ShouldUseNativeFrame() const {
177   return AlwaysUseNativeFrame();
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 // BrowserFrameWin, NativeBrowserFrame implementation:
182 
AsNativeWindow()183 views::NativeWindow* BrowserFrameWin::AsNativeWindow() {
184   return this;
185 }
186 
AsNativeWindow() const187 const views::NativeWindow* BrowserFrameWin::AsNativeWindow() const {
188   return this;
189 }
190 
CreateBrowserNonClientFrameView()191 BrowserNonClientFrameView* BrowserFrameWin::CreateBrowserNonClientFrameView() {
192   if (AlwaysUseNativeFrame())
193     return new GlassBrowserFrameView(this, browser_view_);
194   return browser::CreateBrowserNonClientFrameView(this, browser_view_);
195 }
196 
GetMinimizeButtonOffset() const197 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 
GetThemeProviderForFrame() const209 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 
AlwaysUseNativeFrame() const215 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 
TabStripDisplayModeChanged()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 
UpdateDWMFrame()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
GetTitleFont()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