From 62dbb3a54e528c4de01ae4f4565f00c1d867131b Mon Sep 17 00:00:00 2001 From: speckitor Date: Sat, 16 May 2026 21:59:36 +0700 Subject: [PATCH] layer shell and keybinds --- include/config.h | 1 + include/keybinds.h | 1 + include/layer.h | 9 +++++++ include/types.h | 2 +- src/keybinds.c | 27 +++++++++++++++++--- src/layer-surface.c | 16 ++++++++++-- src/layer.c | 21 ++++++++++++++++ src/layout.c | 60 ++++++++++++++++++++++----------------------- src/output.c | 3 +-- src/server.c | 6 ++--- src/toplevel.c | 11 +++++---- src/xdg-toplevel.c | 11 ++++----- 12 files changed, 116 insertions(+), 52 deletions(-) create mode 100644 include/layer.h create mode 100644 src/layer.c diff --git a/include/config.h b/include/config.h index babde17..2ef0a1d 100644 --- a/include/config.h +++ b/include/config.h @@ -44,6 +44,7 @@ static const absn_keybind keybinds[] = { {ALT | SHIFT, XKB_KEY_k, swap_focus, {.i = -1}}, {ALT, XKB_KEY_f, toggle_fullscreen, {0}}, + {ALT, XKB_KEY_v, toggle_floating, {0}}, {ALT, XKB_KEY_h, increase_master_count, {.i = +1}}, {ALT, XKB_KEY_l, increase_master_count, {.i = -1}}, diff --git a/include/keybinds.h b/include/keybinds.h index b481009..2c29a3b 100644 --- a/include/keybinds.h +++ b/include/keybinds.h @@ -11,6 +11,7 @@ void cycle_focus(absn_server *server, const absn_arg *arg); void swap_focus(absn_server *server, const absn_arg *arg); void toggle_fullscreen(absn_server *server, const absn_arg *arg); +void toggle_floating(absn_server *server, const absn_arg *arg); void increase_master_width(absn_server *server, const absn_arg *arg); void increase_master_count(absn_server *server, const absn_arg *arg); diff --git a/include/layer.h b/include/layer.h new file mode 100644 index 0000000..69227d4 --- /dev/null +++ b/include/layer.h @@ -0,0 +1,9 @@ +#ifndef __LAYER_ARRANGE_H_ +#define __LAYER_ARRANGE_H_ + +#include "output.h" +#include "types.h" + +void layer_arrange(absn_output *output); + +#endif diff --git a/include/types.h b/include/types.h index 930b5ab..36004c3 100644 --- a/include/types.h +++ b/include/types.h @@ -177,7 +177,7 @@ struct absn_output { struct wl_listener request_state; struct wl_listener destroy; - struct wl_list layers[4]; + struct wl_list layer_surfaces; }; typedef struct { diff --git a/src/keybinds.c b/src/keybinds.c index a71641c..80f78d0 100644 --- a/src/keybinds.c +++ b/src/keybinds.c @@ -70,7 +70,8 @@ void swap_focus(absn_server *server, const absn_arg *arg) absn_toplevel *first = NULL; absn_toplevel *last = NULL; - wl_list_for_each(temp, &server->toplevels, link) { + wl_list_for_each(temp, &server->toplevels, link) + { if (temp->workspace == toplevel->workspace) last = temp; if (!first && temp->workspace == toplevel->workspace) @@ -127,6 +128,16 @@ void toggle_fullscreen(absn_server *server, const absn_arg *arg) toplevel_set_fullscreen(focus, !focus->fullscreen); } +void toggle_floating(absn_server *server, const absn_arg *arg) +{ + UNUSED(arg); + if (!server->focused_toplevel) + return; + + absn_toplevel *focus = server->focused_toplevel; + toplevel_set_floating(focus, !focus->floating); +} + void increase_master_width(absn_server *server, const absn_arg *arg) { absn_workspace *workspace = server->focused_output->workspace; @@ -160,6 +171,17 @@ void switch_workspace(absn_server *server, const absn_arg *arg) if (&server->workspaces[i] == server->focused_output->workspace) return; + int toplevels_count = 0; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (toplevel->workspace == server->focused_output->workspace) + toplevels_count++; + } + + if (toplevels_count == 0) + server->focused_output->workspace->output = NULL; + if (!server->workspaces[i].output) { server->workspaces[i].output = server->focused_output; } else if (server->focused_output == server->workspaces[i].output) { @@ -177,7 +199,6 @@ void switch_workspace(absn_server *server, const absn_arg *arg) server->focused_output->workspace = &server->workspaces[i]; absn_toplevel *focus = NULL; - absn_toplevel *toplevel; wl_list_for_each(toplevel, &server->toplevels, link) { if (!focus && toplevel && toplevel->workspace == &server->workspaces[i]) { @@ -193,7 +214,7 @@ void switch_workspace(absn_server *server, const absn_arg *arg) unfocus_toplevel(server->focused_toplevel); if (focus) { - /* crazy way to make it focus client if it was focused before */ + /* crazy way to make toplevel focus properly if it was focused before */ struct wlr_surface *surface; #ifdef XWAYLAND if (focus->type == TOPLEVEL_X11) diff --git a/src/layer-surface.c b/src/layer-surface.c index 069ddda..e29550e 100644 --- a/src/layer-surface.c +++ b/src/layer-surface.c @@ -1,3 +1,7 @@ +#include + +#include "focus.h" +#include "layer.h" #include "types.h" void layer_surface_map(struct wl_listener *listener, void *data) @@ -8,14 +12,22 @@ void layer_surface_map(struct wl_listener *listener, void *data) void layer_surface_unmap(struct wl_listener *listener, void *data) { - UNUSED(listener); UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, unmap); + + if (layer_surface->wlr->surface == layer_surface->server->seat->keyboard_state.focused_surface) + focus_toplevel(focus_get_topmost(layer_surface->server)); } void layer_surface_commit(struct wl_listener *listener, void *data) { - UNUSED(listener); UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, commit); + struct wlr_layer_surface_v1 *surface = layer_surface->wlr; + + wlr_layer_surface_v1_configure(surface, surface->pending.desired_width, surface->pending.desired_height); + + layer_arrange(layer_surface->output); } void layer_surface_new_popup(struct wl_listener *listener, void *data) diff --git a/src/layer.c b/src/layer.c new file mode 100644 index 0000000..d52d82d --- /dev/null +++ b/src/layer.c @@ -0,0 +1,21 @@ +#include + +#include "layout.h" +#include "types.h" + +void layer_arrange(absn_output *output) +{ + struct wlr_box usable_area = output->geom; + absn_layer_surface *layer_surface; + + wl_list_for_each(layer_surface, &output->layer_surfaces, link) + { + if (!layer_surface->wlr->initialized) + continue; + + wlr_scene_layer_surface_v1_configure(layer_surface->scene_layer, &output->geom, &usable_area); + } + + output->usable_area = usable_area; + layout_arrange(output); +} diff --git a/src/layout.c b/src/layout.c index 6b0c4e3..a622a14 100644 --- a/src/layout.c +++ b/src/layout.c @@ -41,8 +41,8 @@ static void tile(struct absn_output *output) if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) break; } - new_geom.x = output->geom.x + og, new_geom.y = output->geom.y + og, - new_geom.width = output->geom.width - 2 * og, new_geom.height = output->geom.height - 2 * og, + new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, + new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, toplevel_set_geom(toplevel, &new_geom); return; @@ -55,8 +55,8 @@ static void tile(struct absn_output *output) float msize = output->workspace->size; int32_t main_stack_width = - (toplevels_count <= mcount) ? output->geom.width - 2 * og : msize * (output->geom.width - 2 * og); - int32_t w = output->geom.width - main_stack_width - 2 * og - lg; + (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); + int32_t w = output->usable_area.width - main_stack_width - 2 * og - lg; int32_t pure_h; int32_t h; @@ -68,7 +68,7 @@ static void tile(struct absn_output *output) if (toplevels_count <= mcount) { total_lg = (toplevels_count - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / toplevels_count; r = pure_h % toplevels_count; @@ -79,8 +79,8 @@ static void tile(struct absn_output *output) cur_h = h + (i < r ? 1 : 0); - new_geom.x = output->geom.x + og; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; new_geom.width = main_stack_width; new_geom.height = cur_h; @@ -100,14 +100,14 @@ static void tile(struct absn_output *output) if (i < mcount) { total_lg = (mcount - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / mcount; r = pure_h % mcount; cur_h = h + (i < r ? 1 : 0); - new_geom.x = output->geom.x + og; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; new_geom.width = main_stack_width; new_geom.height = cur_h; @@ -120,14 +120,14 @@ static void tile(struct absn_output *output) int32_t stack_count = toplevels_count - mcount; total_lg = (stack_count - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / stack_count; r = pure_h % stack_count; cur_h = h + (i - mcount < r ? 1 : 0); - new_geom.x = output->geom.x + main_stack_width + lg + og; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + main_stack_width + lg + og; + new_geom.y = output->usable_area.y + dy; new_geom.width = w; new_geom.height = cur_h; @@ -157,8 +157,8 @@ static void tile_left(struct absn_output *output) if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) break; } - new_geom.x = output->geom.x + og, new_geom.y = output->geom.y + og, - new_geom.width = output->geom.width - 2 * og, new_geom.height = output->geom.height - 2 * og, + new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, + new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, toplevel_set_geom(toplevel, &new_geom); return; @@ -171,8 +171,8 @@ static void tile_left(struct absn_output *output) float msize = output->workspace->size; int32_t main_stack_width = - (toplevels_count <= mcount) ? output->geom.width - 2 * og : msize * (output->geom.width - 2 * og); - int32_t w = output->geom.width - main_stack_width - 2 * og - lg; + (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); + int32_t w = output->usable_area.width - main_stack_width - 2 * og - lg; int32_t pure_h; int32_t h; @@ -184,7 +184,7 @@ static void tile_left(struct absn_output *output) if (toplevels_count <= mcount) { total_lg = (toplevels_count - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / toplevels_count; r = pure_h % toplevels_count; @@ -195,8 +195,8 @@ static void tile_left(struct absn_output *output) cur_h = h + (i < r ? 1 : 0); - new_geom.x = output->geom.x + og; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; new_geom.width = main_stack_width; new_geom.height = cur_h; @@ -216,14 +216,14 @@ static void tile_left(struct absn_output *output) if (i < mcount) { total_lg = (mcount - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / mcount; r = pure_h % mcount; cur_h = h + (i < r ? 1 : 0); - new_geom.x = output->geom.width - og - main_stack_width; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + output->usable_area.width - og - main_stack_width; + new_geom.y = output->usable_area.y + dy; new_geom.width = main_stack_width; new_geom.height = cur_h; @@ -236,14 +236,14 @@ static void tile_left(struct absn_output *output) int32_t stack_count = toplevels_count - mcount; total_lg = (stack_count - 1) * lg; - pure_h = output->geom.height - 2 * og - total_lg; + pure_h = output->usable_area.height - 2 * og - total_lg; h = pure_h / stack_count; r = pure_h % stack_count; cur_h = h + (i - mcount < r ? 1 : 0); - new_geom.x = output->geom.x + og; - new_geom.y = output->geom.y + dy; + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; new_geom.width = w; new_geom.height = cur_h; @@ -266,10 +266,10 @@ static void monocle(struct absn_output *output) int32_t og = OUTPUT_GAP; struct wlr_box new_geom = { - .x = output->geom.x + og, - .y = output->geom.y + og, - .width = output->geom.width - 2 * og, - .height = output->geom.height - 2 * og, + .x = output->usable_area.x + og, + .y = output->usable_area.y + og, + .width = output->usable_area.width - 2 * og, + .height = output->usable_area.height - 2 * og, }; absn_toplevel *toplevel; diff --git a/src/output.c b/src/output.c index fa9122d..f8be1de 100644 --- a/src/output.c +++ b/src/output.c @@ -14,7 +14,6 @@ void output_frame(struct wl_listener *listener, void *data) struct wlr_scene *scene = output->server->scene; struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(scene, output->wlr); - absn_toplevel *toplevel; wl_list_for_each(toplevel, &output->server->toplevels, link) { @@ -23,7 +22,6 @@ void output_frame(struct wl_listener *listener, void *data) } wlr_scene_output_commit(scene_output, NULL); - skip: clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(scene_output, &now); @@ -89,6 +87,7 @@ void output_layout_change(struct wl_listener *listener, void *data) config_head = wlr_output_configuration_head_v1_create(config, output->wlr); wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + output->usable_area = output->geom; if ((toplevel = focus_get_topmost(server)) && toplevel->fullscreen) toplevel_set_size(toplevel, output->geom.width, output->geom.height); diff --git a/src/server.c b/src/server.c index 2fdbc1b..910d915 100644 --- a/src/server.c +++ b/src/server.c @@ -59,13 +59,13 @@ void new_output(struct wl_listener *listener, void *data) wl_list_insert(&server->outputs, &output->link); - for (int i = 0; i < 4; ++i) - wl_list_init(&output->layers[i]); + wl_list_init(&output->layer_surfaces); struct wlr_output_layout_output *l_layout = wlr_output_layout_add_auto(server->output_layout, output->wlr); struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); wlr_scene_output_layout_add_output(server->scene_layout, l_layout, scene_output); wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + output->usable_area = output->geom; } void new_xdg_toplevel(struct wl_listener *listener, void *data) @@ -148,7 +148,7 @@ void new_layer_surface(struct wl_listener *listener, void *data) layer_surface->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, surface); layer_surface->scene_tree = layer_surface->scene_layer->tree; - wl_list_insert(&layer_surface->output->layers[surface->pending.layer], &layer_surface->link); + wl_list_insert(&layer_surface->output->layer_surfaces, &layer_surface->link); wlr_surface_send_enter(surface->surface, surface->output); } diff --git a/src/toplevel.c b/src/toplevel.c index ca1d889..7d5bdaa 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -114,22 +114,23 @@ void toplevel_set_size(absn_toplevel *toplevel, int32_t width, int32_t height) toplevel_update_borders_geom(toplevel); + int32_t bw = toplevel->bw; + struct wlr_box clip = { .x = 0, .y = 0, - .width = width - toplevel->bw, - .height = height - toplevel->bw, + .width = width - bw, + .height = height - bw, }; if (toplevel->type == TOPLEVEL_XDG) { if (wl_resource_get_version(toplevel->xdg->resource) >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) wlr_xdg_toplevel_set_bounds(toplevel->xdg, width, height); - toplevel->resizing = - wlr_xdg_toplevel_set_size(toplevel->xdg, width - 2 * toplevel->bw, height - 2 * toplevel->bw); + toplevel->resizing = wlr_xdg_toplevel_set_size(toplevel->xdg, width - 2 * bw, height - 2 * bw); } #ifdef XWAYLAND else if (toplevel->type == TOPLEVEL_X11) { - wlr_xwayland_surface_configure(toplevel->xw, toplevel->geom.x, toplevel->geom.y, width - 2 * toplevel->bw, + wlr_xwayland_surface_configure(toplevel->xw, toplevel->geom.x, toplevel->geom.y, width - 2 * bw, height - 2 * toplevel->bw); /* manually update position */ toplevel_set_pos(toplevel, toplevel->geom.x, toplevel->geom.y); diff --git a/src/xdg-toplevel.c b/src/xdg-toplevel.c index d1b2ff1..6849286 100644 --- a/src/xdg-toplevel.c +++ b/src/xdg-toplevel.c @@ -10,6 +10,9 @@ void toplevel_commit(struct wl_listener *listener, void *data) UNUSED(data); absn_toplevel *toplevel = wl_container_of(listener, toplevel, commit); + if (toplevel->xdg->base->current.configure_serial < toplevel->resizing) + return; + if (toplevel->xdg->base->initial_commit) { wlr_xdg_toplevel_set_activated(toplevel->xdg, false); @@ -21,12 +24,6 @@ void toplevel_commit(struct wl_listener *listener, void *data) return; } - bool resizing = toplevel->resizing && toplevel->resizing <= toplevel->xdg->base->current.configure_serial; - - /* remove pending resize */ - if (resizing) - toplevel->resizing = 0; - struct wlr_box clip = { .x = toplevel->xdg->base->geometry.x, .y = toplevel->xdg->base->geometry.y, @@ -34,4 +31,6 @@ void toplevel_commit(struct wl_listener *listener, void *data) .height = toplevel->geom.height - toplevel->bw, }; wlr_scene_subsurface_tree_set_clip(&toplevel->scene_surface->node, &clip); + + toplevel->resizing = 0; }