|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <libevdev/libevdev.h>
|
|
|
|
|
#include <linux/input-event-codes.h>
|
|
|
|
@ -6,10 +7,11 @@
|
|
|
|
|
#include <float.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
#include <wlr/types/wlr_box.h>
|
|
|
|
|
#include <wlr/types/wlr_cursor.h>
|
|
|
|
|
#include <wlr/types/wlr_xcursor_manager.h>
|
|
|
|
|
#include <wlr/types/wlr_idle.h>
|
|
|
|
|
#include <wlr/types/wlr_box.h>
|
|
|
|
|
#include <wlr/types/wlr_xcursor_manager.h>
|
|
|
|
|
#include <wlr/util/region.h>
|
|
|
|
|
#include "list.h"
|
|
|
|
|
#include "log.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
@ -327,8 +329,9 @@ void cursor_unhide(struct sway_cursor *cursor) {
|
|
|
|
|
cursor_rebase(cursor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cursor_send_pointer_motion(struct sway_cursor *cursor,
|
|
|
|
|
uint32_t time_msec) {
|
|
|
|
|
void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
|
|
|
|
struct sway_node *node, struct wlr_surface *surface,
|
|
|
|
|
double sx, double sy) {
|
|
|
|
|
if (time_msec == 0) {
|
|
|
|
|
time_msec = get_current_time_msec();
|
|
|
|
|
}
|
|
|
|
@ -343,12 +346,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct wlr_surface *surface = NULL;
|
|
|
|
|
double sx, sy;
|
|
|
|
|
|
|
|
|
|
struct sway_node *prev_node = cursor->previous.node;
|
|
|
|
|
struct sway_node *node = node_at_coords(seat,
|
|
|
|
|
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
|
|
|
|
|
|
|
|
|
|
// Update the stored previous position
|
|
|
|
|
cursor->previous.x = cursor->cursor->x;
|
|
|
|
@ -401,9 +399,62 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
|
|
|
|
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
|
|
|
|
|
struct wlr_event_pointer_motion *event = data;
|
|
|
|
|
cursor_handle_activity(cursor);
|
|
|
|
|
wlr_cursor_move(cursor->cursor, event->device,
|
|
|
|
|
event->delta_x, event->delta_y);
|
|
|
|
|
cursor_send_pointer_motion(cursor, event->time_msec);
|
|
|
|
|
|
|
|
|
|
double dx = event->delta_x;
|
|
|
|
|
double dy = event->delta_y;
|
|
|
|
|
|
|
|
|
|
struct wlr_surface *surface = NULL;
|
|
|
|
|
double sx, sy;
|
|
|
|
|
struct sway_node *node = node_at_coords(cursor->seat,
|
|
|
|
|
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
|
|
|
|
|
|
|
|
|
|
if (cursor->active_constraint) {
|
|
|
|
|
if (cursor->active_constraint->surface != surface) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double sx_confined, sy_confined;
|
|
|
|
|
if (!wlr_region_confine(&cursor->confine, sx, sy, sx + dx, sy + dy,
|
|
|
|
|
&sx_confined, &sy_confined)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dx = sx_confined - sx;
|
|
|
|
|
dy = sy_confined - sy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wlr_cursor_move(cursor->cursor, event->device, dx, dy);
|
|
|
|
|
cursor_send_pointer_motion(cursor, event->time_msec, node, surface,
|
|
|
|
|
sx + dx, sy + dy);
|
|
|
|
|
transaction_commit_dirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cursor_motion_absolute(struct sway_cursor *cursor,
|
|
|
|
|
uint32_t time_msec, struct wlr_input_device *dev,
|
|
|
|
|
double x, double y) {
|
|
|
|
|
cursor_handle_activity(cursor);
|
|
|
|
|
|
|
|
|
|
double lx, ly;
|
|
|
|
|
wlr_cursor_absolute_to_layout_coords(cursor->cursor, dev,
|
|
|
|
|
x, y, &lx, &ly);
|
|
|
|
|
|
|
|
|
|
struct wlr_surface *surface = NULL;
|
|
|
|
|
double sx, sy;
|
|
|
|
|
struct sway_node *node = node_at_coords(cursor->seat,
|
|
|
|
|
lx, ly, &surface, &sx, &sy);
|
|
|
|
|
|
|
|
|
|
if (cursor->active_constraint) {
|
|
|
|
|
if (cursor->active_constraint->surface != surface) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!pixman_region32_contains_point(&cursor->confine,
|
|
|
|
|
floor(sx), floor(sy), NULL)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wlr_cursor_warp_closest(cursor->cursor, dev, lx, ly);
|
|
|
|
|
cursor_send_pointer_motion(cursor, time_msec, node, surface, sx, sy);
|
|
|
|
|
transaction_commit_dirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -412,10 +463,9 @@ static void handle_cursor_motion_absolute(
|
|
|
|
|
struct sway_cursor *cursor =
|
|
|
|
|
wl_container_of(listener, cursor, motion_absolute);
|
|
|
|
|
struct wlr_event_pointer_motion_absolute *event = data;
|
|
|
|
|
cursor_handle_activity(cursor);
|
|
|
|
|
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
|
|
|
|
|
cursor_send_pointer_motion(cursor, event->time_msec);
|
|
|
|
|
transaction_commit_dirty();
|
|
|
|
|
|
|
|
|
|
cursor_motion_absolute(cursor, event->time_msec, event->device,
|
|
|
|
|
event->x, event->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -961,9 +1011,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
|
|
|
|
|
apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
|
|
|
|
|
cursor_send_pointer_motion(cursor, event->time_msec);
|
|
|
|
|
transaction_commit_dirty();
|
|
|
|
|
cursor_motion_absolute(cursor, event->time_msec, event->device, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
|
|
|
@ -1001,6 +1049,49 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
|
|
|
|
|
transaction_commit_dirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_constraint_region(struct sway_cursor *cursor) {
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint;
|
|
|
|
|
pixman_region32_t *region = &constraint->region;
|
|
|
|
|
struct sway_view *view = view_from_wlr_surface(constraint->surface);
|
|
|
|
|
if (view) {
|
|
|
|
|
struct sway_container *con = view->container;
|
|
|
|
|
|
|
|
|
|
double sx = cursor->cursor->x - con->content_x + view->geometry.x;
|
|
|
|
|
double sy = cursor->cursor->y - con->content_y + view->geometry.y;
|
|
|
|
|
|
|
|
|
|
if (!pixman_region32_contains_point(region,
|
|
|
|
|
floor(sx), floor(sy), NULL)) {
|
|
|
|
|
int nboxes;
|
|
|
|
|
pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes);
|
|
|
|
|
if (nboxes > 0) {
|
|
|
|
|
double sx = (boxes[0].x1 + boxes[0].x2) / 2.;
|
|
|
|
|
double sy = (boxes[0].y1 + boxes[0].y2) / 2.;
|
|
|
|
|
|
|
|
|
|
wlr_cursor_warp_closest(cursor->cursor, NULL,
|
|
|
|
|
sx + con->content_x - view->geometry.x,
|
|
|
|
|
sy + con->content_y - view->geometry.y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A locked pointer will result in an empty region, thus disallowing all movement
|
|
|
|
|
if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) {
|
|
|
|
|
pixman_region32_copy(&cursor->confine, region);
|
|
|
|
|
} else {
|
|
|
|
|
pixman_region32_clear(&cursor->confine);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void handle_constraint_commit(struct wl_listener *listener,
|
|
|
|
|
void *data) {
|
|
|
|
|
struct sway_cursor *cursor =
|
|
|
|
|
wl_container_of(listener, cursor, constraint_commit);
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint;
|
|
|
|
|
assert(constraint->surface == data);
|
|
|
|
|
|
|
|
|
|
check_constraint_region(cursor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void handle_request_set_cursor(struct wl_listener *listener,
|
|
|
|
|
void *data) {
|
|
|
|
|
struct sway_cursor *cursor =
|
|
|
|
@ -1162,6 +1253,8 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
|
|
|
|
|
&cursor->request_set_cursor);
|
|
|
|
|
cursor->request_set_cursor.notify = handle_request_set_cursor;
|
|
|
|
|
|
|
|
|
|
wl_list_init(&cursor->constraint_commit.link);
|
|
|
|
|
|
|
|
|
|
cursor->cursor = wlr_cursor;
|
|
|
|
|
|
|
|
|
|
return cursor;
|
|
|
|
@ -1284,3 +1377,107 @@ const char *get_mouse_button_name(uint32_t button) {
|
|
|
|
|
}
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) {
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint;
|
|
|
|
|
|
|
|
|
|
if (constraint->current.committed &
|
|
|
|
|
WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
|
|
|
|
|
double sx = constraint->current.cursor_hint.x;
|
|
|
|
|
double sy = constraint->current.cursor_hint.y;
|
|
|
|
|
|
|
|
|
|
struct sway_view *view = view_from_wlr_surface(constraint->surface);
|
|
|
|
|
struct sway_container *con = view->container;
|
|
|
|
|
|
|
|
|
|
double lx = sx + con->content_x - view->geometry.x;
|
|
|
|
|
double ly = sy + con->content_y - view->geometry.y;
|
|
|
|
|
|
|
|
|
|
wlr_cursor_warp(cursor->cursor, NULL, lx, ly);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_constraint_destroy(struct wl_listener *listener, void *data) {
|
|
|
|
|
struct sway_pointer_constraint *sway_constraint =
|
|
|
|
|
wl_container_of(listener, sway_constraint, destroy);
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint = data;
|
|
|
|
|
struct sway_seat *seat = constraint->seat->data;
|
|
|
|
|
struct sway_cursor *cursor = seat->cursor;
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&sway_constraint->destroy.link);
|
|
|
|
|
|
|
|
|
|
if (cursor->active_constraint == constraint) {
|
|
|
|
|
warp_to_constraint_cursor_hint(cursor);
|
|
|
|
|
|
|
|
|
|
if (cursor->constraint_commit.link.next != NULL) {
|
|
|
|
|
wl_list_remove(&cursor->constraint_commit.link);
|
|
|
|
|
}
|
|
|
|
|
wl_list_init(&cursor->constraint_commit.link);
|
|
|
|
|
cursor->active_constraint = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(sway_constraint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_pointer_constraint(struct wl_listener *listener, void *data) {
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint = data;
|
|
|
|
|
struct sway_seat *seat = constraint->seat->data;
|
|
|
|
|
|
|
|
|
|
struct sway_pointer_constraint *sway_constraint =
|
|
|
|
|
calloc(1, sizeof(struct sway_pointer_constraint));
|
|
|
|
|
sway_constraint->constraint = constraint;
|
|
|
|
|
|
|
|
|
|
sway_constraint->destroy.notify = handle_constraint_destroy;
|
|
|
|
|
wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
|
|
|
|
|
|
|
|
|
|
struct sway_node *focus = seat_get_focus(seat);
|
|
|
|
|
if (focus && focus->type == N_CONTAINER && focus->sway_container->view) {
|
|
|
|
|
struct wlr_surface *surface = focus->sway_container->view->surface;
|
|
|
|
|
if (surface == constraint->surface) {
|
|
|
|
|
sway_cursor_constrain(seat->cursor, constraint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sway_cursor_constrain(struct sway_cursor *cursor,
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint) {
|
|
|
|
|
if (cursor->active_constraint == constraint) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&cursor->constraint_commit.link);
|
|
|
|
|
if (cursor->active_constraint) {
|
|
|
|
|
if (constraint == NULL) {
|
|
|
|
|
warp_to_constraint_cursor_hint(cursor);
|
|
|
|
|
}
|
|
|
|
|
wlr_pointer_constraint_v1_send_deactivated(
|
|
|
|
|
cursor->active_constraint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor->active_constraint = constraint;
|
|
|
|
|
|
|
|
|
|
if (constraint == NULL) {
|
|
|
|
|
wl_list_init(&cursor->constraint_commit.link);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: Big hack, stolen from wlr_pointer_constraints_v1.c:121.
|
|
|
|
|
// This is necessary because the focus may be set before the surface
|
|
|
|
|
// has finished committing, which means that warping won't work properly,
|
|
|
|
|
// since this code will be run *after* the focus has been set.
|
|
|
|
|
// That is why we duplicate the code here.
|
|
|
|
|
if (pixman_region32_not_empty(&constraint->current.region)) {
|
|
|
|
|
pixman_region32_intersect(&constraint->region,
|
|
|
|
|
&constraint->surface->input_region, &constraint->current.region);
|
|
|
|
|
} else {
|
|
|
|
|
pixman_region32_copy(&constraint->region,
|
|
|
|
|
&constraint->surface->input_region);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_constraint_region(cursor);
|
|
|
|
|
|
|
|
|
|
wlr_pointer_constraint_v1_send_activated(constraint);
|
|
|
|
|
|
|
|
|
|
cursor->constraint_commit.notify = handle_constraint_commit;
|
|
|
|
|
wl_signal_add(&constraint->surface->events.commit,
|
|
|
|
|
&cursor->constraint_commit);
|
|
|
|
|
}
|
|
|
|
|