diff options
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) { |