summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_main.cc9
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.cc14
-rw-r--r--chrome/browser/ui/views/constrained_window_win.cc2
-rw-r--r--chrome/browser/ui/views/download_shelf_view.cc2
-rw-r--r--chrome/browser/ui/views/info_bubble.cc1
-rw-r--r--chrome/browser/ui/views/tabs/base_tab.cc2
-rw-r--r--chrome/browser/ui/views/tabs/dragged_tab_view.cc7
-rw-r--r--chrome/browser/ui/views/wrench_menu.cc4
-rw-r--r--views/animation/bounds_animator.cc2
-rw-r--r--views/animation/bounds_animator_unittest.cc2
-rw-r--r--views/controls/menu/submenu_view.cc2
-rw-r--r--views/controls/scroll_view.cc4
-rw-r--r--views/controls/textfield/native_textfield_views.cc2
-rw-r--r--views/view.cc19
-rw-r--r--views/view.h11
-rw-r--r--views/view_unittest.cc40
-rw-r--r--views/views.gyp2
-rw-r--r--views/widget/native_widget.h4
-rw-r--r--views/widget/native_widget_win.cc71
-rw-r--r--views/widget/native_widget_win.h7
-rw-r--r--views/widget/root_view.cc168
-rw-r--r--views/widget/root_view.h70
-rw-r--r--views/widget/root_view_gtk.cc69
-rw-r--r--views/widget/root_view_win.cc31
-rw-r--r--views/widget/widget.h5
-rw-r--r--views/widget/widget_gtk.cc47
-rw-r--r--views/widget/widget_gtk.h16
-rw-r--r--views/widget/widget_impl.cc13
-rw-r--r--views/widget/widget_impl.h3
-rw-r--r--views/widget/widget_win.cc142
-rw-r--r--views/widget/widget_win.h12
-rw-r--r--views/window/window_win.cc121
32 files changed, 200 insertions, 704 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index edd454e..d608d8e 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -163,7 +163,9 @@
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/ui/views/chrome_views_delegate.h"
#include "views/focus/accelerator_handler.h"
-#include "views/widget/root_view.h"
+#if defined(TOOLKIT_USES_GTK)
+#include "views/widget/widget_gtk.h"
+#endif
#endif
#if defined(OS_CHROMEOS)
@@ -1019,8 +1021,11 @@ void InitializeToolkit(const MainFunctionParams& parameters) {
if (!views::ViewsDelegate::views_delegate)
views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
+#if defined(TOOLKIT_USES_GTK)
+ // TODO(beng): Move to WidgetImpl and implement on Windows too!
if (parameters.command_line_.HasSwitch(switches::kDebugViewsPaint))
- views::RootView::EnableDebugPaint();
+ views::WidgetGtk::EnableDebugPaint();
+#endif
#endif
#if defined(OS_WIN)
diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc
index 508e43e..1c81ac3 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.cc
+++ b/chrome/browser/chromeos/notifications/notification_panel.cc
@@ -70,7 +70,7 @@ chromeos::BalloonViewImpl* GetBalloonViewOf(const Balloon* balloon) {
// with gtk 2.18.6. See http://crbug.com/42235 for more details.
class PanelWidget : public views::WidgetGtk {
public:
- PanelWidget() : WidgetGtk(TYPE_WINDOW), painting_(false) {
+ PanelWidget() : WidgetGtk(TYPE_WINDOW) {
}
virtual ~PanelWidget() {
@@ -79,19 +79,7 @@ class PanelWidget : public views::WidgetGtk {
EnableDoubleBuffer(true);
}
- // views::WidgetGtk overrides.
- virtual void PaintNow(const gfx::Rect& update_rect) {
- if (!painting_) {
- painting_ = true;
- WidgetGtk::PaintNow(update_rect);
- painting_ = false;
- }
- }
-
private:
- // True if the painting is in progress.
- bool painting_;
-
DISALLOW_COPY_AND_ASSIGN(PanelWidget);
};
diff --git a/chrome/browser/ui/views/constrained_window_win.cc b/chrome/browser/ui/views/constrained_window_win.cc
index 01e2a58..5b46d34 100644
--- a/chrome/browser/ui/views/constrained_window_win.cc
+++ b/chrome/browser/ui/views/constrained_window_win.cc
@@ -278,7 +278,7 @@ ConstrainedWindowFrameView::~ConstrainedWindowFrameView() {
}
void ConstrainedWindowFrameView::UpdateWindowTitle() {
- SchedulePaintInRect(title_bounds_, false);
+ SchedulePaintInRect(title_bounds_);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/download_shelf_view.cc b/chrome/browser/ui/views/download_shelf_view.cc
index cc6661b..caffb09 100644
--- a/chrome/browser/ui/views/download_shelf_view.cc
+++ b/chrome/browser/ui/views/download_shelf_view.cc
@@ -426,7 +426,7 @@ void DownloadShelfView::SchedulePaintForDownloadItem(views::View* view) {
// Invalidate it
gfx::Rect invalid_rect =
GetFocusRectBounds(static_cast<DownloadItemView*>(view));
- SchedulePaintInRect(invalid_rect, false);
+ SchedulePaintInRect(invalid_rect);
}
gfx::Rect DownloadShelfView::GetFocusRectBounds(
diff --git a/chrome/browser/ui/views/info_bubble.cc b/chrome/browser/ui/views/info_bubble.cc
index 9440a9f..124a186 100644
--- a/chrome/browser/ui/views/info_bubble.cc
+++ b/chrome/browser/ui/views/info_bubble.cc
@@ -225,6 +225,7 @@ gfx::Rect BorderWidget::SizeAndGetBounds(
false, contents_size, &contents_bounds,
&window_bounds);
SetBounds(window_bounds);
+ border_contents_->SchedulePaint();
// Return |contents_bounds| in screen coordinates.
contents_bounds.Offset(window_bounds.origin());
diff --git a/chrome/browser/ui/views/tabs/base_tab.cc b/chrome/browser/ui/views/tabs/base_tab.cc
index 4350d04..f5c063f 100644
--- a/chrome/browser/ui/views/tabs/base_tab.cc
+++ b/chrome/browser/ui/views/tabs/base_tab.cc
@@ -512,7 +512,7 @@ void BaseTab::ScheduleIconPaint() {
if (IsPerformingCrashAnimation())
bounds.set_height(height() - bounds.y());
bounds.set_x(GetMirroredXForRect(bounds));
- SchedulePaintInRect(bounds, false);
+ SchedulePaintInRect(bounds);
}
// static
diff --git a/chrome/browser/ui/views/tabs/dragged_tab_view.cc b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
index 3b5b349..cea6be0 100644
--- a/chrome/browser/ui/views/tabs/dragged_tab_view.cc
+++ b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
@@ -108,14 +108,7 @@ void DraggedTabView::SetTabWidthAndUpdate(int width,
}
void DraggedTabView::Update() {
-#if defined(OS_WIN)
- container_->set_can_update_layered_window(true);
SchedulePaint();
- container_->PaintNow(gfx::Rect());
- container_->set_can_update_layered_window(false);
-#else
- SchedulePaint();
-#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/wrench_menu.cc b/chrome/browser/ui/views/wrench_menu.cc
index 710997a..065cc67 100644
--- a/chrome/browser/ui/views/wrench_menu.cc
+++ b/chrome/browser/ui/views/wrench_menu.cc
@@ -231,12 +231,12 @@ class ScheduleAllView : public views::View {
public:
ScheduleAllView() {}
- virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent) {
+ virtual void SchedulePaintInRect(const gfx::Rect& r) {
if (!IsVisible())
return;
if (parent())
- parent()->SchedulePaintInRect(GetMirroredBounds(), urgent);
+ parent()->SchedulePaintInRect(GetMirroredBounds());
}
private:
diff --git a/views/animation/bounds_animator.cc b/views/animation/bounds_animator.cc
index 20a6616..09d880e 100644
--- a/views/animation/bounds_animator.cc
+++ b/views/animation/bounds_animator.cc
@@ -236,7 +236,7 @@ void BoundsAnimator::AnimationContainerProgressed(
// Adjust for rtl.
repaint_bounds_.set_x(parent_->GetMirroredXWithWidthInView(
repaint_bounds_.x(), repaint_bounds_.width()));
- parent_->SchedulePaintInRect(repaint_bounds_, false);
+ parent_->SchedulePaintInRect(repaint_bounds_);
repaint_bounds_.SetRect(0, 0, 0, 0);
}
diff --git a/views/animation/bounds_animator_unittest.cc b/views/animation/bounds_animator_unittest.cc
index 7dc0f37..a899f8e 100644
--- a/views/animation/bounds_animator_unittest.cc
+++ b/views/animation/bounds_animator_unittest.cc
@@ -75,7 +75,7 @@ bool OwnedDelegate::canceled_ = false;
class TestView : public views::View {
public:
TestView() {}
- virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent) {
+ virtual void SchedulePaintInRect(const gfx::Rect& r) {
if (dirty_rect_.IsEmpty())
dirty_rect_ = r;
else
diff --git a/views/controls/menu/submenu_view.cc b/views/controls/menu/submenu_view.cc
index 67486cd..7c1f69e 100644
--- a/views/controls/menu/submenu_view.cc
+++ b/views/controls/menu/submenu_view.cc
@@ -351,7 +351,7 @@ void SubmenuView::SchedulePaintForDropIndicator(
if (position == MenuDelegate::DROP_ON) {
item->SchedulePaint();
} else if (position != MenuDelegate::DROP_NONE) {
- SchedulePaintInRect(CalculateDropIndicatorBounds(item, position), false);
+ SchedulePaintInRect(CalculateDropIndicatorBounds(item, position));
}
}
diff --git a/views/controls/scroll_view.cc b/views/controls/scroll_view.cc
index 707c8d6..9db46da 100644
--- a/views/controls/scroll_view.cc
+++ b/views/controls/scroll_view.cc
@@ -346,7 +346,7 @@ void ScrollView::ScrollToPosition(ScrollBar* source, int position) {
else if (position > max_pos)
position = max_pos;
contents_->SetX(-position);
- contents_->SchedulePaintInRect(contents_->GetVisibleBounds(), true);
+ contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
}
} else if (source == vert_sb_ && vert_sb_->IsVisible()) {
int vh = viewport_->height();
@@ -359,7 +359,7 @@ void ScrollView::ScrollToPosition(ScrollBar* source, int position) {
else if (position > max_pos)
position = max_pos;
contents_->SetY(-position);
- contents_->SchedulePaintInRect(contents_->GetVisibleBounds(), true);
+ contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
}
}
}
diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc
index 6e62f87..5642ef9 100644
--- a/views/controls/textfield/native_textfield_views.cc
+++ b/views/controls/textfield/native_textfield_views.cc
@@ -437,7 +437,7 @@ void NativeTextfieldViews::UpdateCursor() {
void NativeTextfieldViews::RepaintCursor() {
gfx::Rect r = cursor_bounds_;
r.Inset(-1, -1, -1, -1);
- SchedulePaintInRect(r, false);
+ SchedulePaintInRect(r);
}
void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset() {
diff --git a/views/view.cc b/views/view.cc
index 63fc3d4..a19d662 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -599,19 +599,19 @@ gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
// Painting --------------------------------------------------------------------
void View::SchedulePaint() {
- SchedulePaintInRect(GetLocalBounds(), false);
+ SchedulePaintInRect(GetLocalBounds());
}
-void View::SchedulePaintInRect(const gfx::Rect& r, bool urgent) {
+void View::SchedulePaintInRect(const gfx::Rect& rect) {
if (!IsVisible())
return;
if (parent_) {
// Translate the requested paint rect to the parent's coordinate system
// then pass this notification up to the parent.
- gfx::Rect paint_rect = ConvertRectToParent(r);
+ gfx::Rect paint_rect = ConvertRectToParent(rect);
paint_rect.Offset(GetMirroredPosition());
- parent_->SchedulePaintInRect(paint_rect, urgent);
+ parent_->SchedulePaintInRect(paint_rect);
}
}
@@ -1060,12 +1060,6 @@ void View::OnPaintFocusBorder(gfx::Canvas* canvas) {
canvas->DrawFocusRect(0, 0, width(), height());
}
-#ifndef NDEBUG
-bool View::IsProcessingPaint() const {
- return parent() && parent()->IsProcessingPaint();
-}
-#endif
-
// Input -----------------------------------------------------------------------
bool View::HasHitTestMask() const {
@@ -1150,11 +1144,6 @@ void View::DoRemoveChildView(View* view,
bool update_focus_cycle,
bool update_tool_tip,
bool delete_removed_view) {
-#ifndef NDEBUG
- DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
- "during a paint, this will seriously " <<
- "mess things up!";
-#endif
DCHECK(view);
const ViewVector::iterator i = find(children_.begin(), children_.end(), view);
scoped_ptr<View> view_to_be_deleted;
diff --git a/views/view.h b/views/view.h
index e8f8e58..5ebdd3f 100644
--- a/views/view.h
+++ b/views/view.h
@@ -514,13 +514,11 @@ class View : public AcceleratorTarget {
// Mark all or part of the View's bounds as dirty (needing repaint).
// |r| is in the View's coordinates.
- // When |urgent| is true, the view will be repainted when the current event
- // processing is done. Otherwise, painting will take place as soon as
- // possible. Rectangle |r| should be in the view's coordinate system. The
+ // Rectangle |r| should be in the view's coordinate system. The
// transformations are applied to it to convert it into the parent coordinate
// system before propagating SchedulePaint up the view hierarchy.
virtual void SchedulePaint();
- virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent);
+ virtual void SchedulePaintInRect(const gfx::Rect& r);
// Called by the framework to paint a View. Performs translation and clipping
// for View coordinates and language direction as required, allows the View
@@ -1074,11 +1072,6 @@ class View : public AcceleratorTarget {
// relevant contents.
virtual void OnPaintFocusBorder(gfx::Canvas* canvas);
-#ifndef NDEBUG
- // Returns true if the View is currently processing a paint.
- virtual bool IsProcessingPaint() const;
-#endif
-
// Input ---------------------------------------------------------------------
// Called by HitTest to see if this View has a custom hit test mask. If the
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
index 6ae69c5..90b228a 100644
--- a/views/view_unittest.cc
+++ b/views/view_unittest.cc
@@ -58,6 +58,8 @@ class ViewTest : public ViewsTestBase {
}
};
+/*
+
// Paints the RootView.
void PaintRootView(views::RootView* root, bool empty_paint) {
if (!empty_paint) {
@@ -73,7 +75,6 @@ void PaintRootView(views::RootView* root, bool empty_paint) {
}
}
-/*
typedef CWinTraits<WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS> CVTWTraits;
// A trivial window implementation that tracks whether or not it has been
@@ -1518,8 +1519,32 @@ TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) {
////////////////////////////////////////////////////////////////////////////////
// Transformations
////////////////////////////////////////////////////////////////////////////////
+
+class TransformPaintView : public TestView {
+ public:
+ TransformPaintView() {}
+ virtual ~TransformPaintView() {}
+
+ void ClearScheduledPaintRect() {
+ scheduled_paint_rect_ = gfx::Rect();
+ }
+
+ gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; }
+
+ // Overridden from View:
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) {
+ gfx::Rect xrect = ConvertRectToParent(rect);
+ scheduled_paint_rect_ = scheduled_paint_rect_.Union(xrect);
+ }
+
+ private:
+ gfx::Rect scheduled_paint_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransformPaintView);
+};
+
TEST_F(ViewTest, TransformPaint) {
- TestView* v1 = new TestView();
+ TransformPaintView* v1 = new TransformPaintView();
v1->SetBounds(0, 0, 500, 300);
TestView* v2 = new TestView();
@@ -1531,17 +1556,17 @@ TEST_F(ViewTest, TransformPaint) {
window_win->set_window_style(WS_OVERLAPPEDWINDOW);
window_win->Init(NULL, gfx::Rect(50, 50, 650, 650));
#endif
+ widget->Show();
RootView* root = widget->GetRootView();
root->AddChildView(v1);
v1->AddChildView(v2);
// At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
- root->ClearPaintRect();
+ v1->ClearScheduledPaintRect();
v2->SchedulePaint();
- gfx::Rect rect = root->GetScheduledPaintRect();
- EXPECT_EQ(gfx::Rect(100, 100, 200, 100), rect);
+ EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect());
// Rotate |v1| counter-clockwise.
v1->SetRotation(-90.0);
@@ -1549,11 +1574,10 @@ TEST_F(ViewTest, TransformPaint) {
// |v2| now occupies (100, 200) to (200, 400) in |root|.
- root->ClearPaintRect();
+ v1->ClearScheduledPaintRect();
v2->SchedulePaint();
- rect = root->GetScheduledPaintRect();
- EXPECT_EQ(gfx::Rect(100, 200, 100, 200), rect);
+ EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect());
widget->CloseNow();
}
diff --git a/views/views.gyp b/views/views.gyp
index 23d1f40..8586d1e 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -332,8 +332,6 @@
'widget/gtk_views_window.h',
'widget/root_view.cc',
'widget/root_view.h',
- 'widget/root_view_gtk.cc',
- 'widget/root_view_win.cc',
'widget/tooltip_manager_gtk.cc',
'widget/tooltip_manager_gtk.h',
'widget/tooltip_manager_win.cc',
diff --git a/views/widget/native_widget.h b/views/widget/native_widget.h
index d335145..41782e5 100644
--- a/views/widget/native_widget.h
+++ b/views/widget/native_widget.h
@@ -69,9 +69,7 @@ class NativeWidget {
virtual void ReleaseMouseCapture() = 0;
virtual bool HasMouseCapture() const = 0;
virtual bool ShouldReleaseCaptureOnMouseReleased() const = 0;
- virtual void Invalidate() = 0;
- virtual void InvalidateRect(const gfx::Rect& invalid_rect) = 0;
- virtual void Paint() = 0;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
virtual void FocusNativeView(gfx::NativeView native_view) = 0;
virtual void RunShellDrag(const ui::OSExchangeData& data, int operation) = 0;
virtual WidgetImpl* GetWidgetImpl() = 0;
diff --git a/views/widget/native_widget_win.cc b/views/widget/native_widget_win.cc
index e0f9062..e5e87ef 100644
--- a/views/widget/native_widget_win.cc
+++ b/views/widget/native_widget_win.cc
@@ -23,23 +23,6 @@ namespace internal {
namespace {
-// Called from NativeWidgetWin::Paint() to asynchronously redraw child windows.
-BOOL CALLBACK EnumChildProcForRedraw(HWND hwnd, LPARAM lparam) {
- DWORD process_id;
- GetWindowThreadProcessId(hwnd, &process_id);
- gfx::Rect invalid_rect = *reinterpret_cast<gfx::Rect*>(lparam);
-
- RECT window_rect;
- GetWindowRect(hwnd, &window_rect);
- invalid_rect.Offset(-window_rect.left, -window_rect.top);
-
- int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME;
- if (process_id == GetCurrentProcessId())
- flags |= RDW_UPDATENOW;
- RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags);
- return TRUE;
-}
-
// Links the HWND to its Widget.
const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
@@ -118,7 +101,7 @@ void NativeWidgetWin::Show() {
ShowWindow(hwnd(), SW_SHOWNOACTIVATE);
// TODO(beng): move to windowposchanging to trap visibility changes instead.
if (IsLayeredWindow())
- Invalidate();
+ SchedulePaint();
}
void NativeWidgetWin::Hide() {
@@ -177,38 +160,12 @@ bool NativeWidgetWin::ShouldReleaseCaptureOnMouseReleased() const {
return true;
}
-void NativeWidgetWin::Invalidate() {
- ::InvalidateRect(hwnd(), NULL, FALSE);
-}
-
-void NativeWidgetWin::InvalidateRect(const gfx::Rect& invalid_rect) {
+void NativeWidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
// InvalidateRect() expects client coordinates.
- RECT r = invalid_rect.ToRECT();
+ RECT r = rect.ToRECT();
::InvalidateRect(hwnd(), &r, FALSE);
}
-void NativeWidgetWin::Paint() {
- RECT r;
- GetUpdateRect(hwnd(), &r, FALSE);
- if (!IsRectEmpty(&r)) {
- // TODO(beng): WS_EX_TRANSPARENT windows (see WidgetWin::opaque_)
- // Paint child windows that are in a different process asynchronously.
- // This prevents a hang in other processes from blocking this process.
-
- // Calculate the invalid rect in screen coordinates before the first
- // RedrawWindow() call to the parent HWND, since that will empty update_rect
- // (which comes from a member variable) in the OnPaint call.
- gfx::Rect screen_rect = GetWindowScreenBounds();
- gfx::Rect invalid_screen_rect(r);
- invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
-
- RedrawWindow(hwnd(), &r, NULL,
- RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
-
- LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
- EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam);
- }
-}
void NativeWidgetWin::FocusNativeView(gfx::NativeView native_view) {
if (IsWindow(native_view)) {
@@ -245,11 +202,7 @@ void NativeWidgetWin::WillProcessMessage(const MSG& msg) {
}
void NativeWidgetWin::DidProcessMessage(const MSG& msg) {
- // We need to add ourselves as a message loop observer so that we can repaint
- // aggressively if the contents of our window become invalid. Unfortunately
- // WM_PAINT messages are starved and we get flickery redrawing when resizing
- // if we do not do this.
- Paint();
+ RedrawInvalidRect();
}
////////////////////////////////////////////////////////////////////////////////
@@ -289,6 +242,10 @@ void NativeWidgetWin::OnCommand(UINT notification_code, int command_id,
LRESULT NativeWidgetWin::OnCreate(CREATESTRUCT* create_struct) {
SetNativeWindowProperty(kNativeWidgetKey, this);
listener_->OnNativeWidgetCreated();
+ // We need to add ourselves as a message loop observer so that we can repaint
+ // aggressively if the contents of our window become invalid. Unfortunately
+ // WM_PAINT messages are starved and we get flickery redrawing when resizing
+ // if we do not do this.
MessageLoopForUI::current()->AddObserver(this);
return 0;
}
@@ -634,6 +591,18 @@ void NativeWidgetWin::CloseNow() {
DestroyWindow(hwnd());
}
+void NativeWidgetWin::SchedulePaint() {
+ ::InvalidateRect(hwnd(), NULL, FALSE);
+}
+
+void NativeWidgetWin::RedrawInvalidRect() {
+ RECT r;
+ if (GetUpdateRect(hwnd(), &r, FALSE)) {
+ RedrawWindow(hwnd(), &r, NULL,
+ RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+ }
+}
+
bool NativeWidgetWin::IsLayeredWindow() const {
return !!(window_ex_style() & WS_EX_LAYERED);
}
diff --git a/views/widget/native_widget_win.h b/views/widget/native_widget_win.h
index cc00884..3f0f86e 100644
--- a/views/widget/native_widget_win.h
+++ b/views/widget/native_widget_win.h
@@ -80,9 +80,7 @@ class NativeWidgetWin : public NativeWidget,
virtual void ReleaseMouseCapture();
virtual bool HasMouseCapture() const;
virtual bool ShouldReleaseCaptureOnMouseReleased() const;
- virtual void Invalidate();
- virtual void InvalidateRect(const gfx::Rect& invalid_rect);
- virtual void Paint();
+ virtual void SchedulePaintInRect(const gfx::Rect& rect);
virtual void FocusNativeView(gfx::NativeView native_view);
virtual void RunShellDrag(const ui::OSExchangeData& data, int operation);
virtual WidgetImpl* GetWidgetImpl();
@@ -244,6 +242,9 @@ class NativeWidgetWin : public NativeWidget,
void CloseNow();
+ void SchedulePaint();
+ void RedrawInvalidRect();
+
bool IsLayeredWindow() const;
// A listener implementation that handles events received here.
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
index 3231292..4f2038e 100644
--- a/views/widget/root_view.cc
+++ b/views/widget/root_view.cc
@@ -35,57 +35,8 @@
namespace views {
-// Performs painting after a return to the message loop.
-// TODO(beng): CancelableTask, or delete in SchedulePaint rewrite.
-class PaintTask : public Task {
- public:
- explicit PaintTask(RootView* target) : root_view_(target) {
- }
-
- ~PaintTask() {}
-
- void Cancel() {
- root_view_ = NULL;
- }
-
- void Run() {
- if (root_view_)
- root_view_->PaintNow();
- }
- private:
- // The target root view.
- RootView* root_view_;
-
- DISALLOW_COPY_AND_ASSIGN(PaintTask);
-};
-
-namespace {
-
-#ifndef NDEBUG
-// Sets the value of RootView's |is_processing_paint_| member to true as long
-// as Paint() is being called. Sets it to |false| when it returns.
-class ScopedProcessingPaint {
- public:
- explicit ScopedProcessingPaint(bool* is_processing_paint)
- : is_processing_paint_(is_processing_paint) {
- *is_processing_paint_ = true;
- }
-
- ~ScopedProcessingPaint() {
- *is_processing_paint_ = false;
- }
- private:
- bool* is_processing_paint_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedProcessingPaint);
-};
-#endif
-
-} // namespace
-
// static
const char RootView::kViewClassName[] = "views/RootView";
-bool RootView::debug_paint_enabled_ = false;
////////////////////////////////////////////////////////////////////////////////
// RootView, public:
@@ -94,12 +45,6 @@ bool RootView::debug_paint_enabled_ = false;
RootView::RootView(Widget* widget)
: widget_(widget),
- invalid_rect_urgent_(false),
- pending_paint_task_(NULL),
- paint_task_needed_(false),
-#ifndef NDEBUG
- is_processing_paint_(false),
-#endif
mouse_pressed_handler_(NULL),
mouse_move_handler_(NULL),
last_click_handler_(NULL),
@@ -127,9 +72,6 @@ RootView::~RootView() {
// notification is sent for each one of them.
if (has_children())
RemoveAllChildViews(true);
-
- if (pending_paint_task_)
- pending_paint_task_->Cancel(); // Ensure we're not called any more.
}
// Tree operations -------------------------------------------------------------
@@ -156,41 +98,6 @@ void RootView::NotifyNativeViewHierarchyChanged(bool attached,
PropagateNativeViewHierarchyChanged(attached, native_view, this);
}
-// Painting --------------------------------------------------------------------
-
-bool RootView::NeedsPainting(bool urgent) {
- bool has_invalid_rect = !invalid_rect_.IsEmpty();
- if (urgent)
- return invalid_rect_urgent_ ? has_invalid_rect : false;
- return has_invalid_rect;
-}
-
-const gfx::Rect& RootView::GetScheduledPaintRect() {
- return invalid_rect_;
-}
-
-gfx::Rect RootView::GetScheduledPaintRectConstrainedToSize() {
- if (invalid_rect_.IsEmpty())
- return invalid_rect_;
-
- return invalid_rect_.Intersect(GetLocalBounds());
-}
-
-void RootView::ClearPaintRect() {
- invalid_rect_.SetRect(0, 0, 0, 0);
-
- // This painting has been done. Reset the urgent flag.
- invalid_rect_urgent_ = false;
-
- // If a pending_paint_task_ does Run(), we don't need to do anything.
- paint_task_needed_ = false;
-}
-
-// static
-void RootView::EnableDebugPaint() {
- debug_paint_enabled_ = true;
-}
-
// Input -----------------------------------------------------------------------
void RootView::ProcessMouseDragCanceled() {
@@ -297,70 +204,11 @@ View* RootView::GetFocusTraversableParentView() {
////////////////////////////////////////////////////////////////////////////////
// RootView, View overrides:
-void RootView::SchedulePaintInRect(const gfx::Rect& r, bool urgent) {
- gfx::Rect xrect = ConvertRectToParent(r);
- // If there is an existing invalid rect, add the union of the scheduled
- // rect with the invalid rect. This could be optimized further if
- // necessary.
- if (invalid_rect_.IsEmpty())
- invalid_rect_ = xrect;
- else
- invalid_rect_ = invalid_rect_.Union(xrect);
-
- if (urgent || invalid_rect_urgent_) {
- invalid_rect_urgent_ = true;
- } else {
- if (!pending_paint_task_) {
- pending_paint_task_ = new PaintTask(this);
- MessageLoop::current()->PostTask(FROM_HERE, pending_paint_task_);
- }
- paint_task_needed_ = true;
- }
-}
-
-void RootView::Paint(gfx::Canvas* canvas) {
-#ifndef NDEBUG
- ScopedProcessingPaint processing_paint(&is_processing_paint_);
-#endif
-
- // Clip the invalid rect to our bounds. If a view is in a scrollview
- // it could be a lot larger
- invalid_rect_ = GetScheduledPaintRectConstrainedToSize();
-
- if (invalid_rect_.IsEmpty())
- return;
-
- // Clear the background.
- canvas->AsCanvasSkia()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
-
- // Save the current transforms.
- canvas->Save();
-
- // Set the clip rect according to the invalid rect.
- int clip_x = invalid_rect_.x() + x();
- int clip_y = invalid_rect_.y() + y();
- canvas->ClipRectInt(clip_x, clip_y, invalid_rect_.width(),
- invalid_rect_.height());
-
- // Paint the tree
- View::Paint(canvas);
-
- // Restore the previous transform
- canvas->Restore();
-
- ClearPaintRect();
-}
-
-void RootView::PaintNow() {
- if (pending_paint_task_) {
- pending_paint_task_->Cancel();
- pending_paint_task_ = NULL;
- }
- if (!paint_task_needed_)
- return;
- Widget* widget = GetWidget();
- if (widget)
- widget->PaintNow(invalid_rect_);
+void RootView::SchedulePaintInRect(const gfx::Rect& rect) {
+ gfx::Rect xrect = ConvertRectToParent(rect);
+ gfx::Rect invalid_rect = GetLocalBounds().Intersect(xrect);
+ if (!invalid_rect.IsEmpty())
+ widget_->SchedulePaintInRect(invalid_rect);
}
const Widget* RootView::GetWidget() const {
@@ -620,6 +468,10 @@ AccessibilityTypes::Role RootView::GetAccessibleRole() {
return AccessibilityTypes::ROLE_APPLICATION;
}
+void RootView::OnPaint(gfx::Canvas* canvas) {
+ canvas->AsCanvasSkia()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
+}
+
void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
widget_->ViewHierarchyChanged(is_add, parent, child);
@@ -646,7 +498,7 @@ bool RootView::ConvertPointToMouseHandler(const gfx::Point& l,
gfx::Point* p) {
//
// If the mouse_handler was set explicitly, we need to keep
- // sending events even if it was reparented in a different
+ // sending events even if it was re-parented in a different
// window. (a non explicit mouse handler is automatically
// cleared when the control is removed from the hierarchy)
if (explicit_mouse_handler_) {
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
index e9d436e..830a85d 100644
--- a/views/widget/root_view.h
+++ b/views/widget/root_view.h
@@ -13,13 +13,8 @@
#include "views/focus/focus_search.h"
#include "views/view.h"
-#if defined(OS_LINUX)
-typedef struct _GdkEventExpose GdkEventExpose;
-#endif
-
namespace views {
-class PaintTask;
class Widget;
#if defined(TOUCH_UI)
class GestureManager;
@@ -39,9 +34,6 @@ class GestureManager;
// initialized to attach the contents view to the RootView.
// TODO(beng): Enforce no other callers to AddChildView/tree functions by
// overriding those methods as private here.
-// TODO(beng): Get rid of the scheduled paint rect tracking that this class
-// does - it is superfluous to the underlying environment's invalid
-// rect tracking.
// TODO(beng): Move to internal namespace and remove accessors from
// View/Widget.
// TODO(beng): Clean up API further, make WidgetImpl a friend.
@@ -65,35 +57,6 @@ class RootView : public View,
void NotifyNativeViewHierarchyChanged(bool attached,
gfx::NativeView native_view);
- // Painting ------------------------------------------------------------------
-
- // Whether or not this View needs repainting. If |urgent| is true, this method
- // returns whether this root view needs to paint as soon as possible.
- bool NeedsPainting(bool urgent);
-
- // Invoked by the Widget to discover what rectangle should be painted.
- const gfx::Rect& GetScheduledPaintRect();
-
- // Returns the region scheduled to paint clipped to the RootViews bounds.
- gfx::Rect GetScheduledPaintRectConstrainedToSize();
-
- // Clears the region that is schedule to be painted. You nearly never need
- // to invoke this. This is primarily intended for Widgets.
- void ClearPaintRect();
-
- // TODO(beng): These should be handled at the NativeWidget level. NativeWidget
- // should crack and create a gfx::Canvas which is passed to a
- // paint processing routine here.
-#if defined(OS_WIN)
- // Invoked from the Widget to service a WM_PAINT call.
- void OnPaint(HWND hwnd);
-#elif defined(OS_LINUX)
- void OnPaint(GdkEventExpose* event);
-#endif
-
- // Enables debug painting. See |debug_paint_enabled_| for details.
- static void EnableDebugPaint();
-
// Input ---------------------------------------------------------------------
// Invoked By the Widget if the mouse drag is interrupted by
@@ -157,9 +120,7 @@ class RootView : public View,
virtual View* GetFocusTraversableParentView();
// Overridden from View:
- virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent);
- virtual void Paint(gfx::Canvas* canvas);
- virtual void PaintNow();
+ virtual void SchedulePaintInRect(const gfx::Rect& rect);
virtual const Widget* GetWidget() const;
virtual Widget* GetWidget();
virtual bool OnMousePressed(const MouseEvent& e);
@@ -176,10 +137,8 @@ class RootView : public View,
protected:
// Overridden from View:
+ virtual void OnPaint(gfx::Canvas* canvas);
virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
-#ifndef NDEBUG
- virtual bool IsProcessingPaint() const { return is_processing_paint_; }
-#endif
private:
friend class View;
@@ -217,31 +176,6 @@ class RootView : public View,
// The host Widget
Widget* widget_;
- // Painting ------------------------------------------------------------------
-
- // The rectangle that should be painted
- gfx::Rect invalid_rect_;
-
- // Whether the current invalid rect should be painted urgently.
- bool invalid_rect_urgent_;
-
- // The task that we are using to trigger some non urgent painting or NULL
- // if no painting has been scheduled yet.
- PaintTask* pending_paint_task_;
-
- // Indicate if, when the pending_paint_task_ is run, actual painting is still
- // required.
- bool paint_task_needed_;
-
-#ifndef NDEBUG
- // True if we're currently processing paint.
- bool is_processing_paint_;
-#endif
-
- // True to enable debug painting. Enabling causes the damaged
- // region to be painted to flash in red.
- static bool debug_paint_enabled_;
-
// Input ---------------------------------------------------------------------
// The view currently handing down - drag - up
diff --git a/views/widget/root_view_gtk.cc b/views/widget/root_view_gtk.cc
deleted file mode 100644
index 11b0430..0000000
--- a/views/widget/root_view_gtk.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/widget/root_view.h"
-
-#include <gtk/gtk.h>
-#include <X11/Xlib.h>
-
-#include "base/logging.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "views/widget/widget_gtk.h"
-
-namespace views {
-
-void RootView::OnPaint(GdkEventExpose* event) {
-
- WidgetGtk* widget = static_cast<WidgetGtk*>(GetWidget());
- if (!widget) {
- NOTREACHED();
- return;
- }
- if (debug_paint_enabled_) {
- // Using cairo directly because using skia didn't have immediate effect.
- cairo_t* cr = gdk_cairo_create(event->window);
- gdk_cairo_region(cr, event->region);
- cairo_set_source_rgb(cr, 1, 0, 0); // red
- cairo_rectangle(cr,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- cairo_fill(cr);
- cairo_destroy(cr);
- // Make sure that users see the red flash.
- XSync(ui::GetXDisplay(), false /* don't discard events */);
- }
- gfx::Rect scheduled_dirty_rect = GetScheduledPaintRectConstrainedToSize();
- gfx::Rect expose_rect = gfx::Rect(event->area);
- gfx::CanvasSkiaPaint canvas(event);
- bool invoked_process_paint = false;
- if (!canvas.is_empty()) {
- canvas.set_composite_alpha(widget->is_transparent());
- SchedulePaintInRect(gfx::Rect(canvas.rectangle()), false);
- if (NeedsPainting(false)) {
- Paint(&canvas);
- invoked_process_paint = true;
- }
- }
-
- if (invoked_process_paint && !scheduled_dirty_rect.IsEmpty() &&
- !expose_rect.Contains(scheduled_dirty_rect) && widget &&
- !widget->in_paint_now()) {
- // We're painting as the result of Gtk wanting us to paint (not from views)
- // and there was a region scheduled by views to be painted that is not
- // contained in the region gtk wants us to paint. As a result of the
- // Paint() call above views no longer thinks it needs to be painted.
- // We have to invoke SchedulePaint here to be sure we end up painting the
- // region views wants to paint, otherwise we'll drop the views paint region
- // on the floor.
- //
- // NOTE: We don't expand the region to paint to include
- // scheduled_dirty_rect as that results in us drawing on top of any GTK
- // widgets that don't have a window. We have to schedule the paint through
- // GTK so that such widgets are painted.
- SchedulePaintInRect(scheduled_dirty_rect, false);
- }
-}
-
-}
diff --git a/views/widget/root_view_win.cc b/views/widget/root_view_win.cc
deleted file mode 100644
index 7c89901..0000000
--- a/views/widget/root_view_win.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/widget/root_view.h"
-
-#include "ui/gfx/canvas_skia.h"
-
-namespace views {
-
-void RootView::OnPaint(HWND hwnd) {
- gfx::Rect original_dirty_region = GetScheduledPaintRectConstrainedToSize();
- if (!original_dirty_region.IsEmpty()) {
- // Invoke InvalidateRect so that the dirty region of the window includes the
- // region we need to paint. If we didn't do this and the region didn't
- // include the dirty region, Paint() would incorrectly mark everything as
- // clean. This can happen if a WM_PAINT is generated by the system before
- // the InvokeLater schedule by RootView is processed.
- RECT win_version = original_dirty_region.ToRECT();
- InvalidateRect(hwnd, &win_version, FALSE);
- }
- scoped_ptr<gfx::CanvasPaint> canvas(
- gfx::CanvasPaint::CreateCanvasPaint(hwnd));
- if (!canvas->IsValid()) {
- SchedulePaintInRect(canvas->GetInvalidRect(), false);
- if (NeedsPainting(false))
- Paint(canvas->AsCanvas());
- }
-}
-
-}
diff --git a/views/widget/widget.h b/views/widget/widget.h
index 200d9b1..d27dcd8 100644
--- a/views/widget/widget.h
+++ b/views/widget/widget.h
@@ -159,9 +159,6 @@ class Widget {
// Returns the gfx::NativeView associated with this Widget.
virtual gfx::NativeView GetNativeView() const = 0;
- // Forces a paint of a specified rectangle immediately.
- virtual void PaintNow(const gfx::Rect& update_rect) = 0;
-
// Sets the opacity of the widget. This may allow widgets behind the widget
// in the Z-order to become visible, depending on the capabilities of the
// underlying windowing system. Note that the caller must then schedule a
@@ -240,6 +237,8 @@ class Widget {
// If a view is dragging, this returns it. Otherwise returns NULL.
virtual View* GetDraggedView() = 0;
+
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
};
} // namespace views
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index 45fd1ba..a014158 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -18,6 +18,8 @@
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_gtk.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/canvas_skia_paint.h"
#include "ui/gfx/path.h"
#include "views/focus/view_storage.h"
#include "views/widget/default_theme_provider.h"
@@ -224,6 +226,7 @@ static GtkWidget* CreateDragIconWidget(GdkPixbuf* drag_image) {
// static
GtkWidget* WidgetGtk::null_parent_ = NULL;
+bool WidgetGtk::debug_paint_enabled_ = false;
////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, public:
@@ -244,7 +247,6 @@ WidgetGtk::WidgetGtk(Type type)
ignore_drag_leave_(false),
opacity_(255),
drag_data_(NULL),
- in_paint_now_(false),
is_active_(false),
transient_to_parent_(false),
got_initial_focus_in_(false),
@@ -730,16 +732,6 @@ gfx::NativeView WidgetGtk::GetNativeView() const {
return widget_;
}
-void WidgetGtk::PaintNow(const gfx::Rect& update_rect) {
- if (widget_ && GTK_WIDGET_DRAWABLE(widget_)) {
- gtk_widget_queue_draw_area(widget_, update_rect.x(), update_rect.y(),
- update_rect.width(), update_rect.height());
- // Force the paint to occur now.
- AutoReset<bool> auto_reset_in_paint_now(&in_paint_now_, true);
- gdk_window_process_updates(widget_->window, true);
- }
-}
-
void WidgetGtk::SetOpacity(unsigned char opacity) {
opacity_ = opacity;
if (widget_) {
@@ -881,6 +873,13 @@ View* WidgetGtk::GetDraggedView() {
return dragged_view_;
}
+void WidgetGtk::SchedulePaintInRect(const gfx::Rect& rect) {
+ if (widget_ && GTK_WIDGET_DRAWABLE(widget_)) {
+ gtk_widget_queue_draw_area(widget_, rect.x(), rect.y(), rect.width(),
+ rect.height());
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, FocusTraversable implementation:
@@ -966,6 +965,11 @@ int WidgetGtk::GetFlagsForEventButton(const GdkEventButton& event) {
return flags;
}
+// static
+void WidgetGtk::EnableDebugPaint() {
+ debug_paint_enabled_ = true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, protected:
@@ -1005,7 +1009,26 @@ gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
CompositePainter::SetComposited(widget_);
}
}
- root_view_->OnPaint(event);
+
+ if (debug_paint_enabled_) {
+ // Using cairo directly because using skia didn't have immediate effect.
+ cairo_t* cr = gdk_cairo_create(event->window);
+ gdk_cairo_region(cr, event->region);
+ cairo_set_source_rgb(cr, 1, 0, 0); // red
+ cairo_rectangle(cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+ // Make sure that users see the red flash.
+ XSync(ui::GetXDisplay(), false /* don't discard events */);
+ }
+
+ gfx::CanvasSkiaPaint canvas(event);
+ if (!canvas.is_empty()) {
+ canvas.set_composite_alpha(is_transparent());
+ root_view_->Paint(&canvas);
+ }
return false; // False indicates other widgets should get the event as well.
}
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 2692d5e..44c922a 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -127,10 +127,6 @@ class WidgetGtk
// Starts a drag on this widget. This blocks until the drag is done.
void DoDrag(const OSExchangeData& data, int operation);
- // Are we in PaintNow? See use in root_view_gtk for details on what this is
- // used for.
- bool in_paint_now() const { return in_paint_now_; }
-
// Sets the focus traversable parents.
void SetFocusTraversableParent(FocusTraversable* parent);
void SetFocusTraversableParentView(View* parent_view);
@@ -176,7 +172,6 @@ class WidgetGtk
virtual void Show();
virtual void Hide();
virtual gfx::NativeView GetNativeView() const;
- virtual void PaintNow(const gfx::Rect& update_rect);
virtual void SetOpacity(unsigned char opacity);
virtual void SetAlwaysOnTop(bool on_top);
virtual RootView* GetRootView();
@@ -202,6 +197,7 @@ class WidgetGtk
const OSExchangeData& data,
int operation);
virtual View* GetDraggedView();
+ virtual void SchedulePaintInRect(const gfx::Rect& rect);
// Overridden from FocusTraversable:
virtual FocusSearch* GetFocusSearch();
@@ -218,8 +214,11 @@ class WidgetGtk
// Returns the view::Event::flags for a GdkEventButton.
static int GetFlagsForEventButton(const GdkEventButton& event);
+ // Enables debug painting. See |debug_paint_enabled_| for details.
+ static void EnableDebugPaint();
+
protected:
- // If widget containes another widget, translates event coordinates to the
+ // If widget contains another widget, translates event coordinates to the
// contained widget's coordinates, else returns original event coordinates.
template<class Event> bool GetContainedWidgetEventCoordinates(Event* event,
int* x,
@@ -409,8 +408,9 @@ class WidgetGtk
// for the drag.
const OSExchangeDataProviderGtk* drag_data_;
- // See description above getter for details.
- bool in_paint_now_;
+ // True to enable debug painting. Enabling causes the damaged
+ // region to be painted to flash in red.
+ static bool debug_paint_enabled_;
// Are we active?
bool is_active_;
diff --git a/views/widget/widget_impl.cc b/views/widget/widget_impl.cc
index 9340e5e..365b5b3 100644
--- a/views/widget/widget_impl.cc
+++ b/views/widget/widget_impl.cc
@@ -113,8 +113,8 @@ void WidgetImpl::SetAlwaysOnTop(bool always_on_top) {
NOTIMPLEMENTED();
}
-void WidgetImpl::InvalidateRect(const gfx::Rect& invalid_rect) {
- native_widget_->InvalidateRect(invalid_rect);
+void WidgetImpl::SchedulePaintInRect(const gfx::Rect& invalid_rect) {
+ native_widget_->SchedulePaintInRect(invalid_rect);
}
ThemeProvider* WidgetImpl::GetThemeProvider() const {
@@ -224,10 +224,7 @@ void WidgetImpl::OnNativeWidgetCreated() {
}
void WidgetImpl::OnPaint(gfx::Canvas* canvas) {
- // TODO(beng): replace with root_view_->Paint(canvas);
-#if defined(OS_WIN)
- root_view_->OnPaint(native_widget_->GetNativeView());
-#endif
+ root_view_->Paint(canvas);
}
void WidgetImpl::OnSizeChanged(const gfx::Size& size) {
@@ -299,10 +296,6 @@ gfx::NativeView WidgetImpl::GetNativeView() const {
return native_widget_->GetNativeView();
}
-void WidgetImpl::PaintNow(const gfx::Rect& update_rect) {
- NOTIMPLEMENTED();
-}
-
void WidgetImpl::SetOpacity(unsigned char opacity) {
NOTIMPLEMENTED();
}
diff --git a/views/widget/widget_impl.h b/views/widget/widget_impl.h
index 6cd068a..491d04b 100644
--- a/views/widget/widget_impl.h
+++ b/views/widget/widget_impl.h
@@ -85,7 +85,7 @@ class WidgetImpl : public internal::NativeWidgetListener,
// Causes the specified rectangle to be added to the invalid rectangle for the
// WidgetImpl.
- void InvalidateRect(const gfx::Rect& invalid_rect);
+ void SchedulePaintInRect(const gfx::Rect& rect);
// Returns a ThemeProvider that can be used to provide resources when
// rendering Views associated with this WidgetImpl.
@@ -130,7 +130,6 @@ class WidgetImpl : public internal::NativeWidgetListener,
virtual void MoveAbove(Widget* widget);
virtual void SetShape(gfx::NativeRegion region);
virtual gfx::NativeView GetNativeView() const;
- virtual void PaintNow(const gfx::Rect& update_rect);
virtual void SetOpacity(unsigned char opacity);
virtual RootView* GetRootView();
virtual Widget* GetRootWidget() const;
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
index 8a6e800..ae84d31 100644
--- a/views/widget/widget_win.cc
+++ b/views/widget/widget_win.cc
@@ -217,6 +217,10 @@ void WidgetWin::Init(gfx::NativeView parent, const gfx::Rect& bounds) {
// Sets the RootView as a property, so the automation can introspect windows.
SetNativeWindowProperty(kRootViewWindowProperty, root_view_.get());
+ // We need to add ourselves as a message loop observer so that we can repaint
+ // aggressively if the contents of our window become invalid. Unfortunately
+ // WM_PAINT messages are starved and we get flickery redrawing when resizing
+ // if we do not do this.
MessageLoopForUI::current()->AddObserver(this);
// Windows special DWM window frame requires a special tooltip manager so
@@ -338,65 +342,6 @@ gfx::NativeView WidgetWin::GetNativeView() const {
return WindowImpl::hwnd();
}
-static BOOL CALLBACK EnumChildProcForRedraw(HWND hwnd, LPARAM lparam) {
- DWORD process_id;
- GetWindowThreadProcessId(hwnd, &process_id);
- gfx::Rect invalid_rect = *reinterpret_cast<gfx::Rect*>(lparam);
-
- RECT window_rect;
- GetWindowRect(hwnd, &window_rect);
- invalid_rect.Offset(-window_rect.left, -window_rect.top);
-
- int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME;
- if (process_id == GetCurrentProcessId())
- flags |= RDW_UPDATENOW;
- RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags);
- return TRUE;
-}
-
-void WidgetWin::PaintNow(const gfx::Rect& update_rect) {
- if (use_layered_buffer_) {
- PaintLayeredWindow();
- } else if (root_view_->NeedsPainting(false) && IsWindow()) {
- if (!opaque_ && GetParent()) {
- // We're transparent. Need to force painting to occur from our parent.
- CRect parent_update_rect = update_rect.ToRECT();
- POINT location_in_parent = { 0, 0 };
- ClientToScreen(hwnd(), &location_in_parent);
- ScreenToClient(GetParent(), &location_in_parent);
- parent_update_rect.OffsetRect(location_in_parent);
- RedrawWindow(GetParent(), parent_update_rect, NULL,
- RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
- } else {
- // Paint child windows that are in a different process asynchronously.
- // This prevents a hang in other processes from blocking this process.
-
- // Calculate the invalid rect in screen coordinates before the first
- // RedrawWindow call to the parent HWND, since that will empty update_rect
- // (which comes from a member variable) in the OnPaint call.
- CRect screen_rect_temp;
- GetWindowRect(&screen_rect_temp);
- gfx::Rect screen_rect(screen_rect_temp);
- gfx::Rect invalid_screen_rect = update_rect;
- invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
-
- RedrawWindow(hwnd(), &update_rect.ToRECT(), NULL,
- RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
-
- LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
- EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam);
- }
- // As we were created with a style of WS_CLIPCHILDREN redraw requests may
- // result in an empty paint rect in WM_PAINT (this'll happen if a
- // child HWND completely contains the update _rect). In such a scenario
- // RootView would never get a Paint() and always think it needs to be
- // painted (leading to a steady stream of RedrawWindow requests on every
- // event). For this reason we tell RootView it doesn't need to paint
- // here.
- root_view_->ClearPaintRect();
- }
-}
-
void WidgetWin::SetOpacity(unsigned char opacity) {
layered_alpha_ = static_cast<BYTE>(opacity);
}
@@ -558,6 +503,12 @@ View* WidgetWin::GetDraggedView() {
return dragged_view_;
}
+void WidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
+ // InvalidateRect() expects client coordinates.
+ RECT r = rect.ToRECT();
+ InvalidateRect(hwnd(), &r, FALSE);
+}
+
////////////////////////////////////////////////////////////////////////////////
// MessageLoop::Observer
@@ -565,8 +516,7 @@ void WidgetWin::WillProcessMessage(const MSG& msg) {
}
void WidgetWin::DidProcessMessage(const MSG& msg) {
- if (root_view_->NeedsPainting(true))
- PaintNow(root_view_->GetScheduledPaintRect());
+ RedrawInvalidRect();
}
////////////////////////////////////////////////////////////////////////////////
@@ -639,6 +589,7 @@ LRESULT WidgetWin::OnCreate(CREATESTRUCT* create_struct) {
// Widget::GetWidgetFromNativeView expects the contents of this property
// to be of type Widget, so the cast is necessary.
SetNativeWindowProperty(kWidgetKey, static_cast<Widget*>(this));
+ LayoutRootView();
return 0;
}
@@ -931,7 +882,33 @@ LRESULT WidgetWin::OnNotify(int w_param, NMHDR* l_param) {
}
void WidgetWin::OnPaint(HDC dc) {
- root_view_->OnPaint(hwnd());
+ if (use_layered_buffer_) {
+ RECT r;
+ if (!GetUpdateRect(hwnd(), &r, FALSE))
+ return;
+
+ // We need to clip to the dirty rect ourselves.
+ contents_->save(SkCanvas::kClip_SaveFlag);
+ contents_->ClipRectInt(r.left, r.top, r.right - r.left,
+ r.bottom - r.top);
+ root_view_->Paint(contents_.get());
+ contents_->restore();
+
+ RECT wr;
+ GetWindowRect(&wr);
+ SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
+ POINT position = {wr.left, wr.top};
+ HDC dib_dc = contents_->getTopPlatformDevice().getBitmapDC();
+ POINT zero = {0, 0};
+ 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);
+ ValidateRect(hwnd(), &r);
+ } else {
+ scoped_ptr<gfx::CanvasPaint> canvas(
+ gfx::CanvasPaint::CreateCanvasPaint(hwnd()));
+ root_view_->Paint(canvas->AsCanvas());
+ }
}
LRESULT WidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) {
@@ -1148,9 +1125,6 @@ void WidgetWin::LayoutRootView() {
// complete relayout.
root_view_->SetBounds(0, 0, size.width(), size.height());
root_view_->SchedulePaint();
-
- if (use_layered_buffer_)
- PaintNow(gfx::Rect(0, 0, size.width(), size.height()));
}
void WidgetWin::OnScreenReaderDetected() {
@@ -1189,36 +1163,6 @@ void WidgetWin::SizeContents(const gfx::Size& window_size) {
false));
}
-void WidgetWin::PaintLayeredWindow() {
- // Painting monkeys with our cliprect, so we need to save it so that the
- // call to UpdateLayeredWindow updates the entire window, not just the
- // cliprect.
- contents_->save(SkCanvas::kClip_SaveFlag);
- gfx::Rect dirty_rect = root_view_->GetScheduledPaintRect();
- contents_->ClipRectInt(dirty_rect.x(), dirty_rect.y(), dirty_rect.width(),
- dirty_rect.height());
- root_view_->Paint(contents_.get());
- contents_->restore();
-
- UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
-}
-
-void WidgetWin::UpdateWindowFromContents(HDC dib_dc) {
- DCHECK(use_layered_buffer_);
- if (can_update_layered_window_) {
- CRect wr;
- GetWindowRect(&wr);
- CSize size(wr.right - wr.left, wr.bottom - wr.top);
- CPoint zero_origin(0, 0);
- CPoint window_position = wr.TopLeft();
-
- BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
- UpdateLayeredWindow(
- hwnd(), NULL, &window_position, &size, dib_dc, &zero_origin,
- RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
- }
-}
-
RootView* WidgetWin::GetFocusedViewRootView() {
FocusManager* focus_manager = GetFocusManager();
if (!focus_manager) {
@@ -1349,6 +1293,14 @@ void WidgetWin::MakeMSG(MSG* msg, UINT message, WPARAM w_param,
msg->pt.x = msg->pt.y = 0;
}
+void WidgetWin::RedrawInvalidRect() {
+ RECT r;
+ if (GetUpdateRect(hwnd(), &r, FALSE)) {
+ RedrawWindow(hwnd(), &r, NULL,
+ RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Widget, public:
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
index 2ccde9a..a1d8fc1 100644
--- a/views/widget/widget_win.h
+++ b/views/widget/widget_win.h
@@ -225,7 +225,6 @@ class WidgetWin : public ui::WindowImpl,
virtual void Show();
virtual void Hide();
virtual gfx::NativeView GetNativeView() const;
- virtual void PaintNow(const gfx::Rect& update_rect);
virtual void SetOpacity(unsigned char opacity);
virtual void SetAlwaysOnTop(bool on_top);
virtual RootView* GetRootView();
@@ -251,6 +250,7 @@ class WidgetWin : public ui::WindowImpl,
const OSExchangeData& data,
int operation);
virtual View* GetDraggedView();
+ virtual void SchedulePaintInRect(const gfx::Rect& rect);
// Overridden from MessageLoop::Observer:
void WillProcessMessage(const MSG& msg);
@@ -505,13 +505,6 @@ class WidgetWin : public ui::WindowImpl,
// recreates the entire bitmap.
void SizeContents(const gfx::Size& window_size);
- // Paint into a DIB and then update the layered window with its contents.
- void PaintLayeredWindow();
-
- // In layered mode, update the layered window. |dib_dc| represents a handle
- // to a device context that contains the contents of the window.
- void UpdateWindowFromContents(HDC dib_dc);
-
// Invoked from WM_DESTROY. Does appropriate cleanup and invokes OnDestroy
// so that subclasses can do any cleanup they need to.
// void OnDestroyImpl();
@@ -528,6 +521,9 @@ class WidgetWin : public ui::WindowImpl,
// Fills out a MSG struct with the supplied values.
void MakeMSG(MSG* msg, UINT message, WPARAM w_param, LPARAM l_param) const;
+ // Synchronously paints the invalid contents of the Widget.
+ void RedrawInvalidRect();
+
// The following factory is used for calls to close the WidgetWin
// instance.
ScopedRunnableMethodFactory<WidgetWin> close_widget_factory_;
diff --git a/views/window/window_win.cc b/views/window/window_win.cc
index be578834..239226d 100644
--- a/views/window/window_win.cc
+++ b/views/window/window_win.cc
@@ -854,18 +854,11 @@ void WindowWin::OnMouseLeave() {
LRESULT WindowWin::OnNCActivate(BOOL active) {
is_active_ = !!active;
- // We need to force a synchronous repaint, otherwise we'll be left in the
- // wrong activation state until something else causes a repaint later.
- // Both the native and non-native frames may render activation-state
- // dependent UI.
+ // The frame may need to redraw as a result of the activation change.
// We can get WM_NCACTIVATE before we're actually visible. If we're not
// visible, no need to paint.
- if (IsWindowVisible(GetNativeView())) {
+ if (IsVisible())
non_client_view_->SchedulePaint();
- // We need to force a paint now, as a user dragging a window will block
- // painting operations while the move is in progress.
- PaintNow(root_view_->GetScheduledPaintRect());
- }
// If we're active again, we should be allowed to render as inactive, so
// tell the non-client view. This must be done independently of the check for
@@ -976,114 +969,10 @@ 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 (non_client_view_->UseNativeFrame()) {
- 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() != root_view_->width() ||
- window_rect.Height() != root_view_->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 = GetRootView();
- gfx::Rect old_paint_region =
- root_view->GetScheduledPaintRectConstrainedToSize();
-
- 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);
- }
-
- root_view->SchedulePaintInRect(gfx::Rect(dirty_region), false);
-
- // 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, opaque(), dirty_region.left,
- dirty_region.top, dirty_region.Width(),
- dirty_region.Height());
- root_view->Paint(&canvas);
- }
-
- ReleaseDC(GetNativeView(), dc);
+ // When using a custom frame, we want to avoid calling DefWindowProc() since
+ // that may render artifacts.
+ SetMsgHandled(!non_client_view_->UseNativeFrame());
}
void WindowWin::OnNCLButtonDown(UINT ht_component, const CPoint& point) {