Fixed pointer constraint - FINALLY
This commit is contained in:
parent
bdad659d7c
commit
e86e24c48e
79
nedm.c
79
nedm.c
|
@ -65,49 +65,6 @@
|
|||
#include "xwayland.h"
|
||||
#endif
|
||||
|
||||
static void handle_constraint_destroy(struct wl_listener *listener, __attribute__((unused)) void *data) {
|
||||
struct nedm_seat *seat = wl_container_of(listener, seat, constraint_destroy);
|
||||
seat->active_constraint = NULL;
|
||||
wl_list_remove(&seat->constraint_destroy.link);
|
||||
}
|
||||
|
||||
static void handle_new_pointer_constraint(struct wl_listener *listener, void *data) {
|
||||
struct nedm_server *server = wl_container_of(listener, server, new_pointer_constraint);
|
||||
struct wlr_pointer_constraint_v1 *constraint = data;
|
||||
|
||||
// Check if constraint is for the focused surface
|
||||
struct wlr_surface *focused_surface = server->seat->seat->pointer_state.focused_surface;
|
||||
if (focused_surface == constraint->surface) {
|
||||
// Clear any existing constraint
|
||||
if (server->seat->active_constraint) {
|
||||
wlr_pointer_constraint_v1_send_deactivated(server->seat->active_constraint);
|
||||
wl_list_remove(&server->seat->constraint_destroy.link);
|
||||
}
|
||||
|
||||
// Set as active constraint
|
||||
server->seat->active_constraint = constraint;
|
||||
server->seat->constraint_destroy.notify = handle_constraint_destroy;
|
||||
wl_signal_add(&constraint->events.destroy, &server->seat->constraint_destroy);
|
||||
|
||||
wlr_pointer_constraint_v1_send_activated(constraint);
|
||||
|
||||
// For locked pointer, warp cursor to surface center for now
|
||||
if (constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// Get view position and size
|
||||
if (server->seat->focused_view) {
|
||||
int gx, gy;
|
||||
wlr_scene_node_coords(&server->seat->focused_view->scene_tree->node, &gx, &gy);
|
||||
|
||||
// Warp to center of view (simplified - not using constraint region)
|
||||
struct wlr_surface *surface = constraint->surface;
|
||||
double cx = (double)gx + surface->current.width / 2.0;
|
||||
double cy = (double)gy + surface->current.height / 2.0;
|
||||
wlr_cursor_warp(server->seat->cursor, NULL, cx, cy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WAIT_ANY
|
||||
#define WAIT_ANY -1
|
||||
#endif
|
||||
|
@ -562,6 +519,21 @@ main(int argc, char *argv[]) {
|
|||
server.new_output.notify = handle_new_output;
|
||||
wl_signal_add(&backend->events.new_output, &server.new_output);
|
||||
|
||||
// Initialize pointer constraints and relative pointer protocols
|
||||
server.pointer_constraints = wlr_pointer_constraints_v1_create(server.wl_display);
|
||||
if(!server.pointer_constraints) {
|
||||
wlr_log(WLR_ERROR, "Unable to create pointer constraints manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server.wl_display);
|
||||
if(!server.relative_pointer_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create relative pointer manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.seat = seat_create(&server);
|
||||
if(!server.seat) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the seat");
|
||||
|
@ -664,25 +636,6 @@ main(int argc, char *argv[]) {
|
|||
// Initialize layer shell
|
||||
nedm_layer_shell_init(&server);
|
||||
|
||||
// Initialize pointer constraints and relative pointer protocols
|
||||
server.pointer_constraints = wlr_pointer_constraints_v1_create(server.wl_display);
|
||||
if(!server.pointer_constraints) {
|
||||
wlr_log(WLR_ERROR, "Unable to create pointer constraints manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server.wl_display);
|
||||
if(!server.relative_pointer_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create relative pointer manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Set up pointer constraint event handler
|
||||
server.new_pointer_constraint.notify = handle_new_pointer_constraint;
|
||||
wl_signal_add(&server.pointer_constraints->events.new_constraint, &server.new_pointer_constraint);
|
||||
|
||||
#if NEDM_HAS_XWAYLAND
|
||||
server.xwayland = wlr_xwayland_create(server.wl_display, compositor, true);
|
||||
if(!server.xwayland) {
|
||||
|
@ -891,4 +844,4 @@ end:
|
|||
FcFini();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
149
seat.c
149
seat.c
|
@ -689,6 +689,26 @@ handle_cursor_button(struct wl_listener *listener, void *data) {
|
|||
|
||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button,
|
||||
event->state);
|
||||
|
||||
if(event->state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
double sx, sy;
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||
&seat->server->scene->tree.node, seat->cursor->x, seat->cursor->y,
|
||||
&sx, &sy);
|
||||
if(node && node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_try_from_buffer(
|
||||
wlr_scene_buffer_from_node(node));
|
||||
if(scene_surface) {
|
||||
struct nedm_view *view = view_from_wlr_surface(
|
||||
seat->server, scene_surface->surface);
|
||||
if(view) {
|
||||
seat_set_focus(seat, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||
}
|
||||
|
||||
|
@ -710,45 +730,62 @@ process_cursor_motion(struct nedm_seat *seat, uint32_t time) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check for active pointer constraint
|
||||
if (seat->active_constraint) {
|
||||
bool skip_update = false;
|
||||
if(seat->active_constraint) {
|
||||
struct wlr_pointer_constraint_v1 *constraint = seat->active_constraint;
|
||||
|
||||
// Deactivate constraint if surface changed
|
||||
if (constraint->surface != surface) {
|
||||
if(constraint->surface != surface) {
|
||||
wlr_pointer_constraint_v1_send_deactivated(constraint);
|
||||
wl_list_remove(&seat->constraint_destroy.link);
|
||||
seat->active_constraint = NULL;
|
||||
} else {
|
||||
// Handle constraint behavior
|
||||
if (constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// For locked pointer, don't move cursor but still process enter/motion
|
||||
if (surface && time > 0) {
|
||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
||||
} else if(constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// For locked pointer, do not move or warp the cursor, just notify enter/motion
|
||||
if(surface) {
|
||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
||||
if(time > 0) {
|
||||
wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy);
|
||||
}
|
||||
goto skip_cursor_update;
|
||||
}
|
||||
|
||||
// For confined constraints, clamp cursor to region
|
||||
if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) {
|
||||
// TODO: Implement proper confinement
|
||||
// For now, just allow the motion
|
||||
}
|
||||
// Do not warp or clamp the cursor for locked pointer
|
||||
skip_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(surface != NULL) {
|
||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
||||
bool focus_changed = wlr_seat->pointer_state.focused_surface != surface;
|
||||
if(!focus_changed && time > 0) {
|
||||
wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy);
|
||||
if(!skip_update) {
|
||||
if(surface) {
|
||||
bool focus_changed =
|
||||
wlr_seat->pointer_state.focused_surface != surface;
|
||||
if(!focus_changed && time > 0) {
|
||||
wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy);
|
||||
}
|
||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
||||
} else {
|
||||
wlr_seat_pointer_clear_focus(wlr_seat);
|
||||
}
|
||||
} else {
|
||||
wlr_seat_pointer_clear_focus(wlr_seat);
|
||||
}
|
||||
|
||||
skip_cursor_update:
|
||||
if(seat->active_constraint &&
|
||||
seat->active_constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) {
|
||||
struct wlr_box surface_box;
|
||||
wlr_surface_get_extents(seat->active_constraint->surface, &surface_box);
|
||||
double sx = seat->cursor->x - surface_box.x;
|
||||
double sy = seat->cursor->y - surface_box.y;
|
||||
|
||||
if(sx < 0) {
|
||||
sx = 0;
|
||||
}
|
||||
if(sy < 0) {
|
||||
sy = 0;
|
||||
}
|
||||
if(sx > surface_box.width) {
|
||||
sx = surface_box.width;
|
||||
}
|
||||
if(sy > surface_box.height) {
|
||||
sy = surface_box.height;
|
||||
}
|
||||
|
||||
wlr_cursor_warp(seat->cursor, NULL, surface_box.x + sx,
|
||||
surface_box.y + sy);
|
||||
}
|
||||
|
||||
struct nedm_drag_icon *drag_icon;
|
||||
wl_list_for_each(drag_icon, &seat->drag_icons, link) {
|
||||
|
@ -788,10 +825,7 @@ skip_cursor_update:
|
|||
seat->server->running) {
|
||||
ipc_send_event(
|
||||
seat->server,
|
||||
"{\"event_name\":\"cursor_switch_tile\",\"old_output\":"
|
||||
"\"%s\",\"old_output_id\":%d,"
|
||||
"\"old_tile\":%d,\"new_output\":\"%s\",\"new_output_"
|
||||
"id\":%d,\"new_tile\":%d}",
|
||||
"{'event_name':'cursor_switch_tile','old_output':'%s','old_output_id':%d,'old_tile':%d,'new_output':'%s','new_output_id':%d,'new_tile':%d}",
|
||||
seat->cursor_tile->workspace->output->name,
|
||||
output_get_num(seat->cursor_tile->workspace->output),
|
||||
seat->cursor_tile->id, c_outp->name, output_get_num(nedm_outp),
|
||||
|
@ -818,6 +852,21 @@ handle_cursor_motion(struct wl_listener *listener, void *data) {
|
|||
struct nedm_seat *seat = wl_container_of(listener, seat, cursor_motion);
|
||||
struct wlr_pointer_motion_event *event = data;
|
||||
|
||||
// If pointer is locked, do not move the visible cursor, only send relative motion
|
||||
if (seat->active_constraint && seat->active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// Only send relative motion to the client
|
||||
if (seat->server->relative_pointer_manager) {
|
||||
wlr_relative_pointer_manager_v1_send_relative_motion(
|
||||
seat->server->relative_pointer_manager, seat->seat,
|
||||
(uint64_t)event->time_msec * 1000, event->delta_x, event->delta_y,
|
||||
event->unaccel_dx, event->unaccel_dy);
|
||||
}
|
||||
// Notify the surface of motion (for button state, etc)
|
||||
process_cursor_motion(seat, event->time_msec);
|
||||
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_cursor_move(seat->cursor, &event->pointer->base, event->delta_x,
|
||||
event->delta_y);
|
||||
process_cursor_motion(seat, event->time_msec);
|
||||
|
@ -825,9 +874,9 @@ handle_cursor_motion(struct wl_listener *listener, void *data) {
|
|||
// Send relative motion AFTER cursor position is updated
|
||||
if (seat->server->relative_pointer_manager) {
|
||||
wlr_relative_pointer_manager_v1_send_relative_motion(
|
||||
seat->server->relative_pointer_manager, seat->seat,
|
||||
(uint64_t)event->time_msec * 1000, event->delta_x, event->delta_y,
|
||||
event->unaccel_dx, event->unaccel_dy);
|
||||
seat->server->relative_pointer_manager, seat->seat,
|
||||
(uint64_t)event->time_msec * 1000, event->delta_x, event->delta_y,
|
||||
event->unaccel_dx, event->unaccel_dy);
|
||||
}
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||
|
@ -927,6 +976,35 @@ handle_start_drag(struct wl_listener *listener, void *data) {
|
|||
drag_icon_update_position(drag_icon);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_constraint_destroy(struct wl_listener *listener,
|
||||
__attribute__((unused)) void *data) {
|
||||
struct nedm_seat *seat = wl_container_of(listener, seat, constraint_destroy);
|
||||
seat->active_constraint = NULL;
|
||||
wl_list_remove(&seat->constraint_destroy.link);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_new_constraint(struct wl_listener *listener, void *data) {
|
||||
struct nedm_seat *seat = wl_container_of(listener, seat, new_constraint);
|
||||
struct wlr_pointer_constraint_v1 *constraint = data;
|
||||
|
||||
// If there's an existing constraint, destroy it
|
||||
if (seat->active_constraint) {
|
||||
wlr_pointer_constraint_v1_send_deactivated(seat->active_constraint);
|
||||
wl_list_remove(&seat->constraint_destroy.link);
|
||||
seat->active_constraint = NULL;
|
||||
}
|
||||
|
||||
seat->active_constraint = constraint;
|
||||
wl_signal_add(&constraint->events.destroy, &seat->constraint_destroy);
|
||||
seat->constraint_destroy.notify = handle_constraint_destroy;
|
||||
|
||||
// Activate the constraint
|
||||
wlr_pointer_constraint_v1_send_activated(constraint);
|
||||
process_cursor_motion(seat, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_destroy(struct wl_listener *listener,
|
||||
__attribute__((unused)) void *_data) {
|
||||
|
@ -1040,6 +1118,10 @@ seat_create(struct nedm_server *server) {
|
|||
wl_signal_add(&seat->seat->events.request_set_primary_selection,
|
||||
&seat->request_set_primary_selection);
|
||||
|
||||
seat->new_constraint.notify = handle_new_constraint;
|
||||
wl_signal_add(&server->pointer_constraints->events.new_constraint,
|
||||
&seat->new_constraint);
|
||||
|
||||
wl_list_init(&seat->keyboard_groups);
|
||||
seat->num_keyboards = 0;
|
||||
seat->num_pointers = 0;
|
||||
|
@ -1072,6 +1154,7 @@ seat_destroy(struct nedm_seat *seat) {
|
|||
seat->active_constraint = NULL;
|
||||
}
|
||||
|
||||
wl_list_remove(&seat->new_constraint.link);
|
||||
wl_list_remove(&seat->request_start_drag.link);
|
||||
wl_list_remove(&seat->start_drag.link);
|
||||
|
||||
|
|
1
seat.h
1
seat.h
|
@ -37,6 +37,7 @@ struct nedm_seat {
|
|||
struct wlr_xcursor_manager *xcursor_manager;
|
||||
struct wlr_pointer_constraint_v1 *active_constraint;
|
||||
struct wl_listener constraint_destroy;
|
||||
struct wl_listener new_constraint;
|
||||
struct wl_listener cursor_motion;
|
||||
struct wl_listener cursor_motion_absolute;
|
||||
struct wl_listener cursor_button;
|
||||
|
|
19
view.c
19
view.c
|
@ -238,3 +238,22 @@ view_init(struct nedm_view *view, enum nedm_view_type type,
|
|||
server->curr_output->workspaces[server->curr_output->curr_workspace]
|
||||
->scene);
|
||||
}
|
||||
|
||||
struct nedm_view *
|
||||
view_from_wlr_surface(struct nedm_server *server,
|
||||
struct wlr_surface *surface) {
|
||||
struct nedm_view *view = NULL;
|
||||
struct nedm_workspace *ws =
|
||||
server->curr_output->workspaces[server->curr_output->curr_workspace];
|
||||
wl_list_for_each(view, &ws->views, link) {
|
||||
if(view->wlr_surface == surface) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
wl_list_for_each(view, &ws->unmanaged_views, link) {
|
||||
if(view->wlr_surface == surface) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
3
view.h
3
view.h
|
@ -73,5 +73,8 @@ view_init(struct nedm_view *view, enum nedm_view_type type,
|
|||
const struct nedm_view_impl *impl, struct nedm_server *server);
|
||||
struct nedm_view *
|
||||
view_get_prev_view(struct nedm_view *view);
|
||||
struct nedm_view *
|
||||
view_from_wlr_surface(struct nedm_server *server,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue