Home | History | Annotate | Download | only in frame
      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