diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 22:11:25 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 22:11:25 +0000 |
commit | cba0bf2355b091a874537a3be99955ae3b29f8b0 (patch) | |
tree | 3b8e889372624c048d49e6706f39f6a7947fb6c3 /views | |
parent | c3ca81c42c4e70a3046d5a0fc68e376aa60c626e (diff) | |
download | chromium_src-cba0bf2355b091a874537a3be99955ae3b29f8b0.zip chromium_src-cba0bf2355b091a874537a3be99955ae3b29f8b0.tar.gz chromium_src-cba0bf2355b091a874537a3be99955ae3b29f8b0.tar.bz2 |
Sort methods in RootView cc/h. Add better documentation and outline future plans.
http://crbug.com/72040
TEST=none
TBR=sky
Review URL: http://codereview.chromium.org/6525024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75018 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/widget/root_view.cc | 750 | ||||
-rw-r--r-- | views/widget/root_view.h | 335 |
2 files changed, 529 insertions, 556 deletions
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc index 3a5ce87..b03338e 100644 --- a/views/widget/root_view.cc +++ b/views/widget/root_view.cc @@ -35,11 +35,8 @@ namespace views { -///////////////////////////////////////////////////////////////////////////// -// -// A Task to trigger non urgent painting. -// -///////////////////////////////////////////////////////////////////////////// +// 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) { @@ -62,45 +59,68 @@ class PaintTask : public Task { DISALLOW_COPY_AND_ASSIGN(PaintTask); }; -const char RootView::kViewClassName[] = "views/RootView"; +namespace { + +#ifndef NDEBUG +// Sets the value of RootView's |is_processing_paint_| member to true as long +// as ProcessPaint 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 - constructors, destructors, initialization -// -///////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// RootView, public: + +// Creation and lifetime ------------------------------------------------------- RootView::RootView(Widget* widget) - : mouse_pressed_handler_(NULL), - mouse_move_handler_(NULL), - last_click_handler_(NULL), - widget_(widget), - ALLOW_THIS_IN_INITIALIZER_LIST(focus_search_(this, false, false)), + : 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), explicit_mouse_handler_(false), #if defined(OS_WIN) previous_cursor_(NULL), #endif default_keyboard_handler_(NULL), + last_mouse_event_flags_(0), + last_mouse_event_x_(-1), + last_mouse_event_y_(-1), +#if defined(TOUCH_UI) + gesture_manager_(GestureManager::GetInstance()), + touch_pressed_handler_(NULL), +#endif + ALLOW_THIS_IN_INITIALIZER_LIST(focus_search_(this, false, false)), focus_on_mouse_pressed_(false), ignore_set_focus_calls_(false), focus_traversable_parent_(NULL), focus_traversable_parent_view_(NULL), - drag_view_(NULL) -#if defined(TOUCH_UI) - , - gesture_manager_(GestureManager::GetInstance()), - touch_pressed_handler_(NULL) -#endif -#ifndef NDEBUG - , - is_processing_paint_(false) -#endif -{ + drag_view_(NULL) { } RootView::~RootView() { @@ -113,6 +133,8 @@ RootView::~RootView() { pending_paint_task_->Cancel(); // Ensure we're not called any more. } +// Tree operations ------------------------------------------------------------- + void RootView::SetContentsView(View* contents_view) { DCHECK(contents_view && GetWidget()->GetNativeView()) << "Can't be called until after the native view is created!"; @@ -130,11 +152,190 @@ void RootView::SetContentsView(View* contents_view) { Layout(); } -///////////////////////////////////////////////////////////////////////////// -// -// RootView - layout, painting -// -///////////////////////////////////////////////////////////////////////////// +void RootView::NotifyNativeViewHierarchyChanged(bool attached, + gfx::NativeView native_view) { + 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() { + if (mouse_pressed_handler_) { + // Synthesize a release event. + MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_mouse_event_x_, + last_mouse_event_y_, last_mouse_event_flags_); + OnMouseReleased(release_event, true); + } +} + +void RootView::ProcessOnMouseExited() { + if (mouse_move_handler_ != NULL) { + MouseEvent exited_event(ui::ET_MOUSE_EXITED, 0, 0, 0); + mouse_move_handler_->OnMouseExited(exited_event); + mouse_move_handler_ = NULL; + } +} + +bool RootView::ProcessKeyEvent(const KeyEvent& event) { + bool consumed = false; + + View* v = GetFocusedView(); + // Special case to handle right-click context menus triggered by the + // keyboard. + if (v && v->IsEnabled() && ((event.key_code() == ui::VKEY_APPS) || + (event.key_code() == ui::VKEY_F10 && event.IsShiftDown()))) { + v->ShowContextMenu(v->GetKeyboardContextMenuLocation(), false); + return true; + } + for (; v && v != this && !consumed; v = v->parent()) { + consumed = (event.type() == ui::ET_KEY_PRESSED) ? + v->OnKeyPressed(event) : v->OnKeyReleased(event); + } + + if (!consumed && default_keyboard_handler_) { + consumed = (event.type() == ui::ET_KEY_PRESSED) ? + default_keyboard_handler_->OnKeyPressed(event) : + default_keyboard_handler_->OnKeyReleased(event); + } + + return consumed; +} + +void RootView::SetDefaultKeyboardHandler(View* v) { + default_keyboard_handler_ = v; +} + +bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) { + View* v; + bool consumed = false; + if (GetFocusedView()) { + for (v = GetFocusedView(); v && v != this && !consumed; v = v->parent()) + consumed = v->OnMouseWheel(e); + } + + if (!consumed && default_keyboard_handler_) { + consumed = default_keyboard_handler_->OnMouseWheel(e); + } + return consumed; +} + +// Focus ----------------------------------------------------------------------- + +void RootView::FocusView(View* view) { + if (view != GetFocusedView()) { + FocusManager* focus_manager = GetFocusManager(); + // TODO(jcampan): This fails under WidgetGtk with TYPE_CHILD. + // (see http://crbug.com/21335) Reenable DCHECK and + // verify GetFocusManager works as expecte. +#if defined(OS_WIN) + DCHECK(focus_manager) << "No Focus Manager for Window " << + (GetWidget() ? GetWidget()->GetNativeView() : 0); +#endif + if (!focus_manager) + return; + focus_manager->SetFocusedView(view); + } +} + +View* RootView::GetFocusedView() { + FocusManager* focus_manager = GetFocusManager(); + if (!focus_manager) { + // We may not have a FocusManager when the window that contains us is being + // deleted. Sadly we cannot wait for the window to be destroyed before we + // remove the FocusManager (see xp_frame.cc for more info). + return NULL; + } + + // Make sure the focused view belongs to this RootView's view hierarchy. + View* view = focus_manager->GetFocusedView(); + if (view && (view->GetRootView() == this)) + return view; + +#if defined(OS_LINUX) + if (view && NativeTextfieldViews::IsTextfieldViewsEnabled()) { + // hack to deal with two root views. + // should be fixed by eliminating one of them + return view; + } +#endif + return NULL; +} + +void RootView::SetFocusOnMousePressed(bool f) { + focus_on_mouse_pressed_ = f; +} + +void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) { + DCHECK(focus_traversable != this); + focus_traversable_parent_ = focus_traversable; +} + +void RootView::SetFocusTraversableParentView(View* view) { + focus_traversable_parent_view_ = view; +} + +// System events --------------------------------------------------------------- + +void RootView::NotifyThemeChanged() { + View::PropagateThemeChanged(); +} + +void RootView::NotifyLocaleChanged() { + View::PropagateLocaleChanged(); +} + +//////////////////////////////////////////////////////////////////////////////// +// RootView, FocusTraversable implementation: + +FocusSearch* RootView::GetFocusSearch() { + return &focus_search_; +} + +FocusTraversable* RootView::GetFocusTraversableParent() { + return focus_traversable_parent_; +} + +View* RootView::GetFocusTraversableParentView() { + return focus_traversable_parent_view_; +} + +//////////////////////////////////////////////////////////////////////////////// +// RootView, View overrides: void RootView::SchedulePaintInRect(const gfx::Rect& r, bool urgent) { // If there is an existing invalid rect, add the union of the scheduled @@ -156,30 +357,6 @@ void RootView::SchedulePaintInRect(const gfx::Rect& r, bool urgent) { } } -void RootView::SchedulePaint() { - View::SchedulePaint(); -} - -#ifndef NDEBUG -// Sets the value of RootView's |is_processing_paint_| member to true as long -// as ProcessPaint 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 - void RootView::ProcessPaint(gfx::Canvas* canvas) { #ifndef NDEBUG ScopedProcessingPaint processing_paint(&is_processing_paint_); @@ -225,35 +402,6 @@ void RootView::PaintNow() { widget->PaintNow(invalid_rect_); } -bool RootView::NeedsPainting(bool urgent) { - bool has_invalid_rect = !invalid_rect_.IsEmpty(); - if (urgent) { - if (invalid_rect_urgent_) - return has_invalid_rect; - else - return false; - } else { - 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()); -} - -///////////////////////////////////////////////////////////////////////////// -// -// RootView - tree -// -///////////////////////////////////////////////////////////////////////////// - const Widget* RootView::GetWidget() const { return widget_; } @@ -262,126 +410,6 @@ Widget* RootView::GetWidget() { return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget()); } -void RootView::NotifyThemeChanged() { - View::PropagateThemeChanged(); -} - -void RootView::NotifyLocaleChanged() { - View::PropagateLocaleChanged(); -} - -///////////////////////////////////////////////////////////////////////////// -// -// RootView - event dispatch and propagation -// -///////////////////////////////////////////////////////////////////////////// - -void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { - if (!is_add) { - if (!explicit_mouse_handler_ && mouse_pressed_handler_ == child) { - mouse_pressed_handler_ = NULL; - } - - if (widget_) - widget_->ViewHierarchyChanged(is_add, parent, child); - - if (mouse_move_handler_ == child) { - mouse_move_handler_ = NULL; - } - - if (GetFocusedView() == child) { - FocusView(NULL); - } - - if (child == drag_view_) - drag_view_ = NULL; - - if (default_keyboard_handler_ == child) { - default_keyboard_handler_ = NULL; - } - -#if defined(TOUCH_UI) - if (touch_pressed_handler_) { - touch_pressed_handler_ = NULL; - } -#endif - - FocusManager* focus_manager = widget_->GetFocusManager(); - // An unparanted RootView does not have a FocusManager. - if (focus_manager) - focus_manager->ViewRemoved(parent, child); - - ViewStorage::GetInstance()->ViewRemoved(parent, child); - } -} - -void RootView::SetFocusOnMousePressed(bool f) { - focus_on_mouse_pressed_ = f; -} - -#if defined(TOUCH_UI) -View::TouchStatus RootView::OnTouchEvent(const TouchEvent& e) { - // If touch_pressed_handler_ is non null, we are currently processing - // a touch down on the screen situation. In that case we send the - // event to touch_pressed_handler_ - View::TouchStatus status = TOUCH_STATUS_UNKNOWN; - - if (touch_pressed_handler_) { - TouchEvent touch_event(e, this, touch_pressed_handler_); - status = touch_pressed_handler_->ProcessTouchEvent(touch_event); - gesture_manager_->ProcessTouchEventForGesture(e, this, status); - if (status == TOUCH_STATUS_END) - touch_pressed_handler_ = NULL; - return status; - } - - // Walk up the tree until we find a view that wants the touch event. - for (touch_pressed_handler_ = GetViewForPoint(e.location()); - touch_pressed_handler_ && (touch_pressed_handler_ != this); - touch_pressed_handler_ = touch_pressed_handler_->parent()) { - if (!touch_pressed_handler_->IsEnabled()) { - // Disabled views eat events but are treated as not handled by the - // the GestureManager. - status = TOUCH_STATUS_UNKNOWN; - break; - } - - // See if this view wants to handle the touch - TouchEvent touch_event(e, this, touch_pressed_handler_); - status = touch_pressed_handler_->ProcessTouchEvent(touch_event); - - // If the touch didn't initiate a touch-sequence, then reset the touch event - // handler. - if (status != TOUCH_STATUS_START) - touch_pressed_handler_ = NULL; - - // The view could have removed itself from the tree when handling - // OnTouchEvent(). So handle as per OnMousePressed. NB: we - // assume that the RootView itself cannot be so removed. - // - // NOTE: Don't return true here, because we don't want the frame to - // forward future events to us when there's no handler. - if (!touch_pressed_handler_) - break; - - // If the view handled the event, leave touch_pressed_handler_ set and - // return true, which will cause subsequent drag/release events to get - // forwarded to that view. - if (status != TOUCH_STATUS_UNKNOWN) { - gesture_manager_->ProcessTouchEventForGesture(e, this, status); - return status; - } - } - - // Reset touch_pressed_handler_ to indicate that no processing is occurring. - touch_pressed_handler_ = NULL; - - // Give the touch event to the gesture manager. - gesture_manager_->ProcessTouchEventForGesture(e, this, status); - return status; -} -#endif - bool RootView::OnMousePressed(const MouseEvent& e) { // This function does not normally handle non-client messages except for // non-client double-clicks. Actually, all double-clicks are special as the @@ -478,43 +506,6 @@ bool RootView::OnMousePressed(const MouseEvent& e) { return hit_disabled_view; } -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 - // window. (a non explicit mouse handler is automatically - // cleared when the control is removed from the hierarchy) - if (explicit_mouse_handler_) { - if (mouse_pressed_handler_->GetWidget()) { - *p = l; - ConvertPointToScreen(this, p); - ConvertPointToView(NULL, mouse_pressed_handler_, p); - } else { - // If the mouse_pressed_handler_ is not connected, we send the - // event in screen coordinate system - *p = l; - ConvertPointToScreen(this, p); - return true; - } - } else { - *p = l; - ConvertPointToView(this, mouse_pressed_handler_, p); - } - return true; -} - -void RootView::UpdateCursor(const MouseEvent& e) { - gfx::NativeCursor cursor = NULL; - View* v = GetViewForPoint(e.location()); - if (v && v != this) { - gfx::Point l(e.location()); - View::ConvertPointToView(this, v, &l); - cursor = v->GetCursorForPoint(e.type(), l); - } - SetActiveCursor(cursor); -} - bool RootView::OnMouseDragged(const MouseEvent& e) { UpdateCursor(e); @@ -587,141 +578,130 @@ void RootView::OnMouseMoved(const MouseEvent& e) { } } -void RootView::ProcessOnMouseExited() { - if (mouse_move_handler_ != NULL) { - MouseEvent exited_event(ui::ET_MOUSE_EXITED, 0, 0, 0); - mouse_move_handler_->OnMouseExited(exited_event); - mouse_move_handler_ = NULL; - } -} - void RootView::SetMouseHandler(View *new_mh) { // If we're clearing the mouse handler, clear explicit_mouse_handler as well. explicit_mouse_handler_ = (new_mh != NULL); mouse_pressed_handler_ = new_mh; } -void RootView::ProcessMouseDragCanceled() { - if (mouse_pressed_handler_) { - // Synthesize a release event. - MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_mouse_event_x_, - last_mouse_event_y_, last_mouse_event_flags_); - OnMouseReleased(release_event, true); - } -} +#if defined(TOUCH_UI) +View::TouchStatus RootView::OnTouchEvent(const TouchEvent& e) { + // If touch_pressed_handler_ is non null, we are currently processing + // a touch down on the screen situation. In that case we send the + // event to touch_pressed_handler_ + View::TouchStatus status = TOUCH_STATUS_UNKNOWN; -void RootView::FocusView(View* view) { - if (view != GetFocusedView()) { - FocusManager* focus_manager = GetFocusManager(); - // TODO(jcampan): This fails under WidgetGtk with TYPE_CHILD. - // (see http://crbug.com/21335) Reenable DCHECK and - // verify GetFocusManager works as expecte. -#if defined(OS_WIN) - DCHECK(focus_manager) << "No Focus Manager for Window " << - (GetWidget() ? GetWidget()->GetNativeView() : 0); -#endif - if (!focus_manager) - return; - focus_manager->SetFocusedView(view); + if (touch_pressed_handler_) { + TouchEvent touch_event(e, this, touch_pressed_handler_); + status = touch_pressed_handler_->ProcessTouchEvent(touch_event); + gesture_manager_->ProcessTouchEventForGesture(e, this, status); + if (status == TOUCH_STATUS_END) + touch_pressed_handler_ = NULL; + return status; } -} -View* RootView::GetFocusedView() { - FocusManager* focus_manager = GetFocusManager(); - if (!focus_manager) { - // We may not have a FocusManager when the window that contains us is being - // deleted. Sadly we cannot wait for the window to be destroyed before we - // remove the FocusManager (see xp_frame.cc for more info). - return NULL; - } + // Walk up the tree until we find a view that wants the touch event. + for (touch_pressed_handler_ = GetViewForPoint(e.location()); + touch_pressed_handler_ && (touch_pressed_handler_ != this); + touch_pressed_handler_ = touch_pressed_handler_->parent()) { + if (!touch_pressed_handler_->IsEnabled()) { + // Disabled views eat events but are treated as not handled by the + // the GestureManager. + status = TOUCH_STATUS_UNKNOWN; + break; + } - // Make sure the focused view belongs to this RootView's view hierarchy. - View* view = focus_manager->GetFocusedView(); - if (view && (view->GetRootView() == this)) - return view; + // See if this view wants to handle the touch + TouchEvent touch_event(e, this, touch_pressed_handler_); + status = touch_pressed_handler_->ProcessTouchEvent(touch_event); -#if defined(OS_LINUX) - if (view && NativeTextfieldViews::IsTextfieldViewsEnabled()) { - // hack to deal with two root views. - // should be fixed by eliminating one of them - return view; + // If the touch didn't initiate a touch-sequence, then reset the touch event + // handler. + if (status != TOUCH_STATUS_START) + touch_pressed_handler_ = NULL; + + // The view could have removed itself from the tree when handling + // OnTouchEvent(). So handle as per OnMousePressed. NB: we + // assume that the RootView itself cannot be so removed. + // + // NOTE: Don't return true here, because we don't want the frame to + // forward future events to us when there's no handler. + if (!touch_pressed_handler_) + break; + + // If the view handled the event, leave touch_pressed_handler_ set and + // return true, which will cause subsequent drag/release events to get + // forwarded to that view. + if (status != TOUCH_STATUS_UNKNOWN) { + gesture_manager_->ProcessTouchEventForGesture(e, this, status); + return status; + } } -#endif - return NULL; -} -FocusSearch* RootView::GetFocusSearch() { - return &focus_search_; -} + // Reset touch_pressed_handler_ to indicate that no processing is occurring. + touch_pressed_handler_ = NULL; -FocusTraversable* RootView::GetFocusTraversableParent() { - return focus_traversable_parent_; + // Give the touch event to the gesture manager. + gesture_manager_->ProcessTouchEventForGesture(e, this, status); + return status; } +#endif -void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) { - DCHECK(focus_traversable != this); - focus_traversable_parent_ = focus_traversable; +bool RootView::IsVisibleInRootView() const { + return IsVisible(); } -View* RootView::GetFocusTraversableParentView() { - return focus_traversable_parent_view_; +std::string RootView::GetClassName() const { + return kViewClassName; } -void RootView::SetFocusTraversableParentView(View* view) { - focus_traversable_parent_view_ = view; +AccessibilityTypes::Role RootView::GetAccessibleRole() { + return AccessibilityTypes::ROLE_APPLICATION; } -void RootView::NotifyNativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view) { - PropagateNativeViewHierarchyChanged(attached, native_view, this); -} +void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { + if (!is_add) { + if (!explicit_mouse_handler_ && mouse_pressed_handler_ == child) { + mouse_pressed_handler_ = NULL; + } -bool RootView::ProcessKeyEvent(const KeyEvent& event) { - bool consumed = false; + if (widget_) + widget_->ViewHierarchyChanged(is_add, parent, child); - View* v = GetFocusedView(); - // Special case to handle right-click context menus triggered by the - // keyboard. - if (v && v->IsEnabled() && ((event.key_code() == ui::VKEY_APPS) || - (event.key_code() == ui::VKEY_F10 && event.IsShiftDown()))) { - v->ShowContextMenu(v->GetKeyboardContextMenuLocation(), false); - return true; - } - for (; v && v != this && !consumed; v = v->parent()) { - consumed = (event.type() == ui::ET_KEY_PRESSED) ? - v->OnKeyPressed(event) : v->OnKeyReleased(event); - } + if (mouse_move_handler_ == child) { + mouse_move_handler_ = NULL; + } - if (!consumed && default_keyboard_handler_) { - consumed = (event.type() == ui::ET_KEY_PRESSED) ? - default_keyboard_handler_->OnKeyPressed(event) : - default_keyboard_handler_->OnKeyReleased(event); - } + if (GetFocusedView() == child) { + FocusView(NULL); + } - return consumed; -} + if (child == drag_view_) + drag_view_ = NULL; -bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) { - View* v; - bool consumed = false; - if (GetFocusedView()) { - for (v = GetFocusedView(); v && v != this && !consumed; v = v->parent()) - consumed = v->OnMouseWheel(e); - } + if (default_keyboard_handler_ == child) { + default_keyboard_handler_ = NULL; + } - if (!consumed && default_keyboard_handler_) { - consumed = default_keyboard_handler_->OnMouseWheel(e); +#if defined(TOUCH_UI) + if (touch_pressed_handler_) { + touch_pressed_handler_ = NULL; + } +#endif + + FocusManager* focus_manager = widget_->GetFocusManager(); + // An unparanted RootView does not have a FocusManager. + if (focus_manager) + focus_manager->ViewRemoved(parent, child); + + ViewStorage::GetInstance()->ViewRemoved(parent, child); } - return consumed; } -void RootView::SetDefaultKeyboardHandler(View* v) { - default_keyboard_handler_ = v; -} +//////////////////////////////////////////////////////////////////////////////// +// RootView, protected: -bool RootView::IsVisibleInRootView() const { - return IsVisible(); -} +// Size and disposition -------------------------------------------------------- void RootView::ViewBoundsChanged(View* view, bool size_changed, bool position_changed) { @@ -759,43 +739,45 @@ void RootView::UnregisterViewForVisibleBoundsNotification(View* view) { } } -void RootView::SetMouseLocationAndFlags(const MouseEvent& e) { - last_mouse_event_flags_ = e.flags(); - last_mouse_event_x_ = e.x(); - last_mouse_event_y_ = e.y(); -} - -std::string RootView::GetClassName() const { - return kViewClassName; -} - -void RootView::ClearPaintRect() { - invalid_rect_.SetRect(0, 0, 0, 0); - - // This painting has been done. Reset the urgent flag. - invalid_rect_urgent_ = false; +// Coordinate conversion ------------------------------------------------------- - // 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; +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 + // window. (a non explicit mouse handler is automatically + // cleared when the control is removed from the hierarchy) + if (explicit_mouse_handler_) { + if (mouse_pressed_handler_->GetWidget()) { + *p = l; + ConvertPointToScreen(this, p); + ConvertPointToView(NULL, mouse_pressed_handler_, p); + } else { + // If the mouse_pressed_handler_ is not connected, we send the + // event in screen coordinate system + *p = l; + ConvertPointToScreen(this, p); + return true; + } + } else { + *p = l; + ConvertPointToView(this, mouse_pressed_handler_, p); + } + return true; } -///////////////////////////////////////////////////////////////////////////// -// -// RootView - accessibility -// -///////////////////////////////////////////////////////////////////////////// - -AccessibilityTypes::Role RootView::GetAccessibleRole() { - return AccessibilityTypes::ROLE_APPLICATION; -} +// Input ----------------------------------------------------------------------- -View* RootView::GetDragView() { - return drag_view_; +void RootView::UpdateCursor(const MouseEvent& e) { + gfx::NativeCursor cursor = NULL; + View* v = GetViewForPoint(e.location()); + if (v && v != this) { + gfx::Point l(e.location()); + View::ConvertPointToView(this, v, &l); + cursor = v->GetCursorForPoint(e.type(), l); + } + SetActiveCursor(cursor); } void RootView::SetActiveCursor(gfx::NativeCursor cursor) { @@ -822,4 +804,16 @@ void RootView::SetActiveCursor(gfx::NativeCursor cursor) { #endif } +void RootView::SetMouseLocationAndFlags(const MouseEvent& e) { + last_mouse_event_flags_ = e.flags(); + last_mouse_event_x_ = e.x(); + last_mouse_event_y_ = e.y(); +} + +// Drag and drop --------------------------------------------------------------- + +View* RootView::GetDragView() { + return drag_view_; +} + } // namespace views diff --git a/views/widget/root_view.h b/views/widget/root_view.h index 680b8a5..ad7273c 100644 --- a/views/widget/root_view.h +++ b/views/widget/root_view.h @@ -21,55 +21,55 @@ namespace views { class PaintTask; class Widget; - #if defined(TOUCH_UI) class GestureManager; #endif -///////////////////////////////////////////////////////////////////////////// -// +//////////////////////////////////////////////////////////////////////////////// // RootView class // -// The RootView is the root of a View hierarchy. A RootView is always the -// first and only child of a Widget. +// The RootView is the root of a View hierarchy. A RootView is attached to a +// Widget. The Widget is responsible for receiving events from the host +// environment, converting them to views-compatible events and then forwarding +// them to the RootView for propagation into the View hierarchy. // -// The RootView manages the View hierarchy's interface with the Widget -// and also maintains the current invalid rect - the region that needs -// repainting. +// A RootView can have only one child, called its "Contents View" which is +// sized to fill the bounds of the RootView (and hence the client area of the +// Widget). Call SetContentsView() after the associated Widget has been +// 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. // -///////////////////////////////////////////////////////////////////////////// class RootView : public View, public FocusTraversable { public: static const char kViewClassName[]; + // Creation and lifetime ----------------------------------------------------- explicit RootView(Widget* widget); - virtual ~RootView(); + // Tree operations ----------------------------------------------------------- + // Sets the "contents view" of the RootView. This is the single child view // that is responsible for laying out the contents of the widget. void SetContentsView(View* contents_view); - // Layout and Painting functions - - // Overridden from View to implement paint scheduling. - virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent); - - // Convenience to schedule the whole view - virtual void SchedulePaint(); - - // Paint this RootView and its child Views. - virtual void ProcessPaint(gfx::Canvas* canvas); + // Called when parent of the host changed. + void NotifyNativeViewHierarchyChanged(bool attached, + gfx::NativeView native_view); - // If the invalid rect is non-empty and there is a pending paint the RootView - // is painted immediately. This is internally invoked as the result of - // invoking SchedulePaint. - virtual void PaintNow(); + // 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. - virtual bool NeedsPainting(bool urgent); + bool NeedsPainting(bool urgent); // Invoked by the Widget to discover what rectangle should be painted. const gfx::Rect& GetScheduledPaintRect(); @@ -77,30 +77,24 @@ class RootView : public View, // Returns the region scheduled to paint clipped to the RootViews bounds. gfx::Rect GetScheduledPaintRectConstrainedToSize(); - // Tree functions - - // Get the Widget that hosts this View. - virtual const Widget* GetWidget() const; - virtual Widget* GetWidget(); + // Clears the region that is schedule to be painted. You nearly never need + // to invoke this. This is primarily intended for Widgets. + void ClearPaintRect(); - // Public API for broadcasting theme change notifications to this View - // hierarchy. - void NotifyThemeChanged(); + // 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 - // Public API for broadcasting locale change notifications to this View - // hierarchy. - void NotifyLocaleChanged(); + // Enables debug painting. See |debug_paint_enabled_| for details. + static void EnableDebugPaint(); - // The following event methods are overridden to propagate event to the - // control tree - virtual bool OnMousePressed(const MouseEvent& e); - virtual bool OnMouseDragged(const MouseEvent& e); - virtual void OnMouseReleased(const MouseEvent& e, bool canceled); - virtual void OnMouseMoved(const MouseEvent& e); - virtual void SetMouseHandler(View* new_mouse_handler); -#if defined(TOUCH_UI) - virtual TouchStatus OnTouchEvent(const TouchEvent& e); -#endif + // Input --------------------------------------------------------------------- // Invoked By the Widget if the mouse drag is interrupted by // the system. Invokes OnMouseReleased with a value of true for canceled. @@ -110,13 +104,6 @@ class RootView : public View, // bounds. virtual void ProcessOnMouseExited(); - // Make the provided view focused. Also make sure that our Widget is focused. - void FocusView(View* view); - - // Returns the View in this RootView hierarchy that has the focus, or NULL if - // no View currently has the focus. - View* GetFocusedView(); - // Process a key event. Send the event to the focused view and up the focus // path, and finally to the default keyboard handler, until someone consumes // it. Returns whether anyone consumed the event. @@ -130,48 +117,11 @@ class RootView : public View, // this a list if needed. void SetDefaultKeyboardHandler(View* v); - // Set whether this root view should focus the corresponding hwnd - // when an unprocessed mouse event occurs. - void SetFocusOnMousePressed(bool f); - // Process a mousewheel event. Return true if the event was processed // and false otherwise. // MouseWheel events are sent on the focus path. virtual bool ProcessMouseWheelEvent(const MouseWheelEvent& e); - // Overridden to handle special root view case. - virtual bool IsVisibleInRootView() const; - - // FocusTraversable implementation. - virtual FocusSearch* GetFocusSearch(); - virtual FocusTraversable* GetFocusTraversableParent(); - virtual View* GetFocusTraversableParentView(); - - // Used to set the FocusTraversable parent after the view has been created - // (typically when the hierarchy changes and this RootView is added/removed). - virtual void SetFocusTraversableParent(FocusTraversable* focus_traversable); - - // Used to set the View parent after the view has been created. - virtual void SetFocusTraversableParentView(View* view); - - // Called when parent of the host changed. - void NotifyNativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view); - - // Returns the name of this class: views/RootView - virtual std::string GetClassName() const; - - // Clears the region that is schedule to be painted. You nearly never need - // to invoke this. This is primarily intended for Widgets. - void ClearPaintRect(); - -#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 - // Starts a drag operation for the specified view. This blocks until done. // If the view has not been deleted during the drag, OnDragDone is invoked // on the view. @@ -180,31 +130,74 @@ class RootView : public View, const OSExchangeData& data, int operation); - // Accessibility accessors/mutators, overridden from View. - virtual AccessibilityTypes::Role GetAccessibleRole(); - #if defined(TOUCH_UI) && defined(UNIT_TEST) // For unit testing purposes, we use this method to set a mock // GestureManager void SetGestureManager(GestureManager* g) { gesture_manager_ = g; } #endif - // Enables debug painting. See |debug_paint_enabled_| for details. - static void EnableDebugPaint(); + // Focus --------------------------------------------------------------------- - protected: + // Make the provided view focused. Also make sure that our Widget is focused. + void FocusView(View* view); - // Overridden to properly reset our event propagation member - // variables when a child is removed - virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + // Returns the View in this RootView hierarchy that has the focus, or NULL if + // no View currently has the focus. + View* GetFocusedView(); + + // Set whether this root view should focus the corresponding hwnd + // when an unprocessed mouse event occurs. + void SetFocusOnMousePressed(bool f); + + // Used to set the FocusTraversable parent after the view has been created + // (typically when the hierarchy changes and this RootView is added/removed). + virtual void SetFocusTraversableParent(FocusTraversable* focus_traversable); + + // Used to set the View parent after the view has been created. + virtual void SetFocusTraversableParentView(View* view); + + // System events ------------------------------------------------------------- + + // Public API for broadcasting theme change notifications to this View + // hierarchy. + void NotifyThemeChanged(); + + // Public API for broadcasting locale change notifications to this View + // hierarchy. + void NotifyLocaleChanged(); + + // Overridden from FocusTraversable: + virtual FocusSearch* GetFocusSearch(); + virtual FocusTraversable* GetFocusTraversableParent(); + virtual View* GetFocusTraversableParentView(); + // Overridden from View: + virtual void SchedulePaintInRect(const gfx::Rect& r, bool urgent); + virtual void ProcessPaint(gfx::Canvas* canvas); + virtual void PaintNow(); + virtual const Widget* GetWidget() const; + virtual Widget* GetWidget(); + virtual bool OnMousePressed(const MouseEvent& e); + virtual bool OnMouseDragged(const MouseEvent& e); + virtual void OnMouseReleased(const MouseEvent& e, bool canceled); + virtual void OnMouseMoved(const MouseEvent& e); + virtual void SetMouseHandler(View* new_mouse_handler); +#if defined(TOUCH_UI) + virtual TouchStatus OnTouchEvent(const TouchEvent& e); +#endif + virtual bool IsVisibleInRootView() const; + virtual std::string GetClassName() const; + virtual AccessibilityTypes::Role GetAccessibleRole(); + + protected: + // Overridden from View: + 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; - friend class PaintTask; #if defined(TOUCH_UI) // Required so the GestureManager can call the Process* entry points @@ -212,83 +205,50 @@ class RootView : public View, friend class GestureManager; #endif - RootView(); + // Size and disposition ------------------------------------------------------ + + // Notification that size and/or position of a view has changed. This + // notifies the appropriate views. + void ViewBoundsChanged(View* view, bool size_changed, bool position_changed); + + // Registers a view for notification when the visible bounds relative to the + // root of a view changes. + void RegisterViewForVisibleBoundsNotification(View* view); + void UnregisterViewForVisibleBoundsNotification(View* view); + + // Coordinate conversion ----------------------------------------------------- // Convert a point to our current mouse handler. Returns false if the // mouse handler is not connected to a Widget. In that case, the // conversion cannot take place and *p is unchanged bool ConvertPointToMouseHandler(const gfx::Point& l, gfx::Point *p); + // Input --------------------------------------------------------------------- + // Update the cursor given a mouse event. This is called by non mouse_move // event handlers to honor the cursor desired by views located under the // cursor during drag operations. void UpdateCursor(const MouseEvent& e); - // Notification that size and/or position of a view has changed. This - // notifies the appropriate views. - void ViewBoundsChanged(View* view, bool size_changed, bool position_changed); - - // Registers a view for notification when the visible bounds relative to the - // root of a view changes. - void RegisterViewForVisibleBoundsNotification(View* view); - void UnregisterViewForVisibleBoundsNotification(View* view); - - // Returns the next focusable view or view containing a FocusTraversable (NULL - // if none was found), starting at the starting_view. - // check_starting_view, can_go_up and can_go_down controls the traversal of - // the views hierarchy. - // skip_group_id specifies a group_id, -1 means no group. All views from a - // group are traversed in one pass. - View* FindNextFocusableViewImpl(View* starting_view, - bool check_starting_view, - bool can_go_up, - bool can_go_down, - int skip_group_id, - FocusTraversable** focus_traversable, - View** focus_traversable_view); - - // Same as FindNextFocusableViewImpl but returns the previous focusable view. - View* FindPreviousFocusableViewImpl(View* starting_view, - bool check_starting_view, - bool can_go_up, - bool can_go_down, - int skip_group_id, - FocusTraversable** focus_traversable, - View** focus_traversable_view); - - // Convenience method that returns true if a view is focusable and does not - // belong to the specified group. - bool IsViewFocusableCandidate(View* v, int skip_group_id); - - // Returns the view selected for the group of the selected view. If the view - // does not belong to a group or if no view is selected in the group, the - // specified view is returned. - static View* FindSelectedViewForGroup(View* view); + // Sets the current cursor, or resets it to the last one if NULL is provided. + void SetActiveCursor(gfx::NativeCursor cursor); // Updates the last_mouse_* fields from e. void SetMouseLocationAndFlags(const MouseEvent& e); + // Drag and drop ------------------------------------------------------------- + // If a view is dragging, this returns it. Otherwise returns NULL. View* GetDragView(); - // Sets the current cursor, or resets it to the last one if NULL is provided. - void SetActiveCursor(gfx::NativeCursor cursor); + ////////////////////////////////////////////////////////////////////////////// - // The view currently handing down - drag - up - View* mouse_pressed_handler_; - - // The view currently handling enter / exit - View* mouse_move_handler_; - - // The last view to handle a mouse click, so that we can determine if - // a double-click lands on the same view as its single-click part. - View* last_click_handler_; + // Tree operations ----------------------------------------------------------- // The host Widget Widget* widget_; - // The focus search algorithm. - FocusSearch focus_search_; + // Painting ------------------------------------------------------------------ // The rectangle that should be painted gfx::Rect invalid_rect_; @@ -304,6 +264,27 @@ class RootView : public View, // 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 + View* mouse_pressed_handler_; + + // The view currently handling enter / exit + View* mouse_move_handler_; + + // The last view to handle a mouse click, so that we can determine if + // a double-click lands on the same view as its single-click part. + View* last_click_handler_; + // true if mouse_handler_ has been explicitly set bool explicit_mouse_handler_; @@ -313,6 +294,25 @@ class RootView : public View, // Default keyboard handler View* default_keyboard_handler_; + // Last position/flag of a mouse press/drag. Used if capture stops and we need + // to synthesize a release. + int last_mouse_event_flags_; + int last_mouse_event_x_; + int last_mouse_event_y_; + +#if defined(TOUCH_UI) + // The gesture_manager_ for this. + GestureManager* gesture_manager_; + + // The view currently handling touch events. + View* touch_pressed_handler_; +#endif + + // Focus --------------------------------------------------------------------- + + // The focus search algorithm. + FocusSearch focus_search_; + // Whether this root view should make our hwnd focused // when an unprocessed mouse press event occurs bool focus_on_mouse_pressed_; @@ -324,12 +324,6 @@ class RootView : public View, // Whether this root view belongs to the current active window. // bool activated_; - // Last position/flag of a mouse press/drag. Used if capture stops and we need - // to synthesize a release. - int last_mouse_event_flags_; - int last_mouse_event_x_; - int last_mouse_event_y_; - // The parent FocusTraversable, used for focus traversal. FocusTraversable* focus_traversable_parent_; @@ -337,6 +331,8 @@ class RootView : public View, // wrapped inside native components, and is used for the focus traversal. View* focus_traversable_parent_view_; + // Drag and drop ------------------------------------------------------------- + // Tracks drag state for a view. View::DragInfo drag_info; @@ -344,24 +340,7 @@ class RootView : public View, // view the drag started from. View* drag_view_; -#if defined(TOUCH_UI) - // The gesture_manager_ for this. - GestureManager* gesture_manager_; - - // The view currently handling touch events. - View* touch_pressed_handler_; -#endif - -#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_; - - DISALLOW_COPY_AND_ASSIGN(RootView); + DISALLOW_IMPLICIT_CONSTRUCTORS(RootView); }; } // namespace views |