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