Compositor GL + basic views support.
[chromium-blink-merge.git] / views / view.cc
blob72c7f98b106b76e326988463f302e48d2c0b825f
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "views/view.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h"
13 #include "third_party/skia/include/core/SkRect.h"
14 #include "ui/base/accessibility/accessibility_types.h"
15 #include "ui/base/dragdrop/drag_drop_types.h"
16 #include "ui/gfx/canvas_skia.h"
17 #include "ui/gfx/compositor/compositor.h"
18 #include "ui/gfx/path.h"
19 #include "ui/gfx/transform.h"
20 #include "views/background.h"
21 #include "views/layout/layout_manager.h"
22 #include "views/views_delegate.h"
23 #include "views/widget/native_widget.h"
24 #include "views/widget/root_view.h"
25 #include "views/widget/tooltip_manager.h"
26 #include "views/widget/widget.h"
27 #include "views/window/window.h"
29 #if defined(OS_WIN)
30 #include "base/win/scoped_gdi_object.h"
31 #include "views/accessibility/native_view_accessibility_win.h"
32 #endif
33 #if defined(OS_LINUX)
34 #include "ui/base/gtk/scoped_handle_gtk.h"
35 #endif
37 namespace {
38 // Whether to use accelerated compositing when necessary (e.g. when a view has a
39 // transformation).
40 bool use_acceleration_when_possible = true;
42 // Saves the drawing state, and restores the state when going out of scope.
43 class ScopedCanvas {
44 public:
45 explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) {
46 if (canvas_)
47 canvas_->Save();
49 ~ScopedCanvas() {
50 if (canvas_)
51 canvas_->Restore();
53 void SetCanvas(gfx::Canvas* canvas) {
54 if (canvas_)
55 canvas_->Restore();
56 canvas_ = canvas;
57 canvas_->Save();
60 private:
61 gfx::Canvas* canvas_;
63 DISALLOW_COPY_AND_ASSIGN(ScopedCanvas);
68 namespace views {
70 // static
71 ViewsDelegate* ViewsDelegate::views_delegate = NULL;
73 // static
74 char View::kViewClassName[] = "views/View";
76 ////////////////////////////////////////////////////////////////////////////////
77 // View, public:
79 // TO BE MOVED -----------------------------------------------------------------
81 void View::SetHotTracked(bool flag) {
84 bool View::IsHotTracked() const {
85 return false;
88 // FATE TBD --------------------------------------------------------------------
90 Widget* View::child_widget() {
91 return NULL;
94 // Creation and lifetime -------------------------------------------------------
96 View::View()
97 : enabled_(true),
98 id_(0),
99 group_(-1),
100 focusable_(false),
101 accessibility_focusable_(false),
102 is_parent_owned_(true),
103 parent_(NULL),
104 is_visible_(true),
105 registered_for_visible_bounds_notification_(false),
106 clip_x_(0.0),
107 clip_y_(0.0),
108 needs_layout_(true),
109 flip_canvas_on_paint_for_rtl_ui_(false),
110 #if !defined(COMPOSITOR_2)
111 texture_id_(0), // TODO(sadrul): 0 can be a valid texture id.
112 #endif
113 texture_needs_updating_(true),
114 accelerator_registration_delayed_(false),
115 accelerator_focus_manager_(NULL),
116 registered_accelerator_count_(0),
117 next_focusable_view_(NULL),
118 previous_focusable_view_(NULL),
119 context_menu_controller_(NULL),
120 drag_controller_(NULL) {
123 View::~View() {
124 if (parent_)
125 parent_->RemoveChildView(this);
127 int c = static_cast<int>(children_.size());
128 while (--c >= 0) {
129 children_[c]->SetParent(NULL);
130 if (children_[c]->IsParentOwned())
131 delete children_[c];
134 #if defined(OS_WIN)
135 if (native_view_accessibility_win_.get())
136 native_view_accessibility_win_->set_view(NULL);
137 #endif
140 // Tree operations -------------------------------------------------------------
142 const Widget* View::GetWidget() const {
143 // The root view holds a reference to this view hierarchy's Widget.
144 return parent_ ? parent_->GetWidget() : NULL;
147 Widget* View::GetWidget() {
148 return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget());
151 void View::AddChildView(View* view) {
152 AddChildViewAt(view, child_count());
155 void View::AddChildViewAt(View* view, int index) {
156 CHECK(view != this) << "You cannot add a view as its own child";
158 // Remove the view from its current parent if any.
159 if (view->parent())
160 view->parent()->RemoveChildView(view);
162 // Sets the prev/next focus views.
163 InitFocusSiblings(view, index);
165 // Let's insert the view.
166 children_.insert(children_.begin() + index, view);
167 view->SetParent(this);
169 for (View* p = this; p; p = p->parent())
170 p->ViewHierarchyChangedImpl(false, true, this, view);
172 view->PropagateAddNotifications(this, view);
173 UpdateTooltip();
174 if (GetWidget())
175 RegisterChildrenForVisibleBoundsNotification(view);
177 if (layout_manager_.get())
178 layout_manager_->ViewAdded(this, view);
181 void View::RemoveChildView(View* view) {
182 DoRemoveChildView(view, true, true, false);
185 void View::RemoveAllChildViews(bool delete_views) {
186 ViewVector::iterator iter;
187 while ((iter = children_.begin()) != children_.end())
188 DoRemoveChildView(*iter, false, false, delete_views);
189 UpdateTooltip();
192 const View* View::GetChildViewAt(int index) const {
193 return index < child_count() ? children_[index] : NULL;
196 View* View::GetChildViewAt(int index) {
197 return
198 const_cast<View*>(const_cast<const View*>(this)->GetChildViewAt(index));
201 bool View::Contains(const View* view) const {
202 for (const View* v = view; v; v = v->parent_) {
203 if (v == this)
204 return true;
206 return false;
209 int View::GetIndexOf(const View* view) const {
210 ViewVector::const_iterator it = std::find(children_.begin(), children_.end(),
211 view);
212 return it != children_.end() ? it - children_.begin() : -1;
215 // TODO(beng): remove
216 const Window* View::GetWindow() const {
217 const Widget* widget = GetWidget();
218 return widget ? widget->GetContainingWindow() : NULL;
221 // TODO(beng): remove
222 Window* View::GetWindow() {
223 return const_cast<Window*>(const_cast<const View*>(this)->GetWindow());
226 // TODO(beng): remove
227 bool View::ContainsNativeView(gfx::NativeView native_view) const {
228 for (int i = 0, count = child_count(); i < count; ++i) {
229 if (GetChildViewAt(i)->ContainsNativeView(native_view))
230 return true;
232 return false;
235 // TODO(beng): remove
236 RootView* View::GetRootView() {
237 Widget* widget = GetWidget();
238 return widget ? widget->GetRootView() : NULL;
241 // Size and disposition --------------------------------------------------------
243 void View::SetBounds(int x, int y, int width, int height) {
244 SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height)));
247 void View::SetBoundsRect(const gfx::Rect& bounds) {
248 if (bounds == bounds_) {
249 if (needs_layout_) {
250 needs_layout_ = false;
251 Layout();
252 SchedulePaint();
254 return;
257 gfx::Rect prev = bounds_;
258 bounds_ = bounds;
259 BoundsChanged(prev);
262 void View::SetSize(const gfx::Size& size) {
263 SetBounds(x(), y(), size.width(), size.height());
266 void View::SetPosition(const gfx::Point& position) {
267 SetBounds(position.x(), position.y(), width(), height());
270 void View::SetX(int x) {
271 SetBounds(x, y(), width(), height());
274 void View::SetY(int y) {
275 SetBounds(x(), y, width(), height());
278 gfx::Rect View::GetContentsBounds() const {
279 gfx::Rect contents_bounds(GetLocalBounds());
280 if (border_.get()) {
281 gfx::Insets insets;
282 border_->GetInsets(&insets);
283 contents_bounds.Inset(insets);
285 return contents_bounds;
288 gfx::Rect View::GetLocalBounds() const {
289 return gfx::Rect(0, 0, width(), height());
292 gfx::Insets View::GetInsets() const {
293 gfx::Insets insets;
294 if (border_.get())
295 border_->GetInsets(&insets);
296 return insets;
299 gfx::Rect View::GetVisibleBounds() {
300 if (!IsVisibleInRootView())
301 return gfx::Rect();
302 gfx::Rect vis_bounds(0, 0, width(), height());
303 gfx::Rect ancestor_bounds;
304 View* view = this;
305 int root_x = 0;
306 int root_y = 0;
307 while (view != NULL && !vis_bounds.IsEmpty()) {
308 root_x += view->GetMirroredX();
309 root_y += view->y();
310 vis_bounds.Offset(view->GetMirroredX(), view->y());
311 View* ancestor = view->parent();
312 if (ancestor != NULL) {
313 ancestor_bounds.SetRect(0, 0, ancestor->width(),
314 ancestor->height());
315 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
316 } else if (!view->GetWidget()) {
317 // If the view has no Widget, we're not visible. Return an empty rect.
318 return gfx::Rect();
320 view = ancestor;
322 if (vis_bounds.IsEmpty())
323 return vis_bounds;
324 // Convert back to this views coordinate system.
325 vis_bounds.Offset(-root_x, -root_y);
326 return vis_bounds;
329 gfx::Rect View::GetScreenBounds() const {
330 gfx::Point origin;
331 View::ConvertPointToScreen(this, &origin);
332 return gfx::Rect(origin, size());
335 gfx::Size View::GetPreferredSize() {
336 if (layout_manager_.get())
337 return layout_manager_->GetPreferredSize(this);
338 return gfx::Size();
341 int View::GetBaseline() {
342 return -1;
345 void View::SizeToPreferredSize() {
346 gfx::Size prefsize = GetPreferredSize();
347 if ((prefsize.width() != width()) || (prefsize.height() != height()))
348 SetBounds(x(), y(), prefsize.width(), prefsize.height());
351 gfx::Size View::GetMinimumSize() {
352 return GetPreferredSize();
355 int View::GetHeightForWidth(int w) {
356 if (layout_manager_.get())
357 return layout_manager_->GetPreferredHeightForWidth(this, w);
358 return GetPreferredSize().height();
361 void View::SetVisible(bool flag) {
362 if (flag != is_visible_) {
363 // If the tab is currently visible, schedule paint to
364 // refresh parent
365 if (IsVisible())
366 SchedulePaint();
367 else
368 ResetTexture();
370 is_visible_ = flag;
372 // This notifies all sub-views recursively.
373 PropagateVisibilityNotifications(this, flag);
375 // If we are newly visible, schedule paint.
376 if (IsVisible())
377 SchedulePaint();
381 bool View::IsVisible() const {
382 return is_visible_;
385 bool View::IsVisibleInRootView() const {
386 return IsVisible() && parent() ? parent()->IsVisibleInRootView() : false;
389 void View::SetEnabled(bool state) {
390 if (enabled_ != state) {
391 enabled_ = state;
392 SchedulePaint();
396 bool View::IsEnabled() const {
397 return enabled_;
400 // Transformations -------------------------------------------------------------
402 const ui::Transform& View::GetTransform() const {
403 static const ui::Transform* no_op = new ui::Transform;
404 if (transform_.get())
405 return *transform_.get();
406 return *no_op;
409 void View::SetTransform(const ui::Transform& transform) {
410 if (!transform.HasChange()) {
411 if (!transform_.get())
412 return;
413 transform_.reset(NULL);
414 #if !defined(COMPOSITOR_2)
415 canvas_.reset();
416 #else
417 texture_.reset();
418 #endif
419 SchedulePaint();
420 } else {
421 transform_.reset(new ui::Transform(transform));
422 // TODO: this needs to trigger a paint on the widget. It shouldn't use
423 // SchedulePaint as we don't want to mark the views dirty.
427 // RTL positioning -------------------------------------------------------------
429 gfx::Rect View::GetMirroredBounds() const {
430 gfx::Rect bounds(bounds_);
431 bounds.set_x(GetMirroredX());
432 return bounds;
435 gfx::Point View::GetMirroredPosition() const {
436 return gfx::Point(GetMirroredX(), y());
439 int View::GetMirroredX() const {
440 return parent() ? parent()->GetMirroredXForRect(bounds_) : x();
443 int View::GetMirroredXForRect(const gfx::Rect& bounds) const {
444 return base::i18n::IsRTL() ?
445 (width() - bounds.x() - bounds.width()) : bounds.x();
448 int View::GetMirroredXInView(int x) const {
449 return base::i18n::IsRTL() ? width() - x : x;
452 int View::GetMirroredXWithWidthInView(int x, int w) const {
453 return base::i18n::IsRTL() ? width() - x - w : x;
456 // Layout ----------------------------------------------------------------------
458 void View::Layout() {
459 needs_layout_ = false;
461 // If we have a layout manager, let it handle the layout for us.
462 if (layout_manager_.get())
463 layout_manager_->Layout(this);
465 // Make sure to propagate the Layout() call to any children that haven't
466 // received it yet through the layout manager and need to be laid out. This
467 // is needed for the case when the child requires a layout but its bounds
468 // weren't changed by the layout manager. If there is no layout manager, we
469 // just propagate the Layout() call down the hierarchy, so whoever receives
470 // the call can take appropriate action.
471 for (int i = 0, count = child_count(); i < count; ++i) {
472 View* child = GetChildViewAt(i);
473 if (child->needs_layout_ || !layout_manager_.get()) {
474 child->needs_layout_ = false;
475 child->Layout();
480 void View::InvalidateLayout() {
481 // Always invalidate up. This is needed to handle the case of us already being
482 // valid, but not our parent.
483 needs_layout_ = true;
484 if (parent_)
485 parent_->InvalidateLayout();
488 LayoutManager* View::GetLayoutManager() const {
489 return layout_manager_.get();
492 void View::SetLayoutManager(LayoutManager* layout_manager) {
493 if (layout_manager_.get())
494 layout_manager_->Uninstalled(this);
496 layout_manager_.reset(layout_manager);
497 if (layout_manager_.get())
498 layout_manager_->Installed(this);
501 // Attributes ------------------------------------------------------------------
503 std::string View::GetClassName() const {
504 return kViewClassName;
507 View* View::GetAncestorWithClassName(const std::string& name) {
508 for (View* view = this; view; view = view->parent()) {
509 if (view->GetClassName() == name)
510 return view;
512 return NULL;
515 const View* View::GetViewByID(int id) const {
516 if (id == id_)
517 return const_cast<View*>(this);
519 for (int i = 0, count = child_count(); i < count; ++i) {
520 const View* view = GetChildViewAt(i)->GetViewByID(id);
521 if (view)
522 return view;
524 return NULL;
527 View* View::GetViewByID(int id) {
528 return const_cast<View*>(const_cast<const View*>(this)->GetViewByID(id));
531 void View::SetID(int id) {
532 id_ = id;
535 int View::GetID() const {
536 return id_;
539 void View::SetGroup(int gid) {
540 // Don't change the group id once it's set.
541 DCHECK(group_ == -1 || group_ == gid);
542 group_ = gid;
545 int View::GetGroup() const {
546 return group_;
549 bool View::IsGroupFocusTraversable() const {
550 return true;
553 void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
554 if (group_ == group_id)
555 out->push_back(this);
557 for (int i = 0, count = child_count(); i < count; ++i)
558 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
561 View* View::GetSelectedViewForGroup(int group_id) {
562 std::vector<View*> views;
563 GetWidget()->GetRootView()->GetViewsWithGroup(group_id, &views);
564 return views.empty() ? NULL : views[0];
567 // Coordinate conversion -------------------------------------------------------
569 // static
570 void View::ConvertPointToView(const View* src,
571 const View* dst,
572 gfx::Point* point) {
573 ConvertPointToView(src, dst, point, true);
576 // static
577 void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
578 DCHECK(src);
579 DCHECK(p);
581 src->ConvertPointForAncestor(NULL, p);
584 // static
585 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
586 DCHECK(dest);
587 DCHECK(p);
589 dest->ConvertPointFromAncestor(NULL, p);
592 // static
593 void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
594 DCHECK(src);
595 DCHECK(p);
597 // If the view is not connected to a tree, there's nothing we can do.
598 const Widget* widget = src->GetWidget();
599 if (widget) {
600 ConvertPointToWidget(src, p);
601 gfx::Rect r = widget->GetClientAreaScreenBounds();
602 p->SetPoint(p->x() + r.x(), p->y() + r.y());
606 gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
607 if (!transform_.get() || !transform_->HasChange())
608 return rect;
609 gfx::Rect x_rect = rect;
610 transform_->TransformRect(&x_rect);
611 return x_rect;
614 // Painting --------------------------------------------------------------------
616 void View::SchedulePaint() {
617 SchedulePaintInRect(GetLocalBounds());
620 void View::SchedulePaintInRect(const gfx::Rect& rect) {
621 if (!IsVisible())
622 return;
624 if (parent_) {
625 // Translate the requested paint rect to the parent's coordinate system
626 // then pass this notification up to the parent.
627 gfx::Rect paint_rect = ConvertRectToParent(rect);
628 paint_rect.Offset(GetMirroredPosition());
629 parent_->SchedulePaintInRect(paint_rect);
633 void View::Paint(gfx::Canvas* canvas) {
634 if (!IsVisible())
635 return;
637 ScopedCanvas scoped_canvas(NULL);
638 scoped_ptr<gfx::Canvas> texture_canvas;
639 gfx::Rect texture_rect;
641 #if !defined(COMPOSITOR_2)
642 if (use_acceleration_when_possible &&
643 transform_.get() && transform_->HasChange()) {
644 // This view has a transformation. So this maintains its own canvas.
645 if (!canvas_.get())
646 canvas_.reset(gfx::Canvas::CreateCanvas(width(), height(), false));
647 #else
648 if (ShouldPaintToTexture()) {
649 gfx::Rect dirty_rect;
650 if (!texture_clip_rect_.IsEmpty()) {
651 dirty_rect = texture_clip_rect_;
652 } else {
653 // TODO: clip against dirty rect of canvas (if canvas is non-null).
654 dirty_rect = gfx::Rect(0, 0, width(), height());
656 if (dirty_rect.IsEmpty())
657 return;
659 if (!texture_.get())
660 texture_.reset(GetCompositor()->CreateTexture());
662 if (!texture_needs_updating_) {
663 // We don't need to be painted. Iterate over descendants in case one of
664 // them is dirty.
665 PaintToTexture(dirty_rect);
666 return;
669 texture_canvas.reset(gfx::Canvas::CreateCanvas(dirty_rect.width(),
670 dirty_rect.height(), false));
671 texture_canvas->AsCanvasSkia()->drawColor(
672 SK_ColorBLACK, SkXfermode::kClear_Mode);
673 texture_canvas->TranslateInt(-dirty_rect.x(), -dirty_rect.y());
674 canvas = texture_canvas.get();
675 texture_rect = dirty_rect;
676 // TODO: set texture_needs_updating_ to false.
677 #endif
678 } else {
679 // We're going to modify the canvas, save its state first.
680 scoped_canvas.SetCanvas(canvas);
682 // Paint this View and its children, setting the clip rect to the bounds
683 // of this View and translating the origin to the local bounds' top left
684 // point.
686 // Note that the X (or left) position we pass to ClipRectInt takes into
687 // consideration whether or not the view uses a right-to-left layout so that
688 // we paint our view in its mirrored position if need be.
689 if (!canvas->ClipRectInt(GetMirroredX(), y(),
690 width() - static_cast<int>(clip_x_),
691 height() - static_cast<int>(clip_y_))) {
692 return;
694 // Non-empty clip, translate the graphics such that 0,0 corresponds to
695 // where this view is located (related to its parent).
696 canvas->TranslateInt(GetMirroredX(), y());
698 if (transform_.get() && transform_->HasChange())
699 canvas->Transform(*transform_.get());
703 // If the View we are about to paint requested the canvas to be flipped, we
704 // should change the transform appropriately.
705 // The canvas mirroring is undone once the View is done painting so that we
706 // don't pass the canvas with the mirrored transform to Views that didn't
707 // request the canvas to be flipped.
709 ScopedCanvas scoped(canvas);
710 if (FlipCanvasOnPaintForRTLUI()) {
711 canvas->TranslateInt(width(), 0);
712 canvas->ScaleInt(-1, 1);
715 OnPaint(canvas);
718 PaintChildren(canvas);
720 #if !defined(COMPOSITOR_2)
721 if (canvas == canvas_.get()) {
722 texture_id_ = canvas->GetTextureID();
724 // TODO(sadrul): Make sure the Widget's compositor tree updates itself?
726 #else
727 if (texture_canvas.get()) {
728 texture_->SetBitmap(
729 texture_canvas->AsCanvasSkia()->getDevice()->accessBitmap(false),
730 texture_rect.origin(),
731 size());
733 #endif
736 ThemeProvider* View::GetThemeProvider() const {
737 const Widget* widget = GetWidget();
738 return widget ? widget->GetThemeProvider() : NULL;
741 // Accelerated Painting --------------------------------------------------------
743 // static
744 void View::set_use_acceleration_when_possible(bool use) {
745 use_acceleration_when_possible = use;
748 // Input -----------------------------------------------------------------------
750 View* View::GetEventHandlerForPoint(const gfx::Point& point) {
751 // Walk the child Views recursively looking for the View that most
752 // tightly encloses the specified point.
753 for (int i = child_count() - 1; i >= 0; --i) {
754 View* child = GetChildViewAt(i);
755 if (!child->IsVisible())
756 continue;
758 gfx::Point point_in_child_coords(point);
759 View::ConvertPointToView(this, child, &point_in_child_coords);
760 if (child->HitTest(point_in_child_coords))
761 return child->GetEventHandlerForPoint(point_in_child_coords);
763 return this;
766 gfx::NativeCursor View::GetCursor(const MouseEvent& event) {
767 #if defined(OS_WIN)
768 static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
769 return arrow;
770 #else
771 return NULL;
772 #endif
775 bool View::HitTest(const gfx::Point& l) const {
776 if (GetLocalBounds().Contains(l)) {
777 if (HasHitTestMask()) {
778 gfx::Path mask;
779 GetHitTestMask(&mask);
780 // TODO: can this use SkRegion's contains instead?
781 #if defined(OS_WIN)
782 base::win::ScopedRegion rgn(mask.CreateNativeRegion());
783 return !!PtInRegion(rgn, l.x(), l.y());
784 #elif defined(TOOLKIT_USES_GTK)
785 ui::ScopedRegion rgn(mask.CreateNativeRegion());
786 return gdk_region_point_in(rgn.Get(), l.x(), l.y());
787 #endif
789 // No mask, but inside our bounds.
790 return true;
792 // Outside our bounds.
793 return false;
796 bool View::OnMousePressed(const MouseEvent& event) {
797 return false;
800 bool View::OnMouseDragged(const MouseEvent& event) {
801 return false;
804 void View::OnMouseReleased(const MouseEvent& event) {
807 void View::OnMouseCaptureLost() {
810 void View::OnMouseMoved(const MouseEvent& event) {
813 void View::OnMouseEntered(const MouseEvent& event) {
816 void View::OnMouseExited(const MouseEvent& event) {
819 #if defined(TOUCH_UI)
820 View::TouchStatus View::OnTouchEvent(const TouchEvent& event) {
821 DVLOG(1) << "visited the OnTouchEvent";
822 return TOUCH_STATUS_UNKNOWN;
824 #endif
826 void View::SetMouseHandler(View *new_mouse_handler) {
827 // It is valid for new_mouse_handler to be NULL
828 if (parent_)
829 parent_->SetMouseHandler(new_mouse_handler);
832 bool View::OnKeyPressed(const KeyEvent& event) {
833 return false;
836 bool View::OnKeyReleased(const KeyEvent& event) {
837 return false;
840 bool View::OnMouseWheel(const MouseWheelEvent& event) {
841 return false;
844 TextInputClient* View::GetTextInputClient() {
845 return NULL;
848 InputMethod* View::GetInputMethod() {
849 Widget* widget = GetWidget();
850 return widget ? widget->GetInputMethod() : NULL;
853 // Accelerators ----------------------------------------------------------------
855 void View::AddAccelerator(const Accelerator& accelerator) {
856 if (!accelerators_.get())
857 accelerators_.reset(new std::vector<Accelerator>());
859 std::vector<Accelerator>::iterator iter =
860 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
861 DCHECK(iter == accelerators_->end())
862 << "Registering the same accelerator multiple times";
864 accelerators_->push_back(accelerator);
865 RegisterPendingAccelerators();
868 void View::RemoveAccelerator(const Accelerator& accelerator) {
869 std::vector<Accelerator>::iterator iter;
870 if (!accelerators_.get() ||
871 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
872 accelerator)) == accelerators_->end())) {
873 NOTREACHED() << "Removing non-existing accelerator";
874 return;
877 size_t index = iter - accelerators_->begin();
878 accelerators_->erase(iter);
879 if (index >= registered_accelerator_count_) {
880 // The accelerator is not registered to FocusManager.
881 return;
883 --registered_accelerator_count_;
885 // Providing we are attached to a Widget and registered with a focus manager,
886 // we should de-register from that focus manager now.
887 if (GetWidget() && accelerator_focus_manager_)
888 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
891 void View::ResetAccelerators() {
892 if (accelerators_.get())
893 UnregisterAccelerators(false);
896 bool View::AcceleratorPressed(const Accelerator& accelerator) {
897 return false;
900 // Focus -----------------------------------------------------------------------
902 bool View::HasFocus() {
903 FocusManager* focus_manager = GetFocusManager();
904 if (focus_manager)
905 return focus_manager->GetFocusedView() == this;
906 return false;
909 View* View::GetNextFocusableView() {
910 return next_focusable_view_;
913 const View* View::GetNextFocusableView() const {
914 return next_focusable_view_;
917 View* View::GetPreviousFocusableView() {
918 return previous_focusable_view_;
921 void View::SetNextFocusableView(View* view) {
922 view->previous_focusable_view_ = this;
923 next_focusable_view_ = view;
926 void View::SetFocusable(bool focusable) {
927 focusable_ = focusable;
930 bool View::IsFocusableInRootView() const {
931 return IsFocusable() && IsVisibleInRootView();
934 bool View::IsAccessibilityFocusableInRootView() const {
935 return (focusable_ || accessibility_focusable_) && IsEnabled() &&
936 IsVisibleInRootView();
939 void View::set_accessibility_focusable(bool accessibility_focusable) {
940 accessibility_focusable_ = accessibility_focusable;
943 FocusManager* View::GetFocusManager() {
944 Widget* widget = GetWidget();
945 return widget ? widget->GetFocusManager() : NULL;
948 void View::RequestFocus() {
949 FocusManager* focus_manager = GetFocusManager();
950 if (focus_manager && IsFocusableInRootView())
951 focus_manager->SetFocusedView(this);
954 bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) {
955 return false;
958 FocusTraversable* View::GetFocusTraversable() {
959 return NULL;
962 FocusTraversable* View::GetPaneFocusTraversable() {
963 return NULL;
966 // Tooltips --------------------------------------------------------------------
968 bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
969 return false;
972 bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) {
973 return false;
976 // Context menus ---------------------------------------------------------------
978 void View::SetContextMenuController(ContextMenuController* menu_controller) {
979 context_menu_controller_ = menu_controller;
982 void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) {
983 if (!context_menu_controller_)
984 return;
986 context_menu_controller_->ShowContextMenuForView(this, p, is_mouse_gesture);
989 // Drag and drop ---------------------------------------------------------------
991 void View::SetDragController(DragController* drag_controller) {
992 drag_controller_ = drag_controller;
995 DragController* View::GetDragController() {
996 return drag_controller_;
999 bool View::GetDropFormats(
1000 int* formats,
1001 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1002 return false;
1005 bool View::AreDropTypesRequired() {
1006 return false;
1009 bool View::CanDrop(const OSExchangeData& data) {
1010 // TODO(sky): when I finish up migration, this should default to true.
1011 return false;
1014 void View::OnDragEntered(const DropTargetEvent& event) {
1017 int View::OnDragUpdated(const DropTargetEvent& event) {
1018 return ui::DragDropTypes::DRAG_NONE;
1021 void View::OnDragExited() {
1024 int View::OnPerformDrop(const DropTargetEvent& event) {
1025 return ui::DragDropTypes::DRAG_NONE;
1028 void View::OnDragDone() {
1031 // static
1032 bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1033 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1034 abs(delta_y) > GetVerticalDragThreshold());
1037 // Scrolling -------------------------------------------------------------------
1039 void View::ScrollRectToVisible(const gfx::Rect& rect) {
1040 // We must take RTL UI mirroring into account when adjusting the position of
1041 // the region.
1042 if (parent()) {
1043 gfx::Rect scroll_rect(rect);
1044 scroll_rect.Offset(GetMirroredX(), y());
1045 parent()->ScrollRectToVisible(scroll_rect);
1049 int View::GetPageScrollIncrement(ScrollView* scroll_view,
1050 bool is_horizontal, bool is_positive) {
1051 return 0;
1054 int View::GetLineScrollIncrement(ScrollView* scroll_view,
1055 bool is_horizontal, bool is_positive) {
1056 return 0;
1059 ////////////////////////////////////////////////////////////////////////////////
1060 // View, protected:
1062 // Size and disposition --------------------------------------------------------
1064 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1067 void View::PreferredSizeChanged() {
1068 InvalidateLayout();
1069 if (parent_)
1070 parent_->ChildPreferredSizeChanged(this);
1073 bool View::NeedsNotificationWhenVisibleBoundsChange() const {
1074 return false;
1077 void View::OnVisibleBoundsChanged() {
1080 // Tree operations -------------------------------------------------------------
1082 void View::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
1085 void View::VisibilityChanged(View* starting_from, bool is_visible) {
1088 void View::NativeViewHierarchyChanged(bool attached,
1089 gfx::NativeView native_view,
1090 RootView* root_view) {
1091 FocusManager* focus_manager = GetFocusManager();
1092 if (!accelerator_registration_delayed_ &&
1093 accelerator_focus_manager_ &&
1094 accelerator_focus_manager_ != focus_manager) {
1095 UnregisterAccelerators(true);
1096 accelerator_registration_delayed_ = true;
1098 if (accelerator_registration_delayed_ && attached) {
1099 if (focus_manager) {
1100 RegisterPendingAccelerators();
1101 accelerator_registration_delayed_ = false;
1106 // Painting --------------------------------------------------------------------
1108 void View::PaintChildren(gfx::Canvas* canvas) {
1109 for (int i = 0, count = child_count(); i < count; ++i) {
1110 View* child = GetChildViewAt(i);
1111 if (!child) {
1112 NOTREACHED() << "Should not have a NULL child View for index in bounds";
1113 continue;
1115 child->Paint(canvas);
1119 void View::OnPaint(gfx::Canvas* canvas) {
1120 OnPaintBackground(canvas);
1121 OnPaintFocusBorder(canvas);
1122 OnPaintBorder(canvas);
1125 void View::OnPaintBackground(gfx::Canvas* canvas) {
1126 if (background_.get())
1127 background_->Paint(canvas, this);
1130 void View::OnPaintBorder(gfx::Canvas* canvas) {
1131 if (border_.get())
1132 border_->Paint(*this, canvas);
1135 void View::OnPaintFocusBorder(gfx::Canvas* canvas) {
1136 if ((IsFocusable() || IsAccessibilityFocusableInRootView()) && HasFocus())
1137 canvas->DrawFocusRect(0, 0, width(), height());
1140 // Accelerated Painting --------------------------------------------------------
1142 #if !defined(COMPOSITOR_2)
1143 void View::PaintComposite(ui::Compositor* compositor) {
1144 compositor->SaveTransform();
1146 // TODO(sad): Push a transform matrix for the offset and bounds of the view?
1147 if (texture_id_)
1148 compositor->DrawTextureWithTransform(texture_id_, GetTransform());
1150 for (int i = 0, count = child_count(); i < count; ++i) {
1151 View* child = GetChildViewAt(i);
1152 child->PaintComposite(compositor);
1155 compositor->RestoreTransform();
1157 #else
1158 void View::PaintComposite() {
1159 if (!IsVisible())
1160 return;
1162 if (texture_.get()) {
1163 // TODO: if dirty_region doesn't itersect bounds, return.
1164 ui::Transform transform;
1165 GetTransformRelativeTo(NULL, &transform);
1166 texture_->Draw(transform);
1169 for (int i = 0, count = child_count(); i < count; ++i)
1170 GetChildViewAt(i)->PaintComposite();
1173 void View::PaintToTexture(const gfx::Rect& dirty_region) {
1174 if (!IsVisible())
1175 return;
1177 if (ShouldPaintToTexture() && texture_needs_updating_) {
1178 texture_clip_rect_ = dirty_region;
1179 Paint(NULL);
1180 texture_clip_rect_.SetRect(0, 0, 0, 0);
1181 } else {
1182 // Forward to all children as a descendant may be dirty and have a texture.
1183 for (int i = child_count() - 1; i >= 0; --i) {
1184 View* child_view = GetChildViewAt(i);
1185 gfx::Rect child_dirty_rect(child_view->bounds().Intersect(dirty_region));
1186 if (!child_dirty_rect.IsEmpty()) {
1187 child_dirty_rect.Offset(-child_view->x(), -child_view->y());
1188 GetChildViewAt(i)->PaintToTexture(child_dirty_rect);
1193 #endif
1195 bool View::ShouldPaintToTexture() const {
1196 return use_acceleration_when_possible && transform_.get() &&
1197 transform_->HasChange() && GetCompositor();
1200 const ui::Compositor* View::GetCompositor() const {
1201 return parent_ ? parent_->GetCompositor() : NULL;
1204 ui::Compositor* View::GetCompositor() {
1205 return parent_ ? parent_->GetCompositor() : NULL;
1208 // Input -----------------------------------------------------------------------
1210 bool View::HasHitTestMask() const {
1211 return false;
1214 void View::GetHitTestMask(gfx::Path* mask) const {
1215 DCHECK(mask);
1218 // Focus -----------------------------------------------------------------------
1220 bool View::IsFocusable() const {
1221 return focusable_ && IsEnabled() && IsVisible();
1224 void View::OnFocus() {
1225 // TODO(beng): Investigate whether it's possible for us to move this to
1226 // Focus().
1227 // By default, we clear the native focus. This ensures that no visible native
1228 // view as the focus and that we still receive keyboard inputs.
1229 FocusManager* focus_manager = GetFocusManager();
1230 if (focus_manager)
1231 focus_manager->ClearNativeFocus();
1233 // TODO(beng): Investigate whether it's possible for us to move this to
1234 // Focus().
1235 // Notify assistive technologies of the focus change.
1236 GetWidget()->NotifyAccessibilityEvent(
1237 this, ui::AccessibilityTypes::EVENT_FOCUS, true);
1240 void View::OnBlur() {
1243 void View::Focus() {
1244 SchedulePaint();
1245 OnFocus();
1248 void View::Blur() {
1249 SchedulePaint();
1250 OnBlur();
1253 // Tooltips --------------------------------------------------------------------
1255 void View::TooltipTextChanged() {
1256 Widget* widget = GetWidget();
1257 if (widget)
1258 widget->native_widget()->GetTooltipManager()->TooltipTextChanged(this);
1261 // Context menus ---------------------------------------------------------------
1263 gfx::Point View::GetKeyboardContextMenuLocation() {
1264 gfx::Rect vis_bounds = GetVisibleBounds();
1265 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
1266 vis_bounds.y() + vis_bounds.height() / 2);
1267 ConvertPointToScreen(this, &screen_point);
1268 return screen_point;
1271 // Drag and drop ---------------------------------------------------------------
1273 int View::GetDragOperations(const gfx::Point& press_pt) {
1274 return drag_controller_ ?
1275 drag_controller_->GetDragOperationsForView(this, press_pt) :
1276 ui::DragDropTypes::DRAG_NONE;
1279 void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) {
1280 DCHECK(drag_controller_);
1281 drag_controller_->WriteDragDataForView(this, press_pt, data);
1284 bool View::InDrag() {
1285 Widget* widget = GetWidget();
1286 return widget ? widget->dragged_view() == this : false;
1289 ////////////////////////////////////////////////////////////////////////////////
1290 // View, private:
1292 // DropInfo --------------------------------------------------------------------
1294 void View::DragInfo::Reset() {
1295 possible_drag = false;
1296 start_pt = gfx::Point();
1299 void View::DragInfo::PossibleDrag(const gfx::Point& p) {
1300 possible_drag = true;
1301 start_pt = p;
1304 // Tree operations -------------------------------------------------------------
1306 void View::DoRemoveChildView(View* view,
1307 bool update_focus_cycle,
1308 bool update_tool_tip,
1309 bool delete_removed_view) {
1310 DCHECK(view);
1311 const ViewVector::iterator i = find(children_.begin(), children_.end(), view);
1312 scoped_ptr<View> view_to_be_deleted;
1313 if (i != children_.end()) {
1314 if (update_focus_cycle) {
1315 // Let's remove the view from the focus traversal.
1316 View* next_focusable = view->next_focusable_view_;
1317 View* prev_focusable = view->previous_focusable_view_;
1318 if (prev_focusable)
1319 prev_focusable->next_focusable_view_ = next_focusable;
1320 if (next_focusable)
1321 next_focusable->previous_focusable_view_ = prev_focusable;
1324 if (GetWidget())
1325 UnregisterChildrenForVisibleBoundsNotification(view);
1326 view->ResetTexture();
1327 view->PropagateRemoveNotifications(this);
1328 view->SetParent(NULL);
1330 if (delete_removed_view && view->IsParentOwned())
1331 view_to_be_deleted.reset(view);
1333 children_.erase(i);
1336 if (update_tool_tip)
1337 UpdateTooltip();
1339 if (layout_manager_.get())
1340 layout_manager_->ViewRemoved(this, view);
1343 void View::SetParent(View* parent) {
1344 if (parent != parent_)
1345 parent_ = parent;
1348 void View::PropagateRemoveNotifications(View* parent) {
1349 for (int i = 0, count = child_count(); i < count; ++i)
1350 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
1352 for (View* v = this; v; v = v->parent())
1353 v->ViewHierarchyChangedImpl(true, false, parent, this);
1356 void View::PropagateAddNotifications(View* parent, View* child) {
1357 for (int i = 0, count = child_count(); i < count; ++i)
1358 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
1359 ViewHierarchyChangedImpl(true, true, parent, child);
1362 void View::PropagateNativeViewHierarchyChanged(bool attached,
1363 gfx::NativeView native_view,
1364 RootView* root_view) {
1365 for (int i = 0, count = child_count(); i < count; ++i)
1366 GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached,
1367 native_view,
1368 root_view);
1369 NativeViewHierarchyChanged(attached, native_view, root_view);
1372 void View::ViewHierarchyChangedImpl(bool register_accelerators,
1373 bool is_add,
1374 View* parent,
1375 View* child) {
1376 if (register_accelerators) {
1377 if (is_add) {
1378 // If you get this registration, you are part of a subtree that has been
1379 // added to the view hierarchy.
1380 if (GetFocusManager()) {
1381 RegisterPendingAccelerators();
1382 } else {
1383 // Delay accelerator registration until visible as we do not have
1384 // focus manager until then.
1385 accelerator_registration_delayed_ = true;
1387 } else {
1388 if (child == this)
1389 UnregisterAccelerators(true);
1393 ViewHierarchyChanged(is_add, parent, child);
1394 parent->needs_layout_ = true;
1397 // Size and disposition --------------------------------------------------------
1399 void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
1400 for (int i = 0, count = child_count(); i < count; ++i)
1401 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
1402 VisibilityChangedImpl(start, is_visible);
1405 void View::VisibilityChangedImpl(View* starting_from, bool is_visible) {
1406 if (is_visible)
1407 RegisterPendingAccelerators();
1408 else
1409 UnregisterAccelerators(true);
1410 VisibilityChanged(starting_from, is_visible);
1413 void View::BoundsChanged(const gfx::Rect& previous_bounds) {
1414 #if !defined(COMPOSITOR_2)
1415 if (canvas_.get())
1416 canvas_.reset(gfx::Canvas::CreateCanvas(width(), height(), false));
1417 #endif
1419 if (IsVisible()) {
1420 if (parent_) {
1421 // Paint the old bounds.
1422 if (base::i18n::IsRTL()) {
1423 gfx::Rect paint_rect = previous_bounds;
1424 paint_rect.set_x(parent()->GetMirroredXForRect(paint_rect));
1425 parent_->SchedulePaintInRect(paint_rect);
1426 } else {
1427 parent_->SchedulePaintInRect(previous_bounds);
1430 // Then the new.
1431 parent_->SchedulePaintInRect(GetMirroredBounds());
1432 } else {
1433 // Previous bounds has no meaning to an orphan. This should only happen
1434 // when the View is a RootView.
1435 SchedulePaintInRect(gfx::Rect(0, 0, bounds_.width(), bounds_.height()));
1439 OnBoundsChanged(previous_bounds);
1441 if (previous_bounds.size() != size()) {
1442 needs_layout_ = false;
1443 Layout();
1446 if (NeedsNotificationWhenVisibleBoundsChange()) {
1447 OnVisibleBoundsChanged();
1450 // Notify interested Views that visible bounds within the root view may have
1451 // changed.
1452 if (descendants_to_notify_.get()) {
1453 for (std::vector<View*>::iterator i = descendants_to_notify_->begin();
1454 i != descendants_to_notify_->end(); ++i) {
1455 (*i)->OnVisibleBoundsChanged();
1460 // static
1461 void View::RegisterChildrenForVisibleBoundsNotification(View* view) {
1462 if (view->NeedsNotificationWhenVisibleBoundsChange())
1463 view->RegisterForVisibleBoundsNotification();
1464 for (int i = 0; i < view->child_count(); ++i)
1465 RegisterChildrenForVisibleBoundsNotification(view->GetChildViewAt(i));
1468 // static
1469 void View::UnregisterChildrenForVisibleBoundsNotification(View* view) {
1470 if (view->NeedsNotificationWhenVisibleBoundsChange())
1471 view->UnregisterForVisibleBoundsNotification();
1472 for (int i = 0; i < view->child_count(); ++i)
1473 UnregisterChildrenForVisibleBoundsNotification(view->GetChildViewAt(i));
1476 void View::RegisterForVisibleBoundsNotification() {
1477 if (registered_for_visible_bounds_notification_)
1478 return;
1480 registered_for_visible_bounds_notification_ = true;
1481 View* ancestor = parent();
1482 while (ancestor) {
1483 ancestor->AddDescendantToNotify(this);
1484 ancestor = ancestor->parent();
1488 void View::UnregisterForVisibleBoundsNotification() {
1489 if (!registered_for_visible_bounds_notification_)
1490 return;
1491 registered_for_visible_bounds_notification_ = false;
1492 View* ancestor = parent();
1493 while (ancestor) {
1494 ancestor->RemoveDescendantToNotify(this);
1495 ancestor = ancestor->parent();
1499 void View::AddDescendantToNotify(View* view) {
1500 DCHECK(view);
1501 if (!descendants_to_notify_.get())
1502 descendants_to_notify_.reset(new ViewVector);
1503 descendants_to_notify_->push_back(view);
1506 void View::RemoveDescendantToNotify(View* view) {
1507 DCHECK(view && descendants_to_notify_.get());
1508 ViewVector::iterator i = find(descendants_to_notify_->begin(),
1509 descendants_to_notify_->end(),
1510 view);
1511 DCHECK(i != descendants_to_notify_->end());
1512 descendants_to_notify_->erase(i);
1513 if (descendants_to_notify_->empty())
1514 descendants_to_notify_.reset();
1517 // Transformations -------------------------------------------------------------
1519 bool View::GetTransformRelativeTo(const View* ancestor,
1520 ui::Transform* transform) const {
1521 const View* p = this;
1523 while (p && p != ancestor) {
1524 if (p->transform_.get())
1525 transform->ConcatTransform(*p->transform_);
1526 transform->ConcatTranslate(static_cast<float>(p->GetMirroredX()),
1527 static_cast<float>(p->y()));
1529 p = p->parent_;
1532 return p == ancestor;
1535 // Coordinate conversion -------------------------------------------------------
1537 // static
1538 void View::ConvertPointToView(const View* src,
1539 const View* dst,
1540 gfx::Point* point,
1541 bool try_other_direction) {
1542 // src can be NULL
1543 DCHECK(dst);
1544 DCHECK(point);
1546 if (src == NULL || src->Contains(dst)) {
1547 dst->ConvertPointFromAncestor(src, point);
1548 if (!src) {
1549 const Widget* widget = dst->GetWidget();
1550 if (widget) {
1551 gfx::Rect b = widget->GetClientAreaScreenBounds();
1552 point->SetPoint(point->x() - b.x(), point->y() - b.y());
1555 } else if (src && try_other_direction) {
1556 if (!src->ConvertPointForAncestor(dst, point)) {
1557 // |src| is not an ancestor of |dst|, and |dst| is not an ancestor of
1558 // |src| either. At this stage, |point| is in the widget's coordinate
1559 // system. So convert from the widget's to |dst|'s coordinate system now.
1560 ConvertPointFromWidget(dst, point);
1565 bool View::ConvertPointForAncestor(const View* ancestor,
1566 gfx::Point* point) const {
1567 ui::Transform trans;
1568 // TODO(sad): Have some way of caching the transformation results.
1569 bool result = GetTransformRelativeTo(ancestor, &trans);
1570 trans.TransformPoint(point);
1571 return result;
1574 bool View::ConvertPointFromAncestor(const View* ancestor,
1575 gfx::Point* point) const {
1576 ui::Transform trans;
1577 bool result = GetTransformRelativeTo(ancestor, &trans);
1578 trans.TransformPointReverse(point);
1579 return result;
1582 // Accelerated painting --------------------------------------------------------
1584 void View::ResetTexture() {
1585 #if defined(COMPOSITOR_2)
1586 texture_.reset();
1587 for (int i = child_count() - 1; i >= 0; --i)
1588 GetChildViewAt(i)->ResetTexture();
1589 #endif
1592 // Input -----------------------------------------------------------------------
1594 bool View::ProcessMousePressed(const MouseEvent& event, DragInfo* drag_info) {
1595 const bool enabled = IsEnabled();
1596 int drag_operations =
1597 (enabled && event.IsOnlyLeftMouseButton() && HitTest(event.location())) ?
1598 GetDragOperations(event.location()) : 0;
1599 ContextMenuController* context_menu_controller = event.IsRightMouseButton() ?
1600 context_menu_controller_ : 0;
1602 const bool result = OnMousePressed(event);
1603 // WARNING: we may have been deleted, don't use any View variables.
1605 if (!enabled)
1606 return result;
1608 if (drag_operations != ui::DragDropTypes::DRAG_NONE) {
1609 drag_info->PossibleDrag(event.location());
1610 return true;
1612 return !!context_menu_controller || result;
1615 bool View::ProcessMouseDragged(const MouseEvent& event, DragInfo* drag_info) {
1616 // Copy the field, that way if we're deleted after drag and drop no harm is
1617 // done.
1618 ContextMenuController* context_menu_controller = context_menu_controller_;
1619 const bool possible_drag = drag_info->possible_drag;
1620 if (possible_drag && ExceededDragThreshold(
1621 drag_info->start_pt.x() - event.x(),
1622 drag_info->start_pt.y() - event.y())) {
1623 if (!drag_controller_ ||
1624 drag_controller_->CanStartDragForView(
1625 this, drag_info->start_pt, event.location()))
1626 DoDrag(event, drag_info->start_pt);
1627 } else {
1628 if (OnMouseDragged(event))
1629 return true;
1630 // Fall through to return value based on context menu controller.
1632 // WARNING: we may have been deleted.
1633 return (context_menu_controller != NULL) || possible_drag;
1636 void View::ProcessMouseReleased(const MouseEvent& event) {
1637 if (context_menu_controller_ && event.IsOnlyRightMouseButton()) {
1638 // Assume that if there is a context menu controller we won't be deleted
1639 // from mouse released.
1640 gfx::Point location(event.location());
1641 OnMouseReleased(event);
1642 if (HitTest(location)) {
1643 ConvertPointToScreen(this, &location);
1644 ShowContextMenu(location, true);
1646 } else {
1647 OnMouseReleased(event);
1649 // WARNING: we may have been deleted.
1652 #if defined(TOUCH_UI)
1653 View::TouchStatus View::ProcessTouchEvent(const TouchEvent& event) {
1654 // TODO(rjkroege): Implement a grab scheme similar to as
1655 // as is found in MousePressed.
1656 return OnTouchEvent(event);
1658 #endif
1660 // Accelerators ----------------------------------------------------------------
1662 void View::RegisterPendingAccelerators() {
1663 if (!accelerators_.get() ||
1664 registered_accelerator_count_ == accelerators_->size()) {
1665 // No accelerators are waiting for registration.
1666 return;
1669 if (!GetWidget()) {
1670 // The view is not yet attached to a widget, defer registration until then.
1671 return;
1674 accelerator_focus_manager_ = GetFocusManager();
1675 if (!accelerator_focus_manager_) {
1676 // Some crash reports seem to show that we may get cases where we have no
1677 // focus manager (see bug #1291225). This should never be the case, just
1678 // making sure we don't crash.
1680 // TODO(jcampan): This fails for a view under NativeWidgetGtk with
1681 // TYPE_CHILD. (see http://crbug.com/21335) reenable
1682 // NOTREACHED assertion and verify accelerators works as
1683 // expected.
1684 #if defined(OS_WIN)
1685 NOTREACHED();
1686 #endif
1687 return;
1689 // Only register accelerators if we are visible.
1690 if (!IsVisibleInRootView())
1691 return;
1692 std::vector<Accelerator>::const_iterator iter;
1693 for (iter = accelerators_->begin() + registered_accelerator_count_;
1694 iter != accelerators_->end(); ++iter) {
1695 accelerator_focus_manager_->RegisterAccelerator(*iter, this);
1697 registered_accelerator_count_ = accelerators_->size();
1700 void View::UnregisterAccelerators(bool leave_data_intact) {
1701 if (!accelerators_.get())
1702 return;
1704 if (GetWidget()) {
1705 if (accelerator_focus_manager_) {
1706 // We may not have a FocusManager if the window containing us is being
1707 // closed, in which case the FocusManager is being deleted so there is
1708 // nothing to unregister.
1709 accelerator_focus_manager_->UnregisterAccelerators(this);
1710 accelerator_focus_manager_ = NULL;
1712 if (!leave_data_intact) {
1713 accelerators_->clear();
1714 accelerators_.reset();
1716 registered_accelerator_count_ = 0;
1720 // Focus -----------------------------------------------------------------------
1722 void View::InitFocusSiblings(View* v, int index) {
1723 int child_count = static_cast<int>(children_.size());
1725 if (child_count == 0) {
1726 v->next_focusable_view_ = NULL;
1727 v->previous_focusable_view_ = NULL;
1728 } else {
1729 if (index == child_count) {
1730 // We are inserting at the end, but the end of the child list may not be
1731 // the last focusable element. Let's try to find an element with no next
1732 // focusable element to link to.
1733 View* last_focusable_view = NULL;
1734 for (std::vector<View*>::iterator iter = children_.begin();
1735 iter != children_.end(); ++iter) {
1736 if (!(*iter)->next_focusable_view_) {
1737 last_focusable_view = *iter;
1738 break;
1741 if (last_focusable_view == NULL) {
1742 // Hum... there is a cycle in the focus list. Let's just insert ourself
1743 // after the last child.
1744 View* prev = children_[index - 1];
1745 v->previous_focusable_view_ = prev;
1746 v->next_focusable_view_ = prev->next_focusable_view_;
1747 prev->next_focusable_view_->previous_focusable_view_ = v;
1748 prev->next_focusable_view_ = v;
1749 } else {
1750 last_focusable_view->next_focusable_view_ = v;
1751 v->next_focusable_view_ = NULL;
1752 v->previous_focusable_view_ = last_focusable_view;
1754 } else {
1755 View* prev = children_[index]->GetPreviousFocusableView();
1756 v->previous_focusable_view_ = prev;
1757 v->next_focusable_view_ = children_[index];
1758 if (prev)
1759 prev->next_focusable_view_ = v;
1760 children_[index]->previous_focusable_view_ = v;
1765 // System events ---------------------------------------------------------------
1767 void View::PropagateThemeChanged() {
1768 for (int i = child_count() - 1; i >= 0; --i)
1769 GetChildViewAt(i)->PropagateThemeChanged();
1770 OnThemeChanged();
1773 void View::PropagateLocaleChanged() {
1774 for (int i = child_count() - 1; i >= 0; --i)
1775 GetChildViewAt(i)->PropagateLocaleChanged();
1776 OnLocaleChanged();
1779 // Tooltips --------------------------------------------------------------------
1781 void View::UpdateTooltip() {
1782 Widget* widget = GetWidget();
1783 // TODO(beng): The TooltipManager NULL check can be removed when we
1784 // consolidate Init() methods and make views_unittests Init() all
1785 // Widgets that it uses.
1786 if (widget && widget->native_widget()->GetTooltipManager())
1787 widget->native_widget()->GetTooltipManager()->UpdateTooltip();
1790 // Drag and drop ---------------------------------------------------------------
1792 void View::DoDrag(const MouseEvent& event, const gfx::Point& press_pt) {
1793 int drag_operations = GetDragOperations(press_pt);
1794 if (drag_operations == ui::DragDropTypes::DRAG_NONE)
1795 return;
1797 OSExchangeData data;
1798 WriteDragData(press_pt, &data);
1800 // Message the RootView to do the drag and drop. That way if we're removed
1801 // the RootView can detect it and avoid calling us back.
1802 GetWidget()->RunShellDrag(this, data, drag_operations);
1805 // Debugging -------------------------------------------------------------------
1807 #if defined(TOUCH_DEBUG)
1808 std::string View::PrintViewGraph(bool first) {
1809 // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19.
1810 const size_t kMaxPointerStringLength = 19;
1812 std::string result;
1814 if (first)
1815 result.append("digraph {\n");
1817 // Node characteristics.
1818 char p[kMaxPointerStringLength];
1820 size_t baseNameIndex = GetClassName().find_last_of('/');
1821 if (baseNameIndex == std::string::npos)
1822 baseNameIndex = 0;
1823 else
1824 baseNameIndex++;
1826 // Information about current node.
1827 snprintf(p, kMaxPointerStringLength, "%p", this);
1828 result.append(" N");
1829 result.append(p+2);
1830 result.append(" [label=\"");
1831 result.append(GetClassName().substr(baseNameIndex).c_str());
1832 result.append("\"");
1833 if (!parent())
1834 result.append(", shape=box");
1835 #if defined(COMPOSITOR_2)
1836 if (texture_.get())
1837 #else
1838 if (canvas_.get())
1839 #endif
1840 result.append(", color=green");
1841 result.append("]\n");
1843 // Link to parent.
1844 if (parent()) {
1845 char pp[kMaxPointerStringLength];
1847 snprintf(pp, kMaxPointerStringLength, "%p", parent());
1848 result.append(" N");
1849 result.append(pp+2);
1850 result.append(" -> N");
1851 result.append(p+2);
1852 result.append("\n");
1855 // Children.
1856 for (int i = 0, count = child_count(); i < count; ++i)
1857 result.append(GetChildViewAt(i)->PrintViewGraph(false));
1859 if (first)
1860 result.append("}\n");
1862 return result;
1864 #endif
1866 } // namespace views