Merge branch 'main' into wlroots-next

This commit is contained in:
Guido Cella
2026-11-11 11:18:41 +01:00
2 changed files with 114 additions and 34 deletions
+2
View File
@@ -98,6 +98,8 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
xdg_surface = tmp_xdg_surface; xdg_surface = tmp_xdg_surface;
break; break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL: case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
if (!xdg_surface->toplevel)
return -1;
c = xdg_surface->data; c = xdg_surface->data;
type = c->type; type = c->type;
goto end; goto end;
+111 -33
View File
@@ -83,7 +83,6 @@
#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
#define TAGMASK ((1u << TAGCOUNT) - 1) #define TAGMASK ((1u << TAGCOUNT) - 1)
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
#define LISTEN_STATIC(E, H, D) do { StaticListener *_l = ecalloc(1, sizeof(*_l)); _l->listener.notify = (H); _l->data = (D); wl_signal_add((E), &_l->listener); } while (0)
/* enums */ /* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
@@ -246,6 +245,17 @@ typedef struct {
struct wl_listener destroy; struct wl_listener destroy;
} PointerConstraint; } PointerConstraint;
typedef struct {
struct wlr_idle_inhibitor_v1 *inhibitor;
struct wl_listener destroy;
} IdleInhibitor;
typedef struct {
struct wlr_xdg_popup *popup;
struct wl_listener commit;
struct wl_listener destroy;
} Popup;
typedef struct { typedef struct {
const char *id; const char *id;
const char *title; const char *title;
@@ -263,12 +273,6 @@ typedef struct {
struct wl_listener destroy; struct wl_listener destroy;
} SessionLock; } SessionLock;
typedef struct {
/* Must keep this field first */
struct wl_listener listener;
void *data;
} StaticListener;
/* function declarations */ /* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox); static void applybounds(Client *c, struct wlr_box *bbox);
static void applygeom(Client *c); static void applygeom(Client *c);
@@ -304,6 +308,7 @@ static void createpopup(struct wl_listener *listener, void *data);
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void cursorframe(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void); static void cursorwarptohint(void);
static void destroybackend(struct wl_listener *listener, void *data);
static void destroydecoration(struct wl_listener *listener, void *data); static void destroydecoration(struct wl_listener *listener, void *data);
static void destroydragicon(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data);
@@ -312,6 +317,7 @@ static void destroylock(SessionLock *lock, int unlocked);
static void destroylocksurface(struct wl_listener *listener, void *data); static void destroylocksurface(struct wl_listener *listener, void *data);
static void destroynotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data);
static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data);
static void destroypopup(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroykeyboardgroup(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir); static Monitor *dirtomon(enum wlr_direction dir);
@@ -319,6 +325,7 @@ static void focusclient(Client *c, LayerSurface *l, int lift);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg); static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m); static Client *focustop(Monitor *m);
static void forgetoffmons(void);
static void fullscreennotify(struct wl_listener *listener, void *data); static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data); static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo); static void handlesig(int signo);
@@ -461,6 +468,7 @@ static struct wl_array ghosts; /* struct wlr_scene_node *, unmapped clients */
static struct wl_array offmons; /* char *, names of outputs turned off by clients */ static struct wl_array offmons; /* char *, names of outputs turned off by clients */
/* global event handlers */ /* global event handlers */
static struct wl_listener backend_destroy = {.notify = destroybackend};
static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_button = {.notify = buttonpress};
static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_frame = {.notify = cursorframe};
@@ -855,6 +863,7 @@ cleanup(void)
/* If it's not destroyed manually, it will cause a use-after-free of wlr_seat. /* If it's not destroyed manually, it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed on the wlroots side */ * Destroy it until it's fixed on the wlroots side */
if (backend)
wlr_backend_destroy(backend); wlr_backend_destroy(backend);
if (transaction_idle) if (transaction_idle)
@@ -911,6 +920,7 @@ cleanuplisteners(void)
wl_list_remove(&new_idle_inhibitor.link); wl_list_remove(&new_idle_inhibitor.link);
wl_list_remove(&layout_change.link); wl_list_remove(&layout_change.link);
wl_list_remove(&new_input_device.link); wl_list_remove(&new_input_device.link);
wl_list_remove(&backend_destroy.link);
wl_list_remove(&new_virtual_keyboard.link); wl_list_remove(&new_virtual_keyboard.link);
wl_list_remove(&new_virtual_pointer.link); wl_list_remove(&new_virtual_pointer.link);
wl_list_remove(&new_pointer_constraint.link); wl_list_remove(&new_pointer_constraint.link);
@@ -1054,8 +1064,8 @@ commitnotify(struct wl_listener *listener, void *data)
void void
commitpopup(struct wl_listener *listener, void *data) commitpopup(struct wl_listener *listener, void *data)
{ {
StaticListener *sl = wl_container_of(listener, sl, listener); Popup *p = wl_container_of(listener, p, commit);
struct wlr_xdg_popup *popup = sl->data; struct wlr_xdg_popup *popup = p->popup;
LayerSurface *l = NULL; LayerSurface *l = NULL;
Client *c = NULL; Client *c = NULL;
struct wlr_box box; struct wlr_box box;
@@ -1077,8 +1087,7 @@ commitpopup(struct wl_listener *listener, void *data)
box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x - c->surface.xdg->geometry.x); box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x - c->surface.xdg->geometry.x);
box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y - c->surface.xdg->geometry.y); box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y - c->surface.xdg->geometry.y);
wlr_xdg_popup_unconstrain_from_box(popup, &box); wlr_xdg_popup_unconstrain_from_box(popup, &box);
wl_list_remove(&listener->link); destroypopup(&p->destroy, NULL);
free(listener);
} }
void void
@@ -1098,7 +1107,9 @@ void
createidleinhibitor(struct wl_listener *listener, void *data) createidleinhibitor(struct wl_listener *listener, void *data)
{ {
struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor, idle_inhibitor); IdleInhibitor *i = ecalloc(1, sizeof(*i));
i->inhibitor = idle_inhibitor;
LISTEN(&idle_inhibitor->events.destroy, &i->destroy, destroyidleinhibitor);
checkidleinhibitor(NULL); checkidleinhibitor(NULL);
} }
@@ -1372,7 +1383,10 @@ createpopup(struct wl_listener *listener, void *data)
/* This event is raised when a client (either xdg-shell or layer-shell) /* This event is raised when a client (either xdg-shell or layer-shell)
* creates a new popup. */ * creates a new popup. */
struct wlr_xdg_popup *popup = data; struct wlr_xdg_popup *popup = data;
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup, popup); Popup *p = ecalloc(1, sizeof(*p));
p->popup = popup;
LISTEN(&popup->base->surface->events.commit, &p->commit, commitpopup);
LISTEN(&popup->events.destroy, &p->destroy, destroypopup);
} }
void void
@@ -1413,6 +1427,21 @@ cursorwarptohint(void)
} }
} }
void
destroybackend(struct wl_listener *listener, void *data)
{
/* wlroots destroys the backend itself when the session goes away (e.g.
* seatd stopped at shutdown), and asserts that its listeners are gone */
wl_list_remove(&new_output.link);
wl_list_init(&new_output.link);
wl_list_remove(&new_input_device.link);
wl_list_init(&new_input_device.link);
wl_list_remove(&backend_destroy.link);
wl_list_init(&backend_destroy.link);
backend = NULL;
quit(NULL);
}
void void
destroydecoration(struct wl_listener *listener, void *data) destroydecoration(struct wl_listener *listener, void *data)
{ {
@@ -1435,12 +1464,11 @@ destroydragicon(struct wl_listener *listener, void *data)
void void
destroyidleinhibitor(struct wl_listener *listener, void *data) destroyidleinhibitor(struct wl_listener *listener, void *data)
{ {
StaticListener *sl = wl_container_of(listener, sl, listener); IdleInhibitor *i = wl_container_of(listener, i, destroy);
struct wlr_idle_inhibitor_v1 *idle_inhibitor = sl->data;
/* At this point the idle inhibitor is still in the list of the manager */ /* At this point the idle inhibitor is still in the list of the manager */
checkidleinhibitor(wlr_surface_get_root_surface(idle_inhibitor->surface)); checkidleinhibitor(wlr_surface_get_root_surface(i->inhibitor->surface));
wl_list_remove(&listener->link); wl_list_remove(&i->destroy.link);
free(listener); free(i);
} }
void void
@@ -1492,14 +1520,21 @@ destroylocksurface(struct wl_listener *listener, void *data)
if (lock_surface->surface != seat->keyboard_state.focused_surface) if (lock_surface->surface != seat->keyboard_state.focused_surface)
return; return;
if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { if (!locked) {
surface = wl_container_of(cur_lock->surfaces.next, surface, link);
client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
} else if (!locked) {
focusclient(focustop(selmon), NULL, 1); focusclient(focustop(selmon), NULL, 1);
} else { return;
wlr_seat_keyboard_clear_focus(seat);
} }
/* The surface being destroyed is still in the list */
if (cur_lock) {
wl_list_for_each(surface, &cur_lock->surfaces, link) {
if (surface != lock_surface) {
client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
return;
}
}
}
wlr_seat_keyboard_clear_focus(seat);
} }
void void
@@ -1547,6 +1582,15 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
free(pointer_constraint); free(pointer_constraint);
} }
void
destroypopup(struct wl_listener *listener, void *data)
{
Popup *p = wl_container_of(listener, p, destroy);
wl_list_remove(&p->commit.link);
wl_list_remove(&p->destroy.link);
free(p);
}
void void
destroysessionlock(struct wl_listener *listener, void *data) destroysessionlock(struct wl_listener *listener, void *data)
{ {
@@ -1666,6 +1710,8 @@ void
focusmon(const Arg *arg) focusmon(const Arg *arg)
{ {
int i = 0, nmons = wl_list_length(&mons); int i = 0, nmons = wl_list_length(&mons);
if (!selmon)
return;
if (nmons) { if (nmons) {
do /* don't switch to disabled mons */ do /* don't switch to disabled mons */
selmon = dirtomon(arg->i); selmon = dirtomon(arg->i);
@@ -1706,18 +1752,42 @@ focusstack(const Arg *arg)
Client * Client *
focustop(Monitor *m) focustop(Monitor *m)
{ {
Client *c; Client *c, *fs = NULL;
wl_list_for_each(c, &fstack, flink) wl_list_for_each(c, &fstack, flink) {
if (VISIBLEON(c, m) && c->isfullscreen) if (VISIBLEON(c, m) && c->isfullscreen) {
return c; fs = c;
break;
}
}
/* A fullscreen client's children are shown above it */
wl_list_for_each(c, &fstack, flink) wl_list_for_each(c, &fstack, flink)
if (VISIBLEON(c, m)) if (VISIBLEON(c, m) && (!fs || c == fs || client_get_parent(c) == fs))
return c; return c;
return NULL; return NULL;
} }
void
forgetoffmons(void)
{
/* Forget the outputs that were unplugged while off, or they would stay
* off when plugged in again */
char **name, **kept = offmons.data;
Monitor *m;
wl_array_for_each(name, &offmons) {
wl_list_for_each(m, &mons, link)
if (!strcmp(*name, m->wlr_output->name))
break;
if (&m->link != &mons)
*kept++ = *name;
else
free(*name);
}
offmons.size = (char *)kept - (char *)offmons.data;
}
void void
fullscreennotify(struct wl_listener *listener, void *data) fullscreennotify(struct wl_listener *listener, void *data)
{ {
@@ -2272,8 +2342,12 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
for (i = 0; i < states_len; i++) { for (i = 0; i < states_len; i++) {
struct wlr_swapchain *swapchain = wlr_output_swapchain_manager_get_swapchain( struct wlr_swapchain *swapchain = wlr_output_swapchain_manager_get_swapchain(
&swapchain_manager, states[i].output); &swapchain_manager, states[i].output);
if (swapchain && !states[i].output->enabled) struct wlr_buffer *buffer;
wlr_output_state_set_buffer(&states[i].base, wlr_swapchain_acquire(swapchain)); if (swapchain && !states[i].output->enabled
&& (buffer = wlr_swapchain_acquire(swapchain))) {
wlr_output_state_set_buffer(&states[i].base, buffer);
wlr_buffer_unlock(buffer);
}
} }
if (!(ok = wlr_backend_commit(backend, states, states_len))) if (!(ok = wlr_backend_commit(backend, states, states_len)))
@@ -2405,6 +2479,8 @@ powermgrsetmode(struct wl_listener *listener, void *data)
if (!m) if (!m)
return; return;
if (event->mode)
forgetoffmons();
m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */ m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
wlr_output_state_set_enabled(&state, event->mode); wlr_output_state_set_enabled(&state, event->mode);
/* The output was reconnected while off and was never modeset */ /* The output was reconnected while off and was never modeset */
@@ -2749,6 +2825,7 @@ setup(void)
* if an X11 server is running. */ * if an X11 server is running. */
if (!(backend = wlr_backend_autocreate(event_loop, &session))) if (!(backend = wlr_backend_autocreate(event_loop, &session)))
die("couldn't create backend"); die("couldn't create backend");
wl_signal_add(&backend->events.destroy, &backend_destroy);
/* Initialize the scene graph used to lay out windows */ /* Initialize the scene graph used to lay out windows */
scene = wlr_scene_create(); scene = wlr_scene_create();
@@ -3142,7 +3219,7 @@ void
transactionapply(void) transactionapply(void)
{ {
struct wlr_scene_node **ghost; struct wlr_scene_node **ghost;
Client *c; Client *c, *p;
Monitor *m; Monitor *m;
wl_event_source_timer_update(transaction_timer, 0); wl_event_source_timer_update(transaction_timer, 0);
@@ -3164,7 +3241,8 @@ transactionapply(void)
wl_list_for_each(m, &mons, link) { wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled) if (m->wlr_output->enabled)
wlr_scene_node_set_enabled(&m->fullscreen_bg->node, wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
(c = focustop(m)) && c->isfullscreen); (c = focustop(m)) && (c->isfullscreen
|| ((p = client_get_parent(c)) && p->isfullscreen)));
} }
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);