// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/widget/root_view.h"

#include <algorithm>

#include "app/drag_drop_types.h"
#include "app/gfx/canvas.h"
#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "views/fill_layout.h"
#include "views/focus/view_storage.h"
#include "views/widget/widget.h"
#include "views/window/window.h"

namespace views {

/////////////////////////////////////////////////////////////////////////////
//
// A Task to trigger non urgent painting.
//
/////////////////////////////////////////////////////////////////////////////
class PaintTask : public Task {
 public:
  explicit PaintTask(RootView* target) : root_view_(target) {
  }

  ~PaintTask() {}

  void Cancel() {
    root_view_ = NULL;
  }

  void Run() {
    if (root_view_)
      root_view_->PaintNow();
  }
 private:
  // The target root view.
  RootView* root_view_;

  DISALLOW_COPY_AND_ASSIGN(PaintTask);
};

const char RootView::kViewClassName[] = "views/RootView";

/////////////////////////////////////////////////////////////////////////////
//
// RootView - constructors, destructors, initialization
//
/////////////////////////////////////////////////////////////////////////////

RootView::RootView(Widget* widget)
    : mouse_pressed_handler_(NULL),
      mouse_move_handler_(NULL),
      last_click_handler_(NULL),
      widget_(widget),
      invalid_rect_urgent_(false),
      pending_paint_task_(NULL),
      paint_task_needed_(false),
      explicit_mouse_handler_(false),
#if defined(OS_WIN)
      previous_cursor_(NULL),
#endif
      default_keyboard_handler_(NULL),
      focus_on_mouse_pressed_(false),
      ignore_set_focus_calls_(false),
      focus_traversable_parent_(NULL),
      focus_traversable_parent_view_(NULL),
      drag_view_(NULL)
#ifndef NDEBUG
      ,
      is_processing_paint_(false)
#endif
{
}

RootView::~RootView() {
  // If we have children remove them explicitly so to make sure a remove
  // notification is sent for each one of them.
  if (!child_views_.empty())
    RemoveAllChildViews(true);

  if (pending_paint_task_)
    pending_paint_task_->Cancel();  // Ensure we're not called any more.
}

void RootView::SetContentsView(View* contents_view) {
  DCHECK(contents_view && GetWidget()->GetNativeView()) <<
      "Can't be called until after the native view is created!";
  // The ContentsView must be set up _after_ the window is created so that its
  // Widget pointer is valid.
  SetLayoutManager(new FillLayout);
  if (GetChildViewCount() != 0)
    RemoveAllChildViews(true);
  AddChildView(contents_view);

  // Force a layout now, since the attached hierarchy won't be ready for the
  // containing window's bounds. Note that we call Layout directly rather than
  // calling the widget's size changed handler, since the RootView's bounds may
  // not have changed, which will cause the Layout not to be done otherwise.
  Layout();
}

/////////////////////////////////////////////////////////////////////////////
//
// RootView - layout, painting
//
/////////////////////////////////////////////////////////////////////////////

void RootView::SchedulePaint(const gfx::Rect& r, bool urgent) {
  // If there is an existing invalid rect, add the union of the scheduled
  // rect with the invalid rect. This could be optimized further if
  // necessary.
  if (invalid_rect_.IsEmpty())
    invalid_rect_ = r;
  else
    invalid_rect_ = invalid_rect_.Union(r);

  if (urgent || invalid_rect_urgent_) {
    invalid_rect_urgent_ = true;
  } else {
    if (!pending_paint_task_) {
      pending_paint_task_ = new PaintTask(this);
      MessageLoop::current()->PostTask(FROM_HERE, pending_paint_task_);
    }
    paint_task_needed_ = true;
  }
}

void RootView::SchedulePaint() {
  View::SchedulePaint();
}

void RootView::SchedulePaint(int x, int y, int w, int h) {
  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_EVIL_CONSTRUCTORS(ScopedProcessingPaint);
};
#endif

void RootView::ProcessPaint(gfx::Canvas* canvas) {
#ifndef NDEBUG
  ScopedProcessingPaint processing_paint(&is_processing_paint_);
#endif

  // Clip the invalid rect to our bounds. If a view is in a scrollview
  // it could be a lot larger
  invalid_rect_ = GetScheduledPaintRectConstrainedToSize();

  if (invalid_rect_.IsEmpty())
    return;

  // Clear the background.
  canvas->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);

  // Save the current transforms.
  canvas->save();

  // Set the clip rect according to the invalid rect.
  int clip_x = invalid_rect_.x() + x();
  int clip_y = invalid_rect_.y() + y();
  canvas->ClipRectInt(clip_x, clip_y, invalid_rect_.width(),
                      invalid_rect_.height());

  // Paint the tree
  View::ProcessPaint(canvas);

  // Restore the previous transform
  canvas->restore();

  ClearPaintRect();
}

void RootView::PaintNow() {
  if (pending_paint_task_) {
    pending_paint_task_->Cancel();
    pending_paint_task_ = NULL;
  }
  if (!paint_task_needed_)
    return;
  Widget* widget = GetWidget();
  if (widget)
    widget->PaintNow(invalid_rect_);
}

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(true));
}

/////////////////////////////////////////////////////////////////////////////
//
// RootView - tree
//
/////////////////////////////////////////////////////////////////////////////

Widget* RootView::GetWidget() const {
  return widget_;
}

void RootView::ThemeChanged() {
  View::ThemeChanged();
}

/////////////////////////////////////////////////////////////////////////////
//
// 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;
    }

    FocusManager* focus_manager = widget_->GetFocusManager();
    // An unparanted RootView does not have a FocusManager.
    if (focus_manager)
      focus_manager->ViewRemoved(parent, child);

    ViewStorage::GetSharedInstance()->ViewRemoved(parent, child);
  }
}

void RootView::SetFocusOnMousePressed(bool f) {
  focus_on_mouse_pressed_ = f;
}

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
  // are formed from a single-click followed by a double-click event. When the
  // double-click event lands on a different view than its single-click part,
  // we transform it into a single-click which prevents odd things.
  if ((e.GetFlags() & MouseEvent::EF_IS_NON_CLIENT) &&
      !(e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)) {
    last_click_handler_ = NULL;
    return false;
  }

  UpdateCursor(e);
  SetMouseLocationAndFlags(e);

  // If mouse_pressed_handler_ is non null, we are currently processing
  // a pressed -> drag -> released session. In that case we send the
  // event to mouse_pressed_handler_
  if (mouse_pressed_handler_) {
    MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);
    drag_info.Reset();
    mouse_pressed_handler_->ProcessMousePressed(mouse_pressed_event,
                                                &drag_info);
    return true;
  }
  DCHECK(!explicit_mouse_handler_);

  bool hit_disabled_view = false;
  // Walk up the tree until we find a view that wants the mouse event.
  for (mouse_pressed_handler_ = GetViewForPoint(e.location());
       mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
       mouse_pressed_handler_ = mouse_pressed_handler_->GetParent()) {
    if (!mouse_pressed_handler_->IsEnabled()) {
      // Disabled views should eat events instead of propagating them upwards.
      hit_disabled_view = true;
      break;
    }

    // See if this view wants to handle the mouse press.
    MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);

    // Remove the double-click flag if the handler is different than the
    // one which got the first click part of the double-click.
    if (mouse_pressed_handler_ != last_click_handler_)
      mouse_pressed_event.set_flags(e.GetFlags() &
                                    ~MouseEvent::EF_IS_DOUBLE_CLICK);

    drag_info.Reset();
    bool handled = mouse_pressed_handler_->ProcessMousePressed(
        mouse_pressed_event, &drag_info);

    // The view could have removed itself from the tree when handling
    // OnMousePressed().  In this case, the removal notification will have
    // reset mouse_pressed_handler_ to NULL out from under us.  Detect this
    // case and stop.  (See comments in view.h.)
    //
    // 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 (!mouse_pressed_handler_)
      break;

    // If the view handled the event, leave mouse_pressed_handler_ set and
    // return true, which will cause subsequent drag/release events to get
    // forwarded to that view.
    if (handled) {
      last_click_handler_ = mouse_pressed_handler_;
      return true;
    }
  }

  // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
  mouse_pressed_handler_ = NULL;

  if (focus_on_mouse_pressed_) {
#if defined(OS_WIN)
    HWND hwnd = GetWidget()->GetNativeView();
    if (::GetFocus() != hwnd)
      ::SetFocus(hwnd);
#else
    GtkWidget* widget = GetWidget()->GetNativeView();
    if (!gtk_widget_is_focus(widget))
      gtk_widget_grab_focus(widget);
#endif
  }

  // In the event that a double-click is not handled after traversing the
  // entire hierarchy (even as a single-click when sent to a different view),
  // it must be marked as handled to avoid anything happening from default
  // processing if it the first click-part was handled by us.
  if (last_click_handler_ && e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)
    hit_disabled_view = true;

  last_click_handler_ = NULL;
  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.GetType(), l.x(), l.y());
  }
  SetActiveCursor(cursor);
}

bool RootView::OnMouseDragged(const MouseEvent& e) {
  UpdateCursor(e);

  if (mouse_pressed_handler_) {
    SetMouseLocationAndFlags(e);

    gfx::Point p;
    ConvertPointToMouseHandler(e.location(), &p);
    MouseEvent mouse_event(e.GetType(), p.x(), p.y(), e.GetFlags());
    return mouse_pressed_handler_->ProcessMouseDragged(mouse_event, &drag_info);
  }
  return false;
}

void RootView::OnMouseReleased(const MouseEvent& e, bool canceled) {
  UpdateCursor(e);

  if (mouse_pressed_handler_) {
    gfx::Point p;
    ConvertPointToMouseHandler(e.location(), &p);
    MouseEvent mouse_released(e.GetType(), p.x(), p.y(), e.GetFlags());
    // We allow the view to delete us from ProcessMouseReleased. As such,
    // configure state such that we're done first, then call View.
    View* mouse_pressed_handler = mouse_pressed_handler_;
    mouse_pressed_handler_ = NULL;
    explicit_mouse_handler_ = false;
    mouse_pressed_handler->ProcessMouseReleased(mouse_released, canceled);
    // WARNING: we may have been deleted.
  }
}

void RootView::OnMouseMoved(const MouseEvent& e) {
  View* v = GetViewForPoint(e.location());
  // Find the first enabled view.
  while (v && !v->IsEnabled())
    v = v->GetParent();
  if (v && v != this) {
    if (v != mouse_move_handler_) {
      if (mouse_move_handler_ != NULL) {
        MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
        mouse_move_handler_->OnMouseExited(exited_event);
      }

      mouse_move_handler_ = v;

      MouseEvent entered_event(Event::ET_MOUSE_ENTERED,
                               this,
                               mouse_move_handler_,
                               e.location(),
                               0);
      mouse_move_handler_->OnMouseEntered(entered_event);
    }
    MouseEvent moved_event(Event::ET_MOUSE_MOVED,
                           this,
                           mouse_move_handler_,
                           e.location(),
                           0);
    mouse_move_handler_->OnMouseMoved(moved_event);

    gfx::NativeCursor cursor = mouse_move_handler_->GetCursorForPoint(
        moved_event.GetType(), moved_event.x(), moved_event.y());
    SetActiveCursor(cursor);
  } else if (mouse_move_handler_ != NULL) {
    MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
    mouse_move_handler_->OnMouseExited(exited_event);
    SetActiveCursor(NULL);
  }
}

void RootView::ProcessOnMouseExited() {
  if (mouse_move_handler_ != NULL) {
    MouseEvent exited_event(Event::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(Event::ET_MOUSE_RELEASED, last_mouse_event_x_,
                             last_mouse_event_y_, last_mouse_event_flags_);
    OnMouseReleased(release_event, true);
  }
}

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;
  return NULL;
}

View* RootView::FindNextFocusableView(View* starting_view,
                                      bool reverse,
                                      Direction direction,
                                      bool check_starting_view,
                                      FocusTraversable** focus_traversable,
                                      View** focus_traversable_view) {
  *focus_traversable = NULL;
  *focus_traversable_view = NULL;

  if (GetChildViewCount() == 0) {
    NOTREACHED();
    // Nothing to focus on here.
    return NULL;
  }

  if (!starting_view) {
    // Default to the first/last child
    starting_view = reverse ? GetChildViewAt(GetChildViewCount() - 1) :
                              GetChildViewAt(0) ;
    // If there was no starting view, then the one we select is a potential
    // focus candidate.
    check_starting_view = true;
  } else {
    // The starting view should be part of this RootView.
    DCHECK(IsParentOf(starting_view));
  }

  View* v = NULL;
  if (!reverse) {
    v = FindNextFocusableViewImpl(starting_view, check_starting_view,
                                  true,
                                  (direction == DOWN) ? true : false,
                                  starting_view->GetGroup(),
                                  focus_traversable,
                                  focus_traversable_view);
  } else {
    // If the starting view is focusable, we don't want to go down, as we are
    // traversing the view hierarchy tree bottom-up.
    bool can_go_down = (direction == DOWN) && !starting_view->IsFocusable();
    v = FindPreviousFocusableViewImpl(starting_view, check_starting_view,
                                      true,
                                      can_go_down,
                                      starting_view->GetGroup(),
                                      focus_traversable,
                                      focus_traversable_view);
  }

  // Doing some sanity checks.
  if (v) {
    DCHECK(v->IsFocusable());
    return v;
  }
  if (*focus_traversable) {
    DCHECK(*focus_traversable_view);
    return NULL;
  }
  // Nothing found.
  return NULL;
}

// Strategy for finding the next focusable view:
// - keep going down the first child, stop when you find a focusable view or
//   a focus traversable view (in that case return it) or when you reach a view
//   with no children.
// - go to the right sibling and start the search from there (by invoking
//   FindNextFocusableViewImpl on that view).
// - if the view has no right sibling, go up the parents until you find a parent
//   with a right sibling and start the search from there.
View* RootView::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) {
  if (check_starting_view) {
    if (IsViewFocusableCandidate(starting_view, skip_group_id)) {
      View* v = FindSelectedViewForGroup(starting_view);
      // The selected view might not be focusable (if it is disabled for
      // example).
      if (v && v->IsFocusable())
        return v;
    }

    *focus_traversable = starting_view->GetFocusTraversable();
    if (*focus_traversable) {
      *focus_traversable_view = starting_view;
      return NULL;
    }
  }

  // First let's try the left child.
  if (can_go_down) {
    if (starting_view->GetChildViewCount() > 0) {
      View* v = FindNextFocusableViewImpl(starting_view->GetChildViewAt(0),
                                          true, false, true, skip_group_id,
                                          focus_traversable,
                                          focus_traversable_view);
      if (v || *focus_traversable)
        return v;
    }
  }

  // Then try the right sibling.
  View* sibling = starting_view->GetNextFocusableView();
  if (sibling) {
    View* v = FindNextFocusableViewImpl(sibling,
                                        true, false, true, skip_group_id,
                                        focus_traversable,
                                        focus_traversable_view);
    if (v || *focus_traversable)
      return v;
  }

  // Then go up to the parent sibling.
  if (can_go_up) {
    View* parent = starting_view->GetParent();
    while (parent) {
      sibling = parent->GetNextFocusableView();
      if (sibling) {
        return FindNextFocusableViewImpl(sibling,
                                         true, true, true,
                                         skip_group_id,
                                         focus_traversable,
                                         focus_traversable_view);
      }
      parent = parent->GetParent();
    }
  }

  // We found nothing.
  return NULL;
}

// Strategy for finding the previous focusable view:
// - keep going down on the right until you reach a view with no children, if it
//   it is a good candidate return it.
// - start the search on the left sibling.
// - if there are no left sibling, start the search on the parent (without going
//   down).
View* RootView::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) {
  // Let's go down and right as much as we can.
  if (can_go_down) {
    // Before we go into the direct children, we have to check if this view has
    // a FocusTraversable.
    *focus_traversable = starting_view->GetFocusTraversable();
    if (*focus_traversable) {
      *focus_traversable_view = starting_view;
      return NULL;
    }

    if (starting_view->GetChildViewCount() > 0) {
      View* view =
          starting_view->GetChildViewAt(starting_view->GetChildViewCount() - 1);
      View* v = FindPreviousFocusableViewImpl(view, true, false, true,
                                              skip_group_id,
                                              focus_traversable,
                                              focus_traversable_view);
      if (v || *focus_traversable)
        return v;
    }
  }

  // Then look at this view. Here, we do not need to see if the view has
  // a FocusTraversable, since we do not want to go down any more.
  if (check_starting_view &&
      IsViewFocusableCandidate(starting_view, skip_group_id)) {
    View* v = FindSelectedViewForGroup(starting_view);
    // The selected view might not be focusable (if it is disabled for
    // example).
    if (v && v->IsFocusable())
      return v;
  }

  // Then try the left sibling.
  View* sibling = starting_view->GetPreviousFocusableView();
  if (sibling) {
    return FindPreviousFocusableViewImpl(sibling,
                                         true, true, true,
                                         skip_group_id,
                                         focus_traversable,
                                         focus_traversable_view);
  }

  // Then go up the parent.
  if (can_go_up) {
    View* parent = starting_view->GetParent();
    if (parent)
      return FindPreviousFocusableViewImpl(parent,
                                           true, true, false,
                                           skip_group_id,
                                           focus_traversable,
                                           focus_traversable_view);
  }

  // We found nothing.
  return NULL;
}

FocusTraversable* RootView::GetFocusTraversableParent() {
  return focus_traversable_parent_;
}

void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
  DCHECK(focus_traversable != this);
  focus_traversable_parent_ = focus_traversable;
}

View* RootView::GetFocusTraversableParentView() {
  return focus_traversable_parent_view_;
}

void RootView::SetFocusTraversableParentView(View* view) {
  focus_traversable_parent_view_ = view;
}

