168
src/LunarWM.c
168
src/LunarWM.c
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user