summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--views/widget/widget_win.cc14
-rw-r--r--views/widget/widget_win.h14
-rw-r--r--views/window/window_win.cc122
-rw-r--r--views/window/window_win.h3
4 files changed, 125 insertions, 28 deletions
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
index 353fe4b..3d3a2b7 100644
--- a/views/widget/widget_win.cc
+++ b/views/widget/widget_win.cc
@@ -434,7 +434,7 @@ void WidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
if (use_layered_buffer_) {
// We must update the back-buffer immediately, since Windows' handling of
// invalid rects is somewhat mysterious.
- layered_window_invalid_rect_ = layered_window_invalid_rect_.Union(rect);
+ invalid_rect_ = invalid_rect_.Union(rect);
// In some situations, such as drag and drop, when Windows itself runs a
// nested message loop our message loop appears to be starved and we don't
@@ -1080,15 +1080,15 @@ void WidgetWin::RedrawInvalidRect() {
}
void WidgetWin::RedrawLayeredWindowContents() {
- if (layered_window_invalid_rect_.IsEmpty())
+ if (invalid_rect_.IsEmpty())
return;
// We need to clip to the dirty rect ourselves.
layered_window_contents_->save(SkCanvas::kClip_SaveFlag);
- layered_window_contents_->ClipRectInt(layered_window_invalid_rect_.x(),
- layered_window_invalid_rect_.y(),
- layered_window_invalid_rect_.width(),
- layered_window_invalid_rect_.height());
+ layered_window_contents_->ClipRectInt(invalid_rect_.x(),
+ invalid_rect_.y(),
+ invalid_rect_.width(),
+ invalid_rect_.height());
GetWidget()->GetRootView()->Paint(layered_window_contents_.get());
layered_window_contents_->restore();
@@ -1101,7 +1101,7 @@ void WidgetWin::RedrawLayeredWindowContents() {
BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
- layered_window_invalid_rect_.SetRect(0, 0, 0, 0);
+ invalid_rect_.SetRect(0, 0, 0, 0);
layered_window_contents_->endPlatformPaint();
}
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
index c659b61..79f3f49 100644
--- a/views/widget/widget_win.h
+++ b/views/widget/widget_win.h
@@ -397,6 +397,8 @@ class WidgetWin : public ui::WindowImpl,
// Are a subclass of WindowWin?
bool is_window_;
+ const gfx::Rect& invalid_rect() const { return invalid_rect_; }
+
private:
typedef ScopedVector<ui::ViewProp> ViewProps;
@@ -460,10 +462,14 @@ class WidgetWin : public ui::WindowImpl,
// window.
scoped_ptr<gfx::CanvasSkia> layered_window_contents_;
- // We must track the invalid rect for a layered window ourselves, since
- // Windows will not do this properly with InvalidateRect()/GetUpdateRect().
- // (In fact, it'll return misleading information from GetUpdateRect()).
- gfx::Rect layered_window_invalid_rect_;
+ // We must track the invalid rect ourselves, for two reasons:
+ // For layered windows, Windows will not do this properly with
+ // InvalidateRect()/GetUpdateRect(). (In fact, it'll return misleading
+ // information from GetUpdateRect()).
+ // We also need to keep track of the invalid rectangle for the RootView should
+ // we need to paint the non-client area. The data supplied to WM_NCPAINT seems
+ // to be insufficient.
+ gfx::Rect invalid_rect_;
// A factory that allows us to schedule a redraw for layered windows.
ScopedRunnableMethodFactory<WidgetWin> paint_layered_window_factory_;
diff --git a/views/window/window_win.cc b/views/window/window_win.cc
index 2845379..f50cefa 100644
--- a/views/window/window_win.cc
+++ b/views/window/window_win.cc
@@ -246,8 +246,7 @@ WindowWin::WindowWin(internal::NativeWindowDelegate* delegate)
ignore_pos_changes_factory_(this),
force_hidden_count_(0),
is_right_mouse_pressed_on_caption_(false),
- last_monitor_(NULL),
- is_in_size_move_(false) {
+ last_monitor_(NULL) {
is_window_ = true;
// Initialize these values to 0 so that subclasses can override the default
// behavior before calling Init.
@@ -404,23 +403,13 @@ LRESULT WindowWin::OnDwmCompositionChanged(UINT msg, WPARAM w_param,
}
void WindowWin::OnEnterSizeMove() {
- is_in_size_move_ = true;
WidgetWin::OnEnterSizeMove();
delegate_->OnNativeWindowBeginUserBoundsChange();
}
void WindowWin::OnExitSizeMove() {
- is_in_size_move_ = false;
WidgetWin::OnExitSizeMove();
delegate_->OnNativeWindowEndUserBoundsChange();
-
- if (!GetWindow()->ShouldUseNativeFrame()) {
- // Sending SWP_FRAMECHANGED forces a non-client repaint, which fixes the
- // glitch in rendering the bottom pixel of the window caused by us
- // offsetting the client rect there (See comment in GetClientAreaInsets()).
- SetWindowPos(NULL, 0, 0, 0, 0,
- SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER);
- }
}
void WindowWin::OnFinalMessage(HWND window) {
@@ -687,11 +676,116 @@ LRESULT WindowWin::OnNCHitTest(const CPoint& point) {
return WidgetWin::OnNCHitTest(point);
}
+namespace {
+struct ClipState {
+ // The window being painted.
+ HWND parent;
+
+ // DC painting to.
+ HDC dc;
+
+ // Origin of the window in terms of the screen.
+ int x;
+ int y;
+};
+
+// See comments in OnNCPaint for details of this function.
+static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
+ ClipState* clip_state = reinterpret_cast<ClipState*>(param);
+ if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) {
+ RECT bounds;
+ GetWindowRect(window, &bounds);
+ ExcludeClipRect(clip_state->dc,
+ bounds.left - clip_state->x,
+ bounds.top - clip_state->y,
+ bounds.right - clip_state->x,
+ bounds.bottom - clip_state->y);
+ }
+ return TRUE;
+}
+} // namespace
+
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 (GetWindow()->ShouldUseNativeFrame()) {
+ WidgetWin::OnNCPaint(rgn);
+ return;
+ }
+
+ // We have an NC region and need to paint it. We expand the NC region to
+ // include the dirty region of the root view. This is done to minimize
+ // paints.
+ CRect window_rect;
+ GetWindowRect(&window_rect);
+
+ if (window_rect.Width() != GetWidget()->GetRootView()->width() ||
+ window_rect.Height() != GetWidget()->GetRootView()->height()) {
+ // If the size of the window differs from the size of the root view it
+ // means we're being asked to paint before we've gotten a WM_SIZE. This can
+ // happen when the user is interactively resizing the window. To avoid
+ // mass flickering we don't do anything here. Once we get the WM_SIZE we'll
+ // reset the region of the window which triggers another WM_NCPAINT and
+ // all is well.
+ return;
+ }
+
+ CRect dirty_region;
+ // A value of 1 indicates paint all.
+ if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
+ dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
+ } else {
+ RECT rgn_bounding_box;
+ GetRgnBox(rgn, &rgn_bounding_box);
+ if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
+ return; // Dirty region doesn't intersect window bounds, bale.
+
+ // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
+ OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
+ }
+
+ // In theory GetDCEx should do what we want, but I couldn't get it to work.
+ // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell
+ // it doesn't work at all. So, instead we get the DC for the window then
+ // manually clip out the children.
+ HDC dc = GetWindowDC(GetNativeView());
+ ClipState clip_state;
+ clip_state.x = window_rect.left;
+ clip_state.y = window_rect.top;
+ clip_state.parent = GetNativeView();
+ clip_state.dc = dc;
+ EnumChildWindows(GetNativeView(), &ClipDCToChild,
+ reinterpret_cast<LPARAM>(&clip_state));
+
+ RootView* root_view = GetWidget()->GetRootView();
+ gfx::Rect old_paint_region = invalid_rect();
+
+ if (!old_paint_region.IsEmpty()) {
+ // The root view has a region that needs to be painted. Include it in the
+ // region we're going to paint.
+
+ CRect old_paint_region_crect = old_paint_region.ToRECT();
+ CRect tmp = dirty_region;
+ UnionRect(&dirty_region, &tmp, &old_paint_region_crect);
+ }
+
+ GetWidget()->GetRootView()->SchedulePaintInRect(gfx::Rect(dirty_region));
+
+ // gfx::CanvasSkiaPaint's destructor does the actual painting. As such, wrap
+ // the following in a block to force paint to occur so that we can release
+ // the dc.
+ {
+ gfx::CanvasSkiaPaint canvas(dc, true, dirty_region.left,
+ dirty_region.top, dirty_region.Width(),
+ dirty_region.Height());
+ delegate_->AsNativeWidgetDelegate()->OnNativeWidgetPaint(&canvas);
+ }
+
+ ReleaseDC(GetNativeView(), dc);
// When using a custom frame, we want to avoid calling DefWindowProc() since
// that may render artifacts.
- SetMsgHandled((!IsActive() || is_in_size_move_) &&
- !GetWindow()->ShouldUseNativeFrame());
+ SetMsgHandled(!GetWindow()->ShouldUseNativeFrame());
}
LRESULT WindowWin::OnNCUAHDrawCaption(UINT msg, WPARAM w_param,
diff --git a/views/window/window_win.h b/views/window/window_win.h
index 5270034..c829e13 100644
--- a/views/window/window_win.h
+++ b/views/window/window_win.h
@@ -268,9 +268,6 @@ class WindowWin : public WidgetWin,
DWORD drag_frame_saved_window_style_;
DWORD drag_frame_saved_window_ex_style_;
- // True when the window is being moved/sized.
- bool is_in_size_move_;
-
DISALLOW_COPY_AND_ASSIGN(WindowWin);
};