// static
View* RootView::FindSelectedViewForGroup(View* view) {
  if (view->IsGroupFocusTraversable() ||
      view->GetGroup() == -1)  // No group for that view.
    return view;

  View* selected_view = view->GetSelectedViewForGroup(view->GetGroup());
  if (selected_view)
    return selected_view;

  // No view selected for that group, default to the specified view.
  return view;
}

// static
bool RootView::IsViewFocusableCandidate(View* v, int skip_group_id) {
  return v->IsFocusable() &&
      (v->IsGroupFocusTraversable() || skip_group_id == -1 ||
       v->GetGroup() != skip_group_id);
}

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.GetKeyCode() == base::VKEY_APPS) ||
     (event.GetKeyCode() == base::VKEY_F10 && event.IsShiftDown()))) {
    gfx::Point screen_loc = v->GetKeyboardContextMenuLocation();
    v->ShowContextMenu(screen_loc.x(), screen_loc.y(), false);
    return true;
  }
  for (; v && v != this && !consumed; v = v->GetParent()) {
    consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
        v->OnKeyPressed(event) : v->OnKeyReleased(event);
  }

  if (!consumed && default_keyboard_handler_) {
    consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
        default_keyboard_handler_->OnKeyPressed(event) :
        default_keyboard_handler_->OnKeyReleased(event);
  }

  return consumed;
}

bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) {
  View* v;
  bool consumed = false;
  if (GetFocusedView()) {
    for (v = GetFocusedView();
         v && v != this && !consumed; v = v->GetParent()) {
      consumed = v->OnMouseWheel(e);
    }
  }

  if (!consumed && default_keyboard_handler_) {
    consumed = default_keyboard_handler_->OnMouseWheel(e);
  }
  return consumed;
}

void RootView::SetDefaultKeyboardHandler(View* v) {
  default_keyboard_handler_ = v;
}

bool RootView::IsVisibleInRootView() const {
  return IsVisible();
}

void RootView::ViewBoundsChanged(View* view, bool size_changed,
                                 bool position_changed) {
  DCHECK(view && (size_changed || position_changed));
  if (!view->descendants_to_notify_.get())
    return;

  for (std::vector<View*>::iterator i = view->descendants_to_notify_->begin();
       i != view->descendants_to_notify_->end(); ++i) {
    (*i)->VisibleBoundsInRootChanged();
  }
}

void RootView::RegisterViewForVisibleBoundsNotification(View* view) {
  DCHECK(view);
  if (view->registered_for_visible_bounds_notification_)
    return;
  view->registered_for_visible_bounds_notification_ = true;
  View* ancestor = view->GetParent();
  while (ancestor) {
    ancestor->AddDescendantToNotify(view);
    ancestor = ancestor->GetParent();
  }
}

void RootView::UnregisterViewForVisibleBoundsNotification(View* view) {
  DCHECK(view);
  if (!view->registered_for_visible_bounds_notification_)
    return;
  view->registered_for_visible_bounds_notification_ = false;
  View* ancestor = view->GetParent();
  while (ancestor) {
    ancestor->RemoveDescendantToNotify(view);
    ancestor = ancestor->GetParent();
  }
}

void RootView::SetMouseLocationAndFlags(const MouseEvent& e) {
  last_mouse_event_flags_ = e.GetFlags();
  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;

  // If a pending_paint_task_ does Run(), we don't need to do anything.
  paint_task_needed_ = false;
}

/////////////////////////////////////////////////////////////////////////////
//
// RootView - accessibility
//
/////////////////////////////////////////////////////////////////////////////

bool RootView::GetAccessibleRole(AccessibilityTypes::Role* role) {
  DCHECK(role);

  *role = AccessibilityTypes::ROLE_APPLICATION;
  return true;
}

bool RootView::GetAccessibleName(std::wstring* name) {
  if (!accessible_name_.empty()) {
    *name = accessible_name_;
    return true;
  }
  return false;
}

void RootView::SetAccessibleName(const std::wstring& name) {
  accessible_name_.assign(name);
}

View* RootView::GetDragView() {
  return drag_view_;
}

void RootView::SetActiveCursor(gfx::NativeCursor cursor) {
#if defined(OS_WIN)
  if (cursor) {
    previous_cursor_ = ::SetCursor(cursor);
  } else if (previous_cursor_) {
    ::SetCursor(previous_cursor_);
    previous_cursor_ = NULL;
  }
#elif defined(OS_LINUX)
  gfx::NativeView native_view = GetWidget()->GetNativeView();
  if (!native_view)
    return;
  gdk_window_set_cursor(native_view->window, cursor);
  if (cursor)
    gdk_cursor_destroy(cursor);
#endif
}

}  // namespace views