Mercurial > gbwm
changeset 1:286d4af85ebe
Ported workspaces from eowm
author | Atarwn Gard <a@qwa.su> |
---|---|
date | Fri, 10 Oct 2025 22:52:01 +0500 |
parents | ee781c291790 |
children | 3ad7c3ab949e |
files | gbwm.c |
diffstat | 1 files changed, 124 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/gbwm.c Fri Oct 10 13:40:59 2025 +0500 +++ b/gbwm.c Fri Oct 10 22:52:01 2025 +0500 @@ -1,4 +1,4 @@ -/* eowm - grid-based tiling window manager */ +/* gbwm - grid-based tiling window manager */ #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/Xft/Xft.h> @@ -29,6 +29,7 @@ int x, y, w, h; int saved_x, saved_y, saved_w, saved_h; // Saved position before fullscreen int isfullscreen; + int workspace; Client *next; }; @@ -57,7 +58,8 @@ static Display *dpy; static Window root; -static Client *clients = NULL; +static Client *workspaces[9] = {NULL}; // 9 workspaces +static int current_ws = 0; static Client *focused = NULL; static int sw, sh; static int overlay_mode = 0; @@ -90,10 +92,13 @@ static int sendevent(Client *c, Atom proto); static void updateborder(Client *c); static void find_next_free_cell(int *out_r, int *out_c); +static void switchws(const Arg *arg); +static void movewin_to_ws(const Arg *arg); // Commands static const char *termcmd[] = { "alacritty", NULL }; static const char *menucmd[] = { "dmenu_run", NULL }; +static const char *scrotcmd[] = { "scrot", NULL }; // Key bindings static Key keys[] = { @@ -101,15 +106,38 @@ { MOD, XK_t, enter_overlay, {0} }, { MOD, XK_Return, spawn, {.v = termcmd} }, { MOD, XK_p, spawn, {.v = menucmd} }, + { 0, XK_Print, spawn, {.v = scrotcmd} }, { MOD, XK_q, killclient, {0} }, { MOD, XK_f, toggle_fullscreen, {0} }, { MOD, XK_Tab, cycle_focus, {0} }, { MOD|ShiftMask, XK_q, quit, {0} }, + + // Workspaces + { MOD, XK_1, switchws, {.i = 0} }, + { MOD, XK_2, switchws, {.i = 1} }, + { MOD, XK_3, switchws, {.i = 2} }, + { MOD, XK_4, switchws, {.i = 3} }, + { MOD, XK_5, switchws, {.i = 4} }, + { MOD, XK_6, switchws, {.i = 5} }, + { MOD, XK_7, switchws, {.i = 6} }, + { MOD, XK_8, switchws, {.i = 7} }, + { MOD, XK_9, switchws, {.i = 8} }, + + // Move window to workspace + { MOD|ShiftMask, XK_1, movewin_to_ws, {.i = 0} }, + { MOD|ShiftMask, XK_2, movewin_to_ws, {.i = 1} }, + { MOD|ShiftMask, XK_3, movewin_to_ws, {.i = 2} }, + { MOD|ShiftMask, XK_4, movewin_to_ws, {.i = 3} }, + { MOD|ShiftMask, XK_5, movewin_to_ws, {.i = 4} }, + { MOD|ShiftMask, XK_6, movewin_to_ws, {.i = 5} }, + { MOD|ShiftMask, XK_7, movewin_to_ws, {.i = 6} }, + { MOD|ShiftMask, XK_8, movewin_to_ws, {.i = 7} }, + { MOD|ShiftMask, XK_9, movewin_to_ws, {.i = 8} }, }; // Event handlers static void buttonpress(XEvent *e) { - for (Client *c = clients; c; c = c->next) + for (Client *c = workspaces[current_ws]; c; c = c->next) if (c->win == e->xbutton.subwindow) { focus(c); break; @@ -119,7 +147,7 @@ static void clientmessage(XEvent *e) { XClientMessageEvent *cme = &e->xclient; Client *c; - for (c = clients; c; c = c->next) + for (c = workspaces[current_ws]; c; c = c->next) if (c->win == cme->window) break; if (!c) @@ -137,8 +165,9 @@ Client *c = calloc(1, sizeof(Client)); c->win = e->xmaprequest.window; - c->next = clients; - clients = c; + c->workspace = current_ws; + c->next = workspaces[current_ws]; + workspaces[current_ws] = c; // ICCCM setup XSetWindowBorderWidth(dpy, c->win, border_width); @@ -153,30 +182,35 @@ arrange(); } -static void unmapnotify(XEvent *e) { - Client **p; - for (p = &clients; *p && (*p)->win != e->xunmap.window; p = &(*p)->next); - if (*p) { - Client *c = *p; - if (focused == c) { - focused = c->next ? c->next : (clients == c ? NULL : clients); +static void removeclient(Window win) { + Client *c, **prev; + for (prev = &workspaces[current_ws]; (c = *prev); prev = &c->next) { + if (c->win == win) { + *prev = c->next; + if (focused == c) { + focused = workspaces[current_ws]; + if (focused) + focus(focused); + } + free(c); + arrange(); + return; } - *p = c->next; - free(c); - if (focused) - focus(focused); - arrange(); } } +static void unmapnotify(XEvent *e) { + removeclient(e->xunmap.window); +} + static void destroynotify(XEvent *e) { - unmapnotify(e); + removeclient(e->xdestroywindow.window); } static void enternotify(XEvent *e) { if (e->xcrossing.mode != NotifyNormal || e->xcrossing.detail == NotifyInferior) return; - for (Client *c = clients; c; c = c->next) + for (Client *c = workspaces[current_ws]; c; c = c->next) if (c->win == e->xcrossing.window) { focus(c); break; @@ -263,7 +297,7 @@ int cell_y = padding + r * (cell_h + padding); // Check if any window overlaps with this cell - for (Client *cl = clients; cl; cl = cl->next) { + for (Client *cl = workspaces[current_ws]; cl; cl = cl->next) { if (cl->isfullscreen) continue; // Check for overlap @@ -301,7 +335,7 @@ int cell_x = padding; int cell_y = padding; - for (Client *cl = clients; cl; cl = cl->next) { + for (Client *cl = workspaces[current_ws]; cl; cl = cl->next) { if (cl->isfullscreen) continue; if (cl->x == cell_x && cl->y == cell_y && cl->w == cell_w && cl->h == cell_h) { @@ -312,7 +346,7 @@ int check_y = padding + r * (cell_h + padding); int found_1x1 = 0; - for (Client *check = clients; check; check = check->next) { + for (Client *check = workspaces[current_ws]; check; check = check->next) { if (check->isfullscreen) continue; if (check->x == check_x && check->y == check_y && check->w == cell_w && check->h == cell_h) { @@ -338,9 +372,9 @@ } static void arrange(void) { - if (!clients) return; + if (!workspaces[current_ws]) return; - if (!focused) focused = clients; + if (!focused) focused = workspaces[current_ws]; if (focused->isfullscreen) { return; @@ -359,7 +393,7 @@ } // Update all borders - for (Client *c = clients; c; c = c->next) + for (Client *c = workspaces[current_ws]; c; c = c->next) updateborder(c); } @@ -512,6 +546,66 @@ resize(focused, x, y, w, h); } +// Workspace functions +static void switchws(const Arg *arg) { + int ws = arg->i; + if (ws < 0 || ws >= 9 || ws == current_ws) return; + + current_ws = ws; + + // Hide all windows from all workspaces + for (int i = 0; i < 9; i++) { + for (Client *c = workspaces[i]; c; c = c->next) { + XUnmapWindow(dpy, c->win); + } + } + + // Show current workspace windows + for (Client *c = workspaces[current_ws]; c; c = c->next) { + XMapWindow(dpy, c->win); + } + + focused = workspaces[current_ws]; + if (focused) focus(focused); + arrange(); +} + +static void movewin_to_ws(const Arg *arg) { + int ws = arg->i; + if (!focused || ws < 0 || ws >= 9 || ws == current_ws) return; + + Client *moving = focused; + + // Remove from current workspace + Client **prev; + for (prev = &workspaces[current_ws]; *prev; prev = &(*prev)->next) { + if (*prev == moving) { + *prev = moving->next; + break; + } + } + + // Add to target workspace + moving->workspace = ws; + moving->next = workspaces[ws]; + workspaces[ws] = moving; + moving->isfullscreen = 0; // Reset fullscreen state + + // Hide the window we just moved + XUnmapWindow(dpy, moving->win); + + // Update focus to next available window in current workspace + focused = workspaces[current_ws]; + if (focused) { + focus(focused); + } else { + focused = NULL; + } + + // Re-arrange current workspace + arrange(); +} + // Action functions static int sendevent(Client *c, Atom proto) { int n; @@ -608,15 +702,15 @@ } static void cycle_focus(const Arg *arg) { - if (!clients) return; + if (!workspaces[current_ws]) return; if (!focused) { - focus(clients); + focus(workspaces[current_ws]); return; } Client *next = focused->next; - if (!next) next = clients; + if (!next) next = workspaces[current_ws]; focus(next); } @@ -709,4 +803,4 @@ XCloseDisplay(dpy); return 0; -} \ No newline at end of file +}