diff --git a/nedm.c b/nedm.c index 070a13d..064b052 100644 --- a/nedm.c +++ b/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; -} +} \ No newline at end of file diff --git a/seat.c b/seat.c index ea1b324..39e0b21 100644 --- a/seat.c +++ b/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); diff --git a/seat.h b/seat.h index f5ecc88..9eafc01 100644 --- a/seat.h +++ b/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; diff --git a/view.c b/view.c index 481766f..60dcbc8 100644 --- a/view.c +++ b/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; +} diff --git a/view.h b/view.h index 67adf26..c122b6c 100644 --- a/view.h +++ b/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