Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-08-11 11:00:15 +03:00
parent 971040e038
commit 70ff013dbc
2 changed files with 167 additions and 5 deletions

View File

@@ -63,6 +63,7 @@ void toplevel_commit_notify(struct wl_listener *l, void *)
LunarWM_Toplevel_update(tl);
}
static void focus_fallback(LunarWM *wm);
void toplevel_destroy_notify(struct wl_listener *l, void *)
{
auto *tl = wl_container_of(l, (LunarWM_Toplevel *)(NULL), destroy);
@@ -73,10 +74,66 @@ void toplevel_destroy_notify(struct wl_listener *l, void *)
break;
}
}
focus_fallback(tl->server);
LunarWM_Toplevel_destroy(tl);
free(tl);
}
static void toplevel_map_notify(struct wl_listener *l, void *data)
{
(void)data;
LunarWM_Toplevel *tl = wl_container_of(l, (LunarWM_Toplevel *)0, map);
if (!tl || !tl->surface)
return;
if (tl->is_xwayland && tl->u.xwl) {
if (tl->u.xwl->override_redirect
&& !wlr_xwayland_surface_override_redirect_wants_focus(tl->u.xwl)) {
return;
}
}
LunarWM_Toplevel_focus(tl);
LunarWM *wm = tl->server;
for (size_t i = 0; i < vector_size(wm->wayland.v_toplevels); ++i) {
if (wm->wayland.v_toplevels[i] == tl) {
wm->wayland.current_focus = (int)i;
break;
}
}
}
static void toplevel_unmap_notify(struct wl_listener *l, void *data)
{
(void)data;
LunarWM_Toplevel *tl = wl_container_of(l, tl, unmap);
if (!tl || !tl->surface)
return;
// detach per-surface listeners/resources
if (tl->map.link.prev || tl->map.link.next)
wl_list_remove(&tl->map.link);
if (tl->unmap.link.prev || tl->unmap.link.next)
wl_list_remove(&tl->unmap.link);
if (tl->commit.link.prev || tl->commit.link.next)
wl_list_remove(&tl->commit.link);
if (tl->locked_buffer) {
wlr_buffer_unlock(tl->locked_buffer);
tl->locked_buffer = NULL;
}
tl->texture = NULL;
tl->gles_texture = NULL;
tl->rl_texture = (Texture) { 0 };
tl->surface = NULL;
// If the thing that unmapped was focused, pick a fallback
focus_fallback(tl->server);
}
bool LunarWM_Toplevel_init_xdg(
LunarWM_Toplevel *tl, LunarWM *wm, struct wlr_xdg_toplevel *xdg)
{
@@ -94,6 +151,12 @@ bool LunarWM_Toplevel_init_xdg(
tl->destroy.notify = toplevel_destroy_notify;
wl_signal_add(&tl->surface->events.destroy, &tl->destroy);
tl->map.notify = toplevel_map_notify;
wl_signal_add(&tl->u.xdg->base->surface->events.map, &tl->map);
tl->unmap.notify = toplevel_unmap_notify;
wl_signal_add(&tl->u.xdg->base->surface->events.unmap, &tl->unmap);
return true;
}
@@ -105,7 +168,6 @@ bool LunarWM_Toplevel_init_xwayland(
tl->is_xwayland = true;
tl->u.xwl = xwl;
tl->surface = xwl->surface;
assert(tl->surface);
tl->commit.notify = toplevel_commit_notify;
@@ -114,16 +176,29 @@ bool LunarWM_Toplevel_init_xwayland(
tl->destroy.notify = toplevel_destroy_notify;
wl_signal_add(&tl->surface->events.destroy, &tl->destroy);
tl->map.notify = toplevel_map_notify;
wl_signal_add(&xwl->surface->events.map, &tl->map);
tl->unmap.notify = toplevel_unmap_notify;
wl_signal_add(&xwl->surface->events.unmap, &tl->unmap);
return true;
}
bool LunarWM_Toplevel_destroy(LunarWM_Toplevel *this)
{
wl_list_remove(&this->commit.link);
wl_list_remove(&this->destroy.link);
if (this->locked_buffer != nullptr) {
if (!this)
return false;
if (this->map.link.prev || this->map.link.next)
wl_list_remove(&this->map.link);
if (this->unmap.link.prev || this->unmap.link.next)
wl_list_remove(&this->unmap.link);
if (this->commit.link.prev || this->commit.link.next)
wl_list_remove(&this->commit.link);
if (this->destroy.link.prev || this->destroy.link.next)
wl_list_remove(&this->destroy.link);
if (this->locked_buffer)
wlr_buffer_unlock(this->locked_buffer);
}
return true;
}
@@ -210,6 +285,7 @@ struct XwlHooks {
struct wl_listener req_configure;
struct wl_listener req_maximize;
struct wl_listener req_fullscreen;
struct wl_listener req_activate;
struct wl_listener set_geometry;
};
@@ -290,6 +366,10 @@ static void xwl_unmap_toplevel(LunarWM_Toplevel *tl)
if (!tl)
return;
if (tl->map.link.prev || tl->map.link.next)
wl_list_remove(&tl->map.link);
if (tl->unmap.link.prev || tl->unmap.link.next)
wl_list_remove(&tl->unmap.link);
if (tl->commit.link.prev || tl->commit.link.next)
wl_list_remove(&tl->commit.link);
if (tl->destroy.link.prev || tl->destroy.link.next)
@@ -319,6 +399,8 @@ static void xwl_on_dissociate(struct wl_listener *ll, void *data)
break;
}
}
focus_fallback(wm);
}
static void xwl_on_request_configure(struct wl_listener *ll, void *data)
@@ -357,6 +439,18 @@ static void xwl_on_request_fullscreen(struct wl_listener *ll, void *data)
wlr_xwayland_surface_set_fullscreen(xh->xwl, true);
}
static void xwl_on_request_activate(struct wl_listener *ll, void *data)
{
struct XwlHooks *h = wl_container_of(ll, h, req_activate);
for (size_t i = 0; i < vector_size(h->wm->wayland.v_toplevels); ++i) {
LunarWM_Toplevel *tl = h->wm->wayland.v_toplevels[i];
if (tl->is_xwayland && tl->u.xwl == h->xwl) {
LunarWM_Toplevel_focus(tl);
break;
}
}
}
static void xwl_on_set_geometry(struct wl_listener *ll, void *data)
{
(void)ll;
@@ -375,6 +469,8 @@ static void xwl_on_destroy(struct wl_listener *ll, void *data)
wl_list_remove(&xh->req_maximize.link);
if (xh->req_fullscreen.link.prev)
wl_list_remove(&xh->req_fullscreen.link);
if (xh->req_activate.link.prev)
wl_list_remove(&xh->req_activate.link);
if (xh->set_geometry.link.prev)
wl_list_remove(&xh->set_geometry.link);
if (xh->associate.link.prev)
@@ -393,9 +489,60 @@ static void xwl_on_destroy(struct wl_listener *ll, void *data)
}
}
focus_fallback(wm);
free(xh);
}
static bool xwl_wants_focus(struct wlr_xwayland_surface *x)
{
if (!x)
return false;
if (!x->surface)
return false;
if (x->override_redirect
&& !wlr_xwayland_surface_override_redirect_wants_focus(x)) {
return false;
}
if (x->withdrawn || x->minimized)
return false;
return true;
}
static void focus_fallback(LunarWM *wm)
{
if (!wm || !wm->wayland.seat)
return;
for (ssize_t i = (ssize_t)vector_size(wm->wayland.v_toplevels) - 1; i >= 0;
--i) {
LunarWM_Toplevel *cand = wm->wayland.v_toplevels[i];
if (!cand || !cand->surface)
continue;
if (cand->is_xwayland) {
if (!xwl_wants_focus(cand->u.xwl))
continue;
}
LunarWM_Toplevel_focus(cand);
wm->wayland.current_focus = (int)i;
return;
}
struct wlr_seat *seat = wm->wayland.seat;
struct wlr_surface *prev = seat->keyboard_state.focused_surface;
if (prev) {
struct wlr_xdg_toplevel *pt;
struct wlr_xwayland_surface *px;
if ((pt = wlr_xdg_toplevel_try_from_wlr_surface(prev)))
wlr_xdg_toplevel_set_activated(pt, false);
if ((px = wlr_xwayland_surface_try_from_wlr_surface(prev)))
wlr_xwayland_surface_activate(px, false);
}
wlr_seat_keyboard_clear_focus(seat);
wm->wayland.current_focus = -1;
}
static void xwayland_new_surface_notify(struct wl_listener *l, void *data)
{
LunarWM *wm = wl_container_of(l, wm, wayland.xwayland_new_surface);
@@ -430,6 +577,9 @@ static void xwayland_new_surface_notify(struct wl_listener *l, void *data)
h->req_fullscreen.notify = xwl_on_request_fullscreen;
wl_signal_add(&xwl->events.request_fullscreen, &h->req_fullscreen);
h->req_activate.notify = xwl_on_request_activate;
wl_signal_add(&xwl->events.request_activate, &h->req_activate);
h->set_geometry.notify = xwl_on_set_geometry;
wl_signal_add(&xwl->events.set_geometry, &h->set_geometry);
@@ -2560,6 +2710,12 @@ static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
info->layers[info->layers_count++]
= (XrCompositionLayerBaseHeader *)&info->layer_projection;
if (this->renderer.first_frame) {
l_recenter(this->cman->L);
lua_pop(this->cman->L, 1);
this->renderer.first_frame = false;
}
return true;
}
@@ -2568,6 +2724,8 @@ void LunarWM_run(LunarWM *this)
assert(this);
assert(this->initialized);
this->renderer.first_frame = true;
if (!wlr_backend_start(this->wayland.backend)) {
wlr_log(WLR_ERROR, "Failed to start backend");
return;

View File

@@ -75,6 +75,8 @@ typedef struct {
struct wl_listener commit;
struct wl_listener destroy;
struct wl_listener map, unmap;
union {
struct wlr_xdg_toplevel *xdg;
struct wlr_xwayland_surface *xwl;
@@ -206,6 +208,8 @@ typedef struct LunarWM {
Shader linear_srgb;
Skybox skybox;
bool first_frame;
} renderer;
ConfigManager *cman;