From 87cbffd414a1edd5907e1a0493a9e2b925a4a044 Mon Sep 17 00:00:00 2001 From: speckitor Date: Sun, 10 May 2026 23:02:22 +0700 Subject: [PATCH] workspaces --- include/config.h | 29 +++++++++++++------ include/keybinds.h | 2 ++ include/types.h | 28 ++++++++++-------- src/absinthe.c | 11 +++++++ src/keybinds.c | 64 ++++++++++++++++++++++++++++++++--------- src/layout.c | 41 ++++++++++++++------------ src/server.c | 13 +++++++-- src/toplevel-handlers.c | 1 + 8 files changed, 134 insertions(+), 55 deletions(-) diff --git a/include/config.h b/include/config.h index 43b0a1b..518d35b 100644 --- a/include/config.h +++ b/include/config.h @@ -16,16 +16,24 @@ static const float focused_bc[4] = { 0.0, 0.0, 1.0, 1.0 }; static const float urgent_bc[4] = { 1.0, 0.0, 0.0, 1.0 }; static const float unfocused_bc[4] = { 0.28, 0.28, 0.28, 1.0 }; -#define MSTACK_SIZE 1 -#define MSTACK_WIDTH 0.5 +#define STACK_SIZE 0.5 +#define STACK_COUNT 1 -#define OUTPUT_GAP 10 -#define LAYOUT_GAP 5 +#define OUTPUT_GAP 10 +#define LAYOUT_GAP 5 -#define ALT WLR_MODIFIER_ALT -#define CTRL WLR_MODIFIER_CTRL -#define SHIFT WLR_MODIFIER_SHIFT -#define LOGO WLR_MODIFIER_LOGO +#define ALT WLR_MODIFIER_ALT +#define CTRL WLR_MODIFIER_CTRL +#define SHIFT WLR_MODIFIER_SHIFT +#define LOGO WLR_MODIFIER_LOGO + +static const char *workspaces[] = { + "1", + "2", + "3", + "4", + "5", +}; static const absn_keybind keybinds[] = { { ALT, XKB_KEY_Return, &run, { .v = "alacritty" } }, @@ -37,6 +45,11 @@ static const absn_keybind keybinds[] = { { ALT, XKB_KEY_l, increase_master_count, { .i = -1 } }, { ALT | SHIFT, XKB_KEY_h, increase_master_width, { .f = -0.05 } }, { ALT | SHIFT, XKB_KEY_l, increase_master_width, { .f = +0.05 } }, + { ALT, XKB_KEY_1, switch_workspace, { .v = "1" } }, + { ALT, XKB_KEY_2, switch_workspace, { .v = "2" } }, + { ALT, XKB_KEY_3, switch_workspace, { .v = "3" } }, + { ALT, XKB_KEY_4, switch_workspace, { .v = "4" } }, + { ALT, XKB_KEY_5, switch_workspace, { .v = "5" } }, { ALT, XKB_KEY_E, quit, { 0 } }, }; diff --git a/include/keybinds.h b/include/keybinds.h index 56bfeb0..0ded31b 100644 --- a/include/keybinds.h +++ b/include/keybinds.h @@ -12,6 +12,8 @@ void toggle_fullscreen(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); +void switch_workspace(absn_server *server, const absn_arg *arg); + void quit(absn_server *server, const absn_arg *arg); #endif diff --git a/include/types.h b/include/types.h index 548a3d0..5d36f76 100644 --- a/include/types.h +++ b/include/types.h @@ -78,8 +78,8 @@ static const int layermap[] = { }; enum { - LAYOUT_FLOAT, LAYOUT_TILE, + LAYOUT_FLOAT, LAYOUT_TILELEFT, LAYOUT_TILETOP, LAYOUT_TILEBOTTOM, @@ -93,6 +93,14 @@ enum { typedef struct absn_output absn_output; typedef struct absn_toplevel absn_toplevel; +typedef struct { + int layout; + const char *name; + absn_output *output; + int count; + float size; +} absn_workspace; + typedef struct { struct wl_display *display; struct wlr_backend *backend; @@ -151,17 +159,17 @@ typedef struct { struct wlr_output_manager_v1 *output_mgr; struct wl_listener mgr_apply; struct wl_listener mgr_test; -} absn_server; -typedef struct { - int layout; - uint32_t id; -} absn_tag; + int workspaces_count; + absn_workspace *workspaces; +} absn_server; struct absn_output { struct wl_list link; absn_server *server; + absn_workspace *workspace; + struct wlr_box geom; struct wlr_box usable_area; @@ -170,12 +178,6 @@ struct absn_output { struct wl_listener request_state; struct wl_listener destroy; - float mstack_width; - int mstack_count; - - absn_tag *tags; - uint32_t active_tags; - struct wl_list layers[4]; }; @@ -200,8 +202,10 @@ typedef struct { struct absn_toplevel { struct wl_list link; struct wl_list flink; /* link for focus stack */ + uint32_t tag; absn_server *server; absn_output *output; + absn_workspace *workspace; struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *scene_surface; diff --git a/src/absinthe.c b/src/absinthe.c index f358d5c..1732697 100644 --- a/src/absinthe.c +++ b/src/absinthe.c @@ -146,10 +146,21 @@ setup(absn_server *server) LISTEN(server->request_set_selection, request_cursor, server->seat->events.request_set_selection); + /* layer shell */ server->layer_shell = wlr_layer_shell_v1_create(server->display, 1); for (int i = 0; i < LAYERS_COUNT; ++i) server->layers[i] = wlr_scene_tree_create(&server->scene->tree); + /* workspaces */ + int workspaces_count = sizeof(workspaces) / sizeof(workspaces[0]); + server->workspaces_count = workspaces_count; + server->workspaces = calloc(workspaces_count, sizeof(absn_workspace)); + for (int i = 0; i < workspaces_count; ++i) { + server->workspaces[i].name = workspaces[i]; + server->workspaces[i].count = STACK_COUNT; + server->workspaces[i].size = STACK_SIZE; + } + unsetenv("DISPLAY"); #ifdef XWAYLAND if ((server->xwayland = wlr_xwayland_create(server->display, diff --git a/src/keybinds.c b/src/keybinds.c index 2e0c54c..be199bf 100644 --- a/src/keybinds.c +++ b/src/keybinds.c @@ -77,32 +77,68 @@ toggle_fullscreen(absn_server *server, const absn_arg *arg) void increase_master_width(absn_server *server, const absn_arg *arg) { - if (!server->focused_output) + absn_workspace *workspace = server->focused_output->workspace; + + if (workspace->size + arg->f >= 1.0 || + workspace->size + arg->f <= 0.0) return; - absn_output *focus = server->focused_output; - - if (focus->mstack_width + arg->f >= 1.0 || - focus->mstack_width + arg->f <= 0.0) - return; - - focus->mstack_width += arg->f; - layout_arrange(focus); + workspace->size += arg->f; + layout_arrange(workspace->output); } void increase_master_count(absn_server *server, const absn_arg *arg) { - if (!server->focused_output) + absn_workspace *workspace = server->focused_output->workspace; + + if (workspace->count + arg->i <= 0) return; - absn_output *focus = server->focused_output; + workspace->count += arg->i; + layout_arrange(workspace->output); +} - if (focus->mstack_count + arg->i <= 0) +void +switch_workspace(absn_server *server, const absn_arg *arg) +{ + int i; + for (i = 0; i < server->workspaces_count; ++i) { + if (arg->v == server->workspaces[i].name) + break; /* found it */ + } + + if (&server->workspaces[i] == server->focused_output->workspace) return; - focus->mstack_count += arg->i; - layout_arrange(focus); + if (!server->workspaces[i].output) { + server->workspaces[i].output = server->focused_output; + } else if (server->focused_output == server->workspaces[i].output) { + server->focused_output->workspace = &server->workspaces[i]; + } else { + server->focused_output = server->workspaces[i].output; + + struct wlr_box *geom = &server->focused_output->geom; + + int32_t new_x = geom->x + (geom->width / 2); + int32_t new_y = geom->y + (geom->height / 2); + + wlr_cursor_warp(server->cursor, NULL, new_x, new_y); + } + server->focused_output->workspace = &server->workspaces[i]; + + absn_toplevel *focus = NULL; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (toplevel && toplevel->workspace == &server->workspaces[i]) { + focus = toplevel; /* found it */ + break; + } + } + + focus_toplevel(focus); + layout_arrange(server->focused_output); } noreturn void diff --git a/src/layout.c b/src/layout.c index 291eece..171ba11 100644 --- a/src/layout.c +++ b/src/layout.c @@ -12,11 +12,15 @@ layout_arrange(struct absn_output *output) int toplevels_count = 0; wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->output == output && !toplevel->floating && - !toplevel->fullscreen) { + if (toplevel->workspace == output->workspace && + !toplevel->floating && !toplevel->fullscreen) { toplevels_count++; wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true); + } else if (toplevel->output == output && + toplevel->workspace != output->workspace) { + wlr_scene_node_set_enabled(&toplevel->scene_tree->node, + false); } } @@ -29,8 +33,8 @@ layout_arrange(struct absn_output *output) if (toplevels_count == 1) { wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->output == output && !toplevel->floating && - !toplevel->fullscreen) + if (toplevel->workspace == output->workspace && + !toplevel->floating && !toplevel->fullscreen) break; } new_geom.x = output->geom.x + og, @@ -45,9 +49,11 @@ layout_arrange(struct absn_output *output) int32_t lg = LAYOUT_GAP; int32_t total_lg; - int32_t main_stack_width = (toplevels_count <= output->mstack_count) ? + int mcount = output->workspace->count; + int msize = output->workspace->size; + int32_t main_stack_width = (toplevels_count <= mcount) ? output->geom.width - 2 * og : - output->mstack_width * (output->geom.width - 2 * og); + msize * (output->geom.width - 2 * og); int32_t w = output->geom.width - main_stack_width - 2 * og - lg; int32_t pure_h; @@ -58,7 +64,7 @@ layout_arrange(struct absn_output *output) int32_t dy = og; int i = 0; - if (toplevels_count <= output->mstack_count) { + if (toplevels_count <= mcount) { total_lg = (toplevels_count - 1) * lg; pure_h = output->geom.height - 2 * og - total_lg; h = pure_h / toplevels_count; @@ -66,8 +72,8 @@ layout_arrange(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->output != output || toplevel->floating || - toplevel->fullscreen) + if (toplevel->workspace != output->workspace || + toplevel->floating || toplevel->fullscreen) continue; cur_h = h + (i < r ? 1 : 0); @@ -88,15 +94,15 @@ layout_arrange(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->output != output || toplevel->floating || + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) continue; - if (i < output->mstack_count) { - total_lg = (output->mstack_count - 1) * lg; + if (i < mcount) { + total_lg = (mcount - 1) * lg; pure_h = output->geom.height - 2 * og - total_lg; - h = pure_h / output->mstack_count; - r = pure_h % output->mstack_count; + h = pure_h / mcount; + r = pure_h % mcount; cur_h = h + (i < r ? 1 : 0); @@ -109,17 +115,16 @@ layout_arrange(struct absn_output *output) dy += cur_h + lg; } else { - if (i == output->mstack_count) + if (i == mcount) dy = og; - int32_t stack_count = toplevels_count - - output->mstack_count; + int32_t stack_count = toplevels_count - mcount; total_lg = (stack_count - 1) * lg; pure_h = output->geom.height - 2 * og - total_lg; h = pure_h / stack_count; r = pure_h % stack_count; - cur_h = h + (i - output->mstack_count < r ? 1 : 0); + cur_h = h + (i - mcount < r ? 1 : 0); new_geom.x = output->geom.x + main_stack_width + lg + og; diff --git a/src/server.c b/src/server.c index 199934e..508361f 100644 --- a/src/server.c +++ b/src/server.c @@ -46,6 +46,16 @@ new_output(struct wl_listener *listener, void *data) output->wlr = wlr_output; output->server = server; + for (int i = 0; i < server->workspaces_count; ++i) { + if (!server->workspaces[i].output) { + server->workspaces[i].output = output; + output->workspace = &server->workspaces[i]; + output->workspace->count = STACK_COUNT; + output->workspace->count = STACK_SIZE; + break; + } + } + LISTEN(output->frame, output_frame, wlr_output->events.frame); LISTEN(output->request_state, output_request_state, wlr_output->events.request_state); @@ -64,9 +74,6 @@ new_output(struct wl_listener *listener, void *data) scene_output); wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); - - output->mstack_count = MSTACK_SIZE; - output->mstack_width = MSTACK_WIDTH; } void diff --git a/src/toplevel-handlers.c b/src/toplevel-handlers.c index eba8e1d..8c60abf 100644 --- a/src/toplevel-handlers.c +++ b/src/toplevel-handlers.c @@ -55,6 +55,7 @@ toplevel_map(struct wl_listener *listener, void *data) update_focused_output(toplevel->server); toplevel->output = toplevel->server->focused_output; + toplevel->workspace = toplevel->output->workspace; toplevel->fullscreen = false; wl_list_insert(&toplevel->server->toplevels, &toplevel->link);