diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-15 19:21:57 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-15 19:21:57 +0000 |
commit | 9f36b348f2408118d42d219c8a4fa04877ed3b83 (patch) | |
tree | bc33b026905d139ad739b0c4345fc5cb97a2ed1c | |
parent | 6ef0feb87c69e28e81dd7ca0e45dc402f181619a (diff) | |
download | chromium_src-9f36b348f2408118d42d219c8a4fa04877ed3b83.zip chromium_src-9f36b348f2408118d42d219c8a4fa04877ed3b83.tar.gz chromium_src-9f36b348f2408118d42d219c8a4fa04877ed3b83.tar.bz2 |
Fix a whole category of frame switching bugs relating to the window z-order being screwed up screwed up when DWM is toggled or themes are installed or reset.
The first part of the fix was to remove the hack I put in to hide then show the window while the frame type change occurs.
The hack was to work around the fact that upon returning to glass from non-glass, the area identified by BrowserFrameWin::OnNCCalcSize as client was filled with solid black vs. transparent black.
I don't know why this fix works, but returning a client size for the opaque frame as 1 pixel different to the window rect causes the blackness bug to not occur, so that's what I did (in addition to removing the hack).
I also had to put in a couple of fixes to accommodate the pixel turd we gain in the opaque frame. I renamed ChangeSize to LayoutRootView. When we're using the opaque frame, since the views system is rendering the entire content of the window all the time I always size the widget to the window rect rather than the client rect.
http://crbug.com/15424
TEST=change the frame type by:
- turning on/off aero glass
- installing a theme, then resetting
- running an app that forces the DWM off, e.g. the O3D plugin
The frame should appear correct after the transition in either direction, and window z-order should be preserved.
Review URL: http://codereview.chromium.org/266013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29164 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/frame/browser_frame_win.cc | 43 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_frame_win.h | 1 | ||||
-rw-r--r-- | views/widget/widget_win.cc | 14 | ||||
-rw-r--r-- | views/widget/widget_win.h | 12 | ||||
-rw-r--r-- | views/window/window_win.cc | 22 |
5 files changed, 63 insertions, 29 deletions
diff --git a/chrome/browser/views/frame/browser_frame_win.cc b/chrome/browser/views/frame/browser_frame_win.cc index 4315346..2616dfb 100644 --- a/chrome/browser/views/frame/browser_frame_win.cc +++ b/chrome/browser/views/frame/browser_frame_win.cc @@ -182,12 +182,17 @@ LRESULT BrowserFrameWin::OnNCActivate(BOOL active) { } LRESULT BrowserFrameWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { - // We don't adjust the client area unless we're a tabbed browser window and - // are using the native frame. - if (!GetNonClientView()->UseNativeFrame() || - !browser_view_->IsBrowserTypeNormal()) { + // This class' client rect calculations are specific to the tabbed browser + // window. When the glass frame is active, the client area is reported to be + // a rectangle that touches the top of the window and is inset from the left, + // right and bottom edges. The client rect touches the top because the + // tabstrip is painted over the caption at a custom offset. + // When the glass frame is not active, the client area is reported to be the + // entire window rect, except for the cases noted below. + // For non-tabbed browser windows, we use the default handling from the + // views system. + if (!browser_view_->IsBrowserTypeNormal()) return WindowWin::OnNCCalcSize(mode, l_param); - } RECT* client_rect = mode ? &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0] : @@ -221,8 +226,22 @@ LRESULT BrowserFrameWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { --client_rect->bottom; } } else if (!browser_view_->IsFullscreen()) { - // We draw our own client edge over part of the default frame would be. - border_thickness = GetSystemMetrics(SM_CXSIZEFRAME) - kClientEdgeThickness; + if (GetNonClientView()->UseNativeFrame()) { + // We draw our own client edge over part of the default frame. + border_thickness = + GetSystemMetrics(SM_CXSIZEFRAME) - kClientEdgeThickness; + } else { + // This is weird, but highly essential. If we don't offset the bottom edge + // of the client rect, the window client area and window area will match, + // and when returning to glass rendering mode from non-glass, the client + // area will not paint black as transparent. This is because (and I don't + // know why) the client area goes from matching the window rect to being + // something else. If the client area is not the window rect in both + // modes, the blackness doesn't occur. Because of this, we need to tell + // the RootView to lay out to fit the window rect, rather than the client + // rect when using the opaque frame. See SizeRootViewToWindowRect. + --client_rect->bottom; + } } client_rect->left += border_thickness; client_rect->right -= border_thickness; @@ -301,6 +320,10 @@ ThemeProvider* BrowserFrameWin::GetDefaultThemeProvider() const { return profile_->GetThemeProvider(); } +bool BrowserFrameWin::SizeRootViewToWindowRect() const { + return !GetNonClientView()->UseNativeFrame(); +} + /////////////////////////////////////////////////////////////////////////////// // BrowserFrame, views::CustomFrameWindow overrides: @@ -317,8 +340,10 @@ views::NonClientFrameView* BrowserFrameWin::CreateFrameViewForWindow() { } void BrowserFrameWin::UpdateFrameAfterFrameChange() { - WindowWin::UpdateFrameAfterFrameChange(); + // We need to update the glass region on or off before the base class adjusts + // the window region. UpdateDWMFrame(); + WindowWin::UpdateFrameAfterFrameChange(); } views::RootView* BrowserFrameWin::CreateRootView() { @@ -352,8 +377,6 @@ void BrowserFrameWin::UpdateDWMFrame() { } } else { // For popup and app windows we want to use the default margins. - margins.cxLeftWidth = margins.cxRightWidth = margins.cyTopHeight = - margins.cyBottomHeight = 0; } DwmExtendFrameIntoClientArea(GetNativeView(), &margins); } diff --git a/chrome/browser/views/frame/browser_frame_win.h b/chrome/browser/views/frame/browser_frame_win.h index dc23eb7..df59f36 100644 --- a/chrome/browser/views/frame/browser_frame_win.h +++ b/chrome/browser/views/frame/browser_frame_win.h @@ -64,6 +64,7 @@ class BrowserFrameWin : public BrowserFrame, public views::WindowWin { virtual void OnWindowPosChanged(WINDOWPOS* window_pos); virtual ThemeProvider* GetThemeProvider() const; virtual ThemeProvider* GetDefaultThemeProvider() const; + virtual bool SizeRootViewToWindowRect() const; // Overridden from views::Window: virtual int GetShowState() const; diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc index a4f2181..3d9987c 100644 --- a/views/widget/widget_win.cc +++ b/views/widget/widget_win.cc @@ -342,9 +342,7 @@ void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) { if (use_layered_buffer_) { // Force creation of the buffer at the right size. - RECT wr; - GetWindowRect(&wr); - ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top)); + LayoutRootView(); } else { contents_.reset(NULL); } @@ -808,7 +806,7 @@ void WidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { } void WidgetWin::OnSize(UINT param, const CSize& size) { - ChangeSize(param, size); + LayoutRootView(); } void WidgetWin::OnSysCommand(UINT notification_code, CPoint click) { @@ -951,15 +949,17 @@ void WidgetWin::ProcessMouseExited() { active_mouse_tracking_flags_ = 0; } -void WidgetWin::ChangeSize(UINT size_param, const CSize& size) { +void WidgetWin::LayoutRootView() { CRect rect; - if (use_layered_buffer_) { + if (SizeRootViewToWindowRect() || use_layered_buffer_) { GetWindowRect(&rect); - SizeContents(rect); } else { GetClientRect(&rect); } + if (use_layered_buffer_) + SizeContents(rect); + // Resizing changes the size of the view hierarchy and thus forces a // complete relayout. root_view_->SetBounds(0, 0, rect.Width(), rect.Height()); diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h index 40b3387..f8ba2a5 100644 --- a/views/widget/widget_win.h +++ b/views/widget/widget_win.h @@ -387,6 +387,13 @@ class WidgetWin : public app::WindowImpl, // behavior. virtual void OnFinalMessage(HWND window); + // Returns true if the RootView should be sized to the window rect instead of + // the client rect when the widget is resized. This is true if the widget's + // WM_NCCALCSIZE handler returns a client rect that differs from the window + // rect but the painted content of the window should still fill the entire + // visible window. + virtual bool SizeRootViewToWindowRect() const { return false; } + // Start tracking all mouse events so that this window gets sent mouse leave // messages too. void TrackMouseEvents(DWORD mouse_tracking_flags); @@ -403,8 +410,9 @@ class WidgetWin : public app::WindowImpl, void ProcessMouseMoved(const CPoint& point, UINT flags, bool is_nonclient); void ProcessMouseExited(); - // Handles re-laying out content in response to a window size change. - virtual void ChangeSize(UINT size_param, const CSize& size); + // Lays out the root view to fit the appropriate area within the widget. + // Called when the window size or non client metrics change. + void LayoutRootView(); // Returns whether capture should be released on mouse release. The default // is true. diff --git a/views/window/window_win.cc b/views/window/window_win.cc index 27ff3df..4daa279 100644 --- a/views/window/window_win.cc +++ b/views/window/window_win.cc @@ -190,14 +190,6 @@ static BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) { } // namespace void WindowWin::FrameTypeChanged() { - WINDOWPLACEMENT wp = {0}; - GetWindowPlacement(GetNativeWindow(), &wp); - Hide(); - - // Update the non-client view with the correct frame view for the active frame - // type. - non_client_view_->UpdateFrame(); - if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { // We need to toggle the rendering policy of the DWM/glass frame as we // change from opaque to glass. "Non client rendering enabled" means that @@ -217,11 +209,19 @@ void WindowWin::FrameTypeChanged() { SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE); + // The frame type change results in the client rect changing size, but this + // does not explicitly send a WM_SIZE, so we need to force the root view to + // be resized now. + LayoutRootView(); + + // Update the non-client view with the correct frame view for the active frame + // type. + non_client_view_->UpdateFrame(); + // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want // to notify our children too, since we can have MDI child windows who need to // update their appearance. EnumChildWindows(GetNativeView(), &SendDwmCompositionChanged, NULL); - SetWindowPlacement(GetNativeWindow(), &wp); } //////////////////////////////////////////////////////////////////////////////// @@ -789,6 +789,8 @@ static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) { void WindowWin::OnNCPaint(HRGN rgn) { // We only do non-client painting if we're not using the native frame. + // It's required to avoid some native painting artifacts from appearing when + // the window is resized. if (non_client_view_->UseNativeFrame()) { WidgetWin::OnNCPaint(rgn); return; @@ -1004,7 +1006,7 @@ void WindowWin::OnSize(UINT size_param, const CSize& new_size) { // and maximized bounds are the same, then we need to layout (because we // layout differently when maximized). SaveWindowPosition(); - ChangeSize(size_param, new_size); + LayoutRootView(); RedrawWindow(GetNativeView(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've |