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;
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
if (!xdg_surface->toplevel)
return -1;
c = xdg_surface->data;
type = c->type;
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 TAGMASK ((1u << TAGCOUNT) - 1)
#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 */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
@@ -246,6 +245,17 @@ typedef struct {
struct wl_listener destroy;
} 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 {
const char *id;
const char *title;
@@ -263,12 +273,6 @@ typedef struct {
struct wl_listener destroy;
} SessionLock;
typedef struct {
/* Must keep this field first */
struct wl_listener listener;
void *data;
} StaticListener;
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
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 cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
static void destroybackend(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 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 destroynotify(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 destroykeyboardgroup(struct wl_listener *listener, void *data);
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 focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void forgetoffmons(void);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
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 */
/* global event handlers */
static struct wl_listener backend_destroy = {.notify = destroybackend};
static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_button = {.notify = buttonpress};
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.
* Destroy it until it's fixed on the wlroots side */
if (backend)
wlr_backend_destroy(backend);
if (transaction_idle)
@@ -911,6 +920,7 @@ cleanuplisteners(void)
wl_list_remove(&new_idle_inhibitor.link);
wl_list_remove(&layout_change.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_pointer.link);
wl_list_remove(&new_pointer_constraint.link);
@@ -1054,8 +1064,8 @@ commitnotify(struct wl_listener *listener, void *data)
void
commitpopup(struct wl_listener *listener, void *data)
{
StaticListener *sl = wl_container_of(listener, sl, listener);
struct wlr_xdg_popup *popup = sl->data;
Popup *p = wl_container_of(listener, p, commit);
struct wlr_xdg_popup *popup = p->popup;
LayerSurface *l = NULL;
Client *c = NULL;
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.y -= (type == LayerShell ? l->scene->node.y : c->geom.y - c->surface.xdg->geometry.y);
wlr_xdg_popup_unconstrain_from_box(popup, &box);
wl_list_remove(&listener->link);
free(listener);
destroypopup(&p->destroy, NULL);
}
void
@@ -1098,7 +1107,9 @@ void
createidleinhibitor(struct wl_listener *listener, void *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);
}
@@ -1372,7 +1383,10 @@ createpopup(struct wl_listener *listener, void *data)
/* This event is raised when a client (either xdg-shell or layer-shell)
* creates a new popup. */
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
@@ -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
destroydecoration(struct wl_listener *listener, void *data)
{
@@ -1435,12 +1464,11 @@ destroydragicon(struct wl_listener *listener, void *data)
void
destroyidleinhibitor(struct wl_listener *listener, void *data)
{
StaticListener *sl = wl_container_of(listener, sl, listener);
struct wlr_idle_inhibitor_v1 *idle_inhibitor = sl->data;
IdleInhibitor *i = wl_container_of(listener, i, destroy);
/* At this point the idle inhibitor is still in the list of the manager */
checkidleinhibitor(wlr_surface_get_root_surface(idle_inhibitor->surface));
wl_list_remove(&listener->link);
free(listener);
checkidleinhibitor(wlr_surface_get_root_surface(i->inhibitor->surface));
wl_list_remove(&i->destroy.link);
free(i);
}
void
@@ -1492,14 +1520,21 @@ destroylocksurface(struct wl_listener *listener, void *data)
if (lock_surface->surface != seat->keyboard_state.focused_surface)
return;
if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
surface = wl_container_of(cur_lock->surfaces.next, surface, link);
client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
} else if (!locked) {
if (!locked) {
focusclient(focustop(selmon), NULL, 1);
} else {
wlr_seat_keyboard_clear_focus(seat);
return;
}
/* 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
@@ -1547,6 +1582,15 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
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
destroysessionlock(struct wl_listener *listener, void *data)
{
@@ -1666,6 +1710,8 @@ void
focusmon(const Arg *arg)
{
int i = 0, nmons = wl_list_length(&mons);
if (!selmon)
return;
if (nmons) {
do /* don't switch to disabled mons */
selmon = dirtomon(arg->i);
@@ -1706,18 +1752,42 @@ focusstack(const Arg *arg)
Client *
focustop(Monitor *m)
{
Client *c;
Client *c, *fs = NULL;
wl_list_for_each(c, &fstack, flink)
if (VISIBLEON(c, m) && c->isfullscreen)
return c;
wl_list_for_each(c, &fstack, flink) {
if (VISIBLEON(c, m) && c->isfullscreen) {
fs = c;
break;
}
}
/* A fullscreen client's children are shown above it */
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 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
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++) {
struct wlr_swapchain *swapchain = wlr_output_swapchain_manager_get_swapchain(
&swapchain_manager, states[i].output);
if (swapchain && !states[i].output->enabled)
wlr_output_state_set_buffer(&states[i].base, wlr_swapchain_acquire(swapchain));
struct wlr_buffer *buffer;
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)))
@@ -2405,6 +2479,8 @@ powermgrsetmode(struct wl_listener *listener, void *data)
if (!m)
return;
if (event->mode)
forgetoffmons();
m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
wlr_output_state_set_enabled(&state, event->mode);
/* The output was reconnected while off and was never modeset */
@@ -2749,6 +2825,7 @@ setup(void)
* if an X11 server is running. */
if (!(backend = wlr_backend_autocreate(event_loop, &session)))
die("couldn't create backend");
wl_signal_add(&backend->events.destroy, &backend_destroy);
/* Initialize the scene graph used to lay out windows */
scene = wlr_scene_create();
@@ -3142,7 +3219,7 @@ void
transactionapply(void)
{
struct wlr_scene_node **ghost;
Client *c;
Client *c, *p;
Monitor *m;
wl_event_source_timer_update(transaction_timer, 0);
@@ -3164,7 +3241,8 @@ transactionapply(void)
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled)
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);