wl_backend: standalone DRM/KMS mode, fix pointer focus and keyboard delivery
- Use wlr_backend_autocreate for standalone mode (from TTY) instead of headless-only. Gives real DRM/KMS output + libinput. - wl_update_pointer_focus: skip client surface focus when pointer is over an internal frame_buf (menu, titlebar). Prevents client from stealing cursor/events from WM chrome. - wl_focus_set: ensure seat keyboard is set and flush clients before sending keyboard.enter so client has processed wl_seat.capabilities. - Renderer and allocator use the autocreated backend in standalone mode.
This commit is contained in:
parent
213f5a6528
commit
62b8e4254e
|
|
@ -1768,10 +1768,13 @@ handle_backend_new_input(struct wl_listener *listener, void *data)
|
|||
}
|
||||
case WLR_INPUT_DEVICE_POINTER: {
|
||||
struct wlr_pointer *ptr = wlr_pointer_from_input_device(dev);
|
||||
/* Nested backend delivers absolute motion events (host cursor
|
||||
* position normalised to [0,1]); no relative motion needed. */
|
||||
wl_state.real_pointer_dev = dev;
|
||||
wl_state.pointer_dev = dev;
|
||||
/* Relative motion (libinput / standalone DRM) */
|
||||
wl_state.pointer_motion_listener.notify = handle_pointer_motion;
|
||||
wl_signal_add(&ptr->events.motion,
|
||||
&wl_state.pointer_motion_listener);
|
||||
/* Absolute motion (nested Wayland backend) */
|
||||
wl_state.real_pointer_motion_abs_listener.notify =
|
||||
handle_pointer_motion_absolute;
|
||||
wl_signal_add(&ptr->events.motion_absolute,
|
||||
|
|
@ -1782,11 +1785,10 @@ handle_backend_new_input(struct wl_listener *listener, void *data)
|
|||
wl_state.real_pointer_frame_listener.notify = handle_pointer_frame;
|
||||
wl_signal_add(&ptr->events.frame,
|
||||
&wl_state.real_pointer_frame_listener);
|
||||
/* Phase 29: axis (scroll wheel) from real nested pointer. */
|
||||
wl_state.real_pointer_axis_listener.notify = handle_pointer_axis;
|
||||
wl_signal_add(&ptr->events.axis,
|
||||
&wl_state.real_pointer_axis_listener);
|
||||
wwarning("wl_backend: real pointer wired from nested backend");
|
||||
wwarning("wl_backend: real pointer wired");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -2070,7 +2072,7 @@ wl_display_open(const char *name)
|
|||
wl_state.wl_backend_inner = wlr_wl_backend_create(
|
||||
wl_display_get_event_loop(wl_state.display), NULL);
|
||||
if (!wl_state.wl_backend_inner) {
|
||||
wwarning("wl_backend: failed to create nested Wayland backend; falling back to headless");
|
||||
wwarning("wl_backend: failed to create nested Wayland backend; falling back to standalone");
|
||||
wl_state.is_nested = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2083,15 +2085,28 @@ wl_display_open(const char *name)
|
|||
wl_state.backend = multi;
|
||||
wwarning("wl_backend: nested Wayland compositor mode");
|
||||
} else {
|
||||
wl_state.backend = wl_state.headless_inner;
|
||||
wwarning("wl_backend: headless compositor mode");
|
||||
/* Standalone: use autocreate to get DRM/KMS + libinput on real hardware.
|
||||
* Clear DISPLAY and WAYLAND_DISPLAY so wlroots goes straight to DRM. */
|
||||
unsetenv("DISPLAY");
|
||||
unsetenv("WAYLAND_DISPLAY");
|
||||
struct wlr_session *session = NULL;
|
||||
wl_state.backend = wlr_backend_autocreate(
|
||||
wl_display_get_event_loop(wl_state.display), &session);
|
||||
if (!wl_state.backend) {
|
||||
wwarning("wl_backend: wlr_backend_autocreate failed; falling back to headless");
|
||||
wl_state.backend = wl_state.headless_inner;
|
||||
} else {
|
||||
wwarning("wl_backend: standalone DRM/KMS compositor mode");
|
||||
}
|
||||
}
|
||||
|
||||
/* Renderer: prefer the Wayland backend (EGL) in nested mode; fall back
|
||||
* to headless (pixman software) for the pure-headless case. */
|
||||
/* Renderer: use the appropriate backend as source. */
|
||||
{
|
||||
struct wlr_backend *render_src = wl_state.wl_backend_inner
|
||||
? wl_state.wl_backend_inner : wl_state.headless_inner;
|
||||
struct wlr_backend *render_src;
|
||||
if (wl_state.wl_backend_inner)
|
||||
render_src = wl_state.wl_backend_inner;
|
||||
else
|
||||
render_src = wl_state.backend;
|
||||
wl_state.renderer = wlr_renderer_autocreate(render_src);
|
||||
}
|
||||
if (!wl_state.renderer) {
|
||||
|
|
@ -2103,10 +2118,10 @@ wl_display_open(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocator (Phase 18) — needed for wlr_output_init_render. */
|
||||
/* Allocator — needed for wlr_output_init_render. */
|
||||
{
|
||||
struct wlr_backend *alloc_src = wl_state.wl_backend_inner
|
||||
? wl_state.wl_backend_inner : wl_state.headless_inner;
|
||||
? wl_state.wl_backend_inner : wl_state.backend;
|
||||
wl_state.allocator = wlr_allocator_autocreate(alloc_src, wl_state.renderer);
|
||||
}
|
||||
if (!wl_state.allocator)
|
||||
|
|
@ -4135,6 +4150,13 @@ wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp)
|
|||
}
|
||||
if (!v->xdg_surface || !v->xdg_surface->surface)
|
||||
return;
|
||||
if (wl_state.keyboard_dev) {
|
||||
struct wlr_keyboard *kb = wlr_keyboard_from_input_device(wl_state.keyboard_dev);
|
||||
wlr_seat_set_keyboard(wl_state.seat, kb);
|
||||
}
|
||||
/* Flush pending events to client so it has processed wl_seat.capabilities
|
||||
* and bound wl_keyboard before we send keyboard.enter. */
|
||||
wl_display_flush_clients(wl_state.display);
|
||||
wlr_seat_keyboard_notify_enter(wl_state.seat,
|
||||
v->xdg_surface->surface,
|
||||
NULL, 0, NULL);
|
||||
|
|
@ -4902,17 +4924,19 @@ wl_update_pointer_focus(uint32_t time_msec)
|
|||
|
||||
double sx, sy;
|
||||
struct wl_toplevel_view *view = NULL;
|
||||
struct wlr_surface *surface = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &view);
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
/* If pointer is over an internal frame_buf (menu, titlebar, etc.),
|
||||
* don't send pointer events to any client surface. */
|
||||
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x, wl_state.pointer_y);
|
||||
if (!fb)
|
||||
surface = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &view);
|
||||
|
||||
static struct wlr_surface *last_focused_surface = NULL;
|
||||
if (surface) {
|
||||
if (surface != last_focused_surface) {
|
||||
wwarning("wl_backend: pointer focus entered surface %p at %.1f,%.1f",
|
||||
(void *)surface, sx, sy);
|
||||
last_focused_surface = surface;
|
||||
/* Reset to default cursor; client will override via
|
||||
* request_set_cursor after receiving wl_pointer.enter. */
|
||||
wl_set_cursor_image("left_ptr");
|
||||
}
|
||||
wlr_seat_pointer_notify_enter(wl_state.seat, surface, sx, sy);
|
||||
|
|
@ -4920,7 +4944,6 @@ wl_update_pointer_focus(uint32_t time_msec)
|
|||
wlr_seat_pointer_notify_frame(wl_state.seat);
|
||||
} else {
|
||||
if (last_focused_surface) {
|
||||
wwarning("wl_backend: pointer left all surfaces");
|
||||
last_focused_surface = NULL;
|
||||
}
|
||||
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||
|
|
|
|||
|
|
@ -915,8 +915,9 @@ void wMenuMapAt(WMenu * menu, int x, int y, int keyboard)
|
|||
wm_backend->window_move((WNativeWindow)menu->frame->core->window, x, y);
|
||||
menu->frame_x = x;
|
||||
menu->frame_y = y;
|
||||
if (menu->frame->core->window)
|
||||
if (menu->frame->core->window) {
|
||||
wm_backend->window_map((WNativeWindow)menu->frame->core->window);
|
||||
}
|
||||
wRaiseFrame(menu->frame->core);
|
||||
menu->flags.mapped = 1;
|
||||
wMenuPaint(menu);
|
||||
|
|
|
|||
Loading…
Reference in New Issue