blob: f2ca1eccd75ae82043b4bb85988224fafc1565f0 [file] [log] [blame]
// Copyright 2015 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 "components/exo/pointer.h"
#include "ash/shell.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/surface.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
namespace exo {
////////////////////////////////////////////////////////////////////////////////
// Pointer, public:
Pointer::Pointer(PointerDelegate* delegate)
: delegate_(delegate), focus_(nullptr) {
ash::Shell::GetInstance()->AddPreTargetHandler(this);
}
Pointer::~Pointer() {
delegate_->OnPointerDestroying(this);
if (focus_)
focus_->RemoveSurfaceObserver(this);
ash::Shell::GetInstance()->RemovePreTargetHandler(this);
}
////////////////////////////////////////////////////////////////////////////////
// ui::EventHandler overrides:
void Pointer::OnMouseEvent(ui::MouseEvent* event) {
Surface* target = GetEffectiveTargetForEvent(event);
// If target is different than the current pointer focus then we need to
// generate enter and leave events.
if (target != focus_) {
// First generate a leave event if we currently have a target in focus.
if (focus_) {
delegate_->OnPointerLeave(focus_);
focus_->RemoveSurfaceObserver(this);
focus_ = nullptr;
}
// Second generate an enter event if focus moved to a new target.
if (target) {
delegate_->OnPointerEnter(target, event->location(),
event->button_flags());
location_ = event->location();
focus_ = target;
focus_->AddSurfaceObserver(this);
}
}
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_RELEASED:
if (focus_) {
delegate_->OnPointerButton(event->time_stamp(),
event->changed_button_flags(),
event->type() == ui::ET_MOUSE_PRESSED);
}
break;
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_DRAGGED:
// Generate motion event if location changed. We need to check location
// here as mouse movement can generate both "moved" and "entered" events
// but OnPointerMotion should only be called if location changed since
// OnPointerEnter was called.
if (focus_ && event->location() != location_) {
delegate_->OnPointerMotion(event->time_stamp(), event->location());
location_ = event->location();
}
break;
case ui::ET_MOUSEWHEEL:
if (focus_) {
delegate_->OnPointerWheel(
event->time_stamp(),
static_cast<ui::MouseWheelEvent*>(event)->offset());
}
break;
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSE_CAPTURE_CHANGED:
break;
default:
NOTREACHED();
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// SurfaceObserver overrides:
void Pointer::OnSurfaceDestroying(Surface* surface) {
DCHECK(surface == focus_);
focus_ = nullptr;
surface->RemoveSurfaceObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
// Pointer, private:
Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
Surface* target =
Surface::AsSurface(static_cast<aura::Window*>(event->target()));
if (!target)
return nullptr;
return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
}
} // namespace exo