blob: b8dc5437f7971851460958a8159e96af8ee62915 [file] [log] [blame]
// Copyright 2018 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 "ui/ozone/platform/wayland/wayland_touch.h"
#include <sys/mman.h>
#include <wayland-client.h>
#include "base/files/scoped_file.h"
#include "base/memory/ptr_util.h"
#include "ui/base/ui_features.h"
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_window.h"
namespace ui {
WaylandTouch::TouchPoint::TouchPoint() = default;
WaylandTouch::TouchPoint::TouchPoint(gfx::Point location,
wl_surface* current_surface)
: surface(current_surface), last_known_location(location) {}
WaylandTouch::TouchPoint::~TouchPoint() = default;
//-----------------------------------------------------------------------------
WaylandTouch::WaylandTouch(wl_touch* touch,
const EventDispatchCallback& callback)
: obj_(touch), callback_(callback) {
static const wl_touch_listener listener = {
&WaylandTouch::Down, &WaylandTouch::Up, &WaylandTouch::Motion,
&WaylandTouch::Frame, &WaylandTouch::Cancel,
};
wl_touch_add_listener(obj_.get(), &listener, this);
}
WaylandTouch::~WaylandTouch() {
DCHECK(current_points_.empty());
}
void WaylandTouch::RemoveTouchPoints(const WaylandWindow* window) {
base::EraseIf(current_points_,
[window](const TouchPoints::value_type& point) {
return point.second.surface == window->surface();
});
}
void WaylandTouch::MaybeUnsetFocus(const WaylandTouch::TouchPoints& points,
int32_t id,
wl_surface* surface) {
for (const auto& point : points) {
// Return early on the first other point having this surface.
if (surface == point.second.surface && id != point.first)
return;
}
DCHECK(surface);
WaylandWindow::FromSurface(surface)->set_touch_focus(false);
}
void WaylandTouch::Down(void* data,
wl_touch* obj,
uint32_t serial,
uint32_t time,
struct wl_surface* surface,
int32_t id,
wl_fixed_t x,
wl_fixed_t y) {
if (!surface)
return;
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
touch->connection_->set_serial(serial);
WaylandWindow::FromSurface(surface)->set_touch_focus(true);
// Make sure this touch point wasn't present before.
if (touch->current_points_.find(id) != touch->current_points_.end()) {
LOG(WARNING) << "Touch down fired with wrong id";
return;
}
EventType type = ET_TOUCH_PRESSED;
gfx::Point location(wl_fixed_to_double(x), wl_fixed_to_double(y));
base::TimeTicks time_stamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id);
TouchEvent event(type, location, time_stamp, pointer_details);
touch->callback_.Run(&event);
touch->current_points_[id] = TouchPoint(location, surface);
}
void WaylandTouch::Up(void* data,
wl_touch* obj,
uint32_t serial,
uint32_t time,
int32_t id) {
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
const auto iterator = touch->current_points_.find(id);
// Make sure this touch point was present before.
if (iterator == touch->current_points_.end()) {
LOG(WARNING) << "Touch up fired with no matching touch down";
return;
}
EventType type = ET_TOUCH_RELEASED;
base::TimeTicks time_stamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id);
TouchEvent event(type, touch->current_points_[id].last_known_location,
time_stamp, pointer_details);
touch->callback_.Run(&event);
touch->MaybeUnsetFocus(touch->current_points_, id,
touch->current_points_[id].surface);
touch->current_points_.erase(iterator);
}
void WaylandTouch::Motion(void* data,
wl_touch* obj,
uint32_t time,
int32_t id,
wl_fixed_t x,
wl_fixed_t y) {
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
// Make sure this touch point wasn't present before.
if (touch->current_points_.find(id) == touch->current_points_.end()) {
LOG(WARNING) << "Touch event fired with wrong id";
return;
}
EventType type = ET_TOUCH_MOVED;
gfx::Point location(wl_fixed_to_double(x), wl_fixed_to_double(y));
base::TimeTicks time_stamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id);
TouchEvent event(type, location, time_stamp, pointer_details);
touch->callback_.Run(&event);
touch->current_points_[id].last_known_location = location;
}
void WaylandTouch::Frame(void* data, wl_touch* obj) {}
void WaylandTouch::Cancel(void* data, wl_touch* obj) {
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
for (auto& point : touch->current_points_) {
int32_t id = point.first;
EventType type = ET_TOUCH_CANCELLED;
base::TimeTicks time_stamp = base::TimeTicks::Now();
PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id);
TouchEvent event(type, gfx::Point(), time_stamp, pointer_details);
touch->callback_.Run(&event);
WaylandWindow::FromSurface(point.second.surface)->set_touch_focus(false);
}
touch->current_points_.clear();
}
} // namespace ui