SWOv git · main
SWOv - window overview for sway
C 91.5% Markdown 7.6%git clone https://git.christianimmanuel.de/sway/SWOv.gitwget https://git.christianimmanuel.de/sway/SWOv/archive/SWOv.tar.gzUnify config name And stuff
README.md | 17 +++++++++++----- config.example | 14 +++++++++---- sw_config.example | 60 ------------------------------------------------------- sw_theme.h | 10 +++++----- swov.c | 41 ++++++++++++++++++++++++++----------- 5 files changed, 56 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 5013474..bb8d411 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,10 @@ when there is one. left or right quarter of another it inserts there, pushing the occupied run up by one. -**Ghost slots** are the free numbers 0–10. They appear when a workspace drag +**Ghost slots** are the free numbers 0–10. Dragging a window inside swov +brings them out; a drag from swas does not, unless `drop_ghosts=1` — they add +a dozen tiles to the grid, and the workspaces you are aiming at shrink to a +third just as you start aiming. They appear when a workspace drag starts, or when a dragged window leaves its own workspace, and the tiles glide aside to make room. Drop on one to give a workspace that number, or to create a workspace from a single window. @@ -190,7 +193,7 @@ there before, and takes that. `--beside` places the new window next to an existing one with the same three sway commands a drag inside swov uses, and `--adopt-debug` narrates the whole thing to stderr. -appwheel uses all three: `overview=1` puts swov behind the wheel, dragging an +swas uses all three: `overview=1` puts swov behind the wheel, dragging an app asks it where the pointer is — including which side of which window — and dropping starts the app exactly there. @@ -218,8 +221,11 @@ swov --info # every path and setting in use: binary, config, usage file, A second dot scale down the *right* edge of each tile says how busy that workspace is, mirroring the usage dots on the left: the same shape in a different colour, one for the time you have spent there and one for the work -happening there now. It stays teal until a workspace is really pinned, and -only then tips towards red. swbr measures it — a rate needs two samples +happening there now. The scale is in cores — one core kept busy is `1.0`, and `cpu_full=4` fills +it. Anything alive but below the scale gets one faint dot, so a workspace that +is doing something never looks asleep, while a terminal at a prompt stays +blank. It stays teal until a workspace is really pinned, and only then tips +towards red. swbr measures it — a rate needs two samples seconds apart and swov is only on screen for a moment — and leaves the answer in `$XDG_RUNTIME_DIR/swbr-cpu`. Without swbr running the file is stale or missing and nothing is drawn. `cpu=0` turns it off. @@ -235,7 +241,7 @@ swov --ssaa=1 --header_pos=top-left swov --shot /tmp/o.png # one frame to a PNG, for tuning colours ``` -Colours and fonts can also be set once for swov, appwheel and swbr together in +Colours and fonts can also be set once for swov, swas and swbr together in `${XDG_CONFIG_HOME:-~/.config}/sw/config`, using role names (`surface`, `accent`, `hl`, ...) that each program maps onto its own keys. `sw_theme.h` lists them. The file above is read after it, so swov's own config always wins. @@ -252,6 +258,7 @@ lists them. The file above is read after it, so swov's own config always wins. | `header_pos`, `hints_pos` | `none`, or `top`/`bottom` + `left`/`center`/`right` | | `anim_ms` | tile glide duration, and the backdrop fade; `0` disables | | `blur` | how soft `--backdrop` is drawn, `0`–`3` | +| `drop_ghosts` | offer the free numbers while an app is dragged over the backdrop | | `cpu`, `cpu_min`, `cpu_full` | the load dot, and the range it covers | | `track`, `usage_dots`, `dot_count`, `dot_px` | usage recording and its dot scale | | `start_selection` | `workspace`, `none` or `window` | diff --git a/config.example b/config.example index ac187ac..3ab5ab2 100644 --- a/config.example +++ b/config.example @@ -27,11 +27,17 @@ usage_dots=1 # dot scale down the left edge of a tile: how much that dot_count=14 # how many dots the scale has; fewer are drawn if the tile # is too short for them dot_px=5 # dot diameter -cpu=1 # a dot next to a workspace number showing how busy it is. -cpu_min=4 # swbr measures this and leaves it in -cpu_full=60 # $XDG_RUNTIME_DIR/swbr-cpu; without swbr running there is - # nothing to show and nothing is drawn +cpu=1 # a dot scale down the right edge of a tile, mirroring the +cpu_idle=0.01 # usage dots on the left. In cores: 1.0 is one core kept +cpu_min=0.25 # busy, and four fills the scale. Anything alive but under +cpu_full=4 # cpu_min gets one faint dot. swbr measures it and + # leaves it in $XDG_RUNTIME_DIR/swbr-cpu; without swbr + # running there is nothing to show and nothing is drawn +drop_ghosts=0 # --backdrop only: 1 = while an app is being dragged over + # the overview, offer the free workspace numbers as extra + # tiles. They cost the real tiles two thirds of their size + # just as you start aiming, so this is off blur=2 # --backdrop only: how soft the overview is drawn while # something else has the foreground. 0 = off, 3 = softest. # It sharpens by itself while an app is being dragged over diff --git a/sw_config.example b/sw_config.example deleted file mode 100644 index 57458a2..0000000 --- a/sw_config.example +++ /dev/null @@ -1,60 +0,0 @@ -# ~/.config/sw/config — one look for swov, appwheel and swbr. -# -# Keys written here, before any [section], go to all three. Role names are -# translated to each program's own keys; roles a program has no use for are -# dropped. sw_theme.h holds the whole table. -# -# Read after the built-in defaults and before each program's own config, so -# ~/.config/swov/config and the command line still win over anything here. - -# --- the palette --------------------------------------------------------- -# role swov appwheel swbr -bg=0d1117cc # bg bg — the scrim -surface=1e2733f2 # tile ring bg the panel itself -surface_alt=26313ff2 # tile_sel ring2 — -surface_hi=2b3644f2 # tile_hover — ws_visible_bg -inset=11171f9e # mini_bg center — -card=33404ff7 # card — ws_bg -card_hi=46566af7 # card_hover — — -card_focus=3b4a5bf7 # card_focus — — - -text=e8e8e8ff # text text text -subtext=b3c0cdff # subtext — ws_fg, ws_visible_fg -dim=5a6b7aff # dim dim dim -hint=a7b5c4ff # hint — — - -accent=89afc4ff # accent accent accent, msg_info -hl=cb9b00ff # hl hl hl, ws_focused_bg, mode_bg -hltext=141414ff # hltext hltext ws_focused_fg, mode_fg -current=4fb3a5ff # current — — -match=b58ae0ff # match — — -warn=cb9b00ff # — — msg_warn -urgent=e0533cff # urgent — urgent, ws_urgent_bg, msg_error -ok=3ddc84ff # — — running -outline=0a0e1499 # outline — outline, separator_color -shadow=00000073 # shadow_color — — - -# --- everything else ----------------------------------------------------- -# font= leave unset and each program asks fc-match -ui_scale=1.0 -anim_ms=160 -corner_radius=14 # swov radius, swbr radius. appwheel's `radius` is the size - # of the wheel, so it is left alone -ssaa=2 # swov, appwheel -icons=1 # swov, appwheel -icon_px=40 - -# --- per program --------------------------------------------------------- -# Inside a section that program's own key names work as well. - -[swov] -# blur=2 -# cpu=1 - -[appwheel] -# radius=0.44 -# slots=8 - -[swbr] -# height=30 -# ws_cpu=1 diff --git a/sw_theme.h b/sw_theme.h index 63d22c6..0a512fc 100644 --- a/sw_theme.h +++ b/sw_theme.h @@ -1,10 +1,10 @@ -/* sw_theme.h — one look for swov, appwheel and swbr. +/* sw_theme.h — one look for swov, swas and swbr. * * ${XDG_CONFIG_HOME:-~/.config}/sw/config * * key=value, '#' comments, same as every other config here. Keys written * before any [section] go to all three programs; keys inside [swov], - * [appwheel] or [swbr] go to that one only. + * [swas] or [swbr] go to that one only. * * Outside a section only *role* names are understood (surface, accent, hl, * ...). Each program translates them to its own keys, and roles it has no use @@ -34,11 +34,11 @@ * separated by commas: swbr paints its focused workspace button with `hl`. */ typedef struct { - const char *role, *swov, *appwheel, *swbr; + const char *role, *swov, *swas, *swbr; } SwRole; static const SwRole SW_ROLES[] = { - /* role swov appwheel swbr */ + /* role swov swas swbr */ { "bg", "bg", "bg", NULL }, { "surface", "tile", "ring", "bg" }, { "surface_alt", "tile_sel", "ring2", NULL }, @@ -97,7 +97,7 @@ static int sw_ci_eq(const char *a, const char *b) static const char *sw_role_for(const SwRole *r, const char *app) { if (sw_ci_eq(app, "swov")) return r->swov; - if (sw_ci_eq(app, "appwheel")) return r->appwheel; + if (sw_ci_eq(app, "swas") || sw_ci_eq(app, "appwheel")) return r->swas; if (sw_ci_eq(app, "swbr")) return r->swbr; return NULL; } diff --git a/swov.c b/swov.c index 22a8093..1d343ce 100644 --- a/swov.c +++ b/swov.c @@ -228,8 +228,10 @@ typedef struct { int track; /* record how long each workspace is used */ int back_scope; /* -b: 0 global, 1 this monitor, 2 sway's own */ int blur; /* --backdrop only: 0 off, 1..3 how soft */ - int cpu; /* the load dot on a tile, measured by swbr */ - float cpu_min, cpu_full; /* under min nothing shows; full = fully hot */ + int drop_ghosts; /* --backdrop: offer the free numbers as tiles */ + int cpu; /* the load dots on a tile, measured by swbr */ + float cpu_idle; /* under this, nothing is happening at all */ + float cpu_min, cpu_full; /* the scale, in cores */ int dot_count; /* how many dots the scale has */ float dot_px; /* dot diameter */ float anim_ms; /* tile glide duration, 0 disables */ @@ -280,8 +282,10 @@ static Cfg cfg_defaults(void) c.back_scope = 0; /* global: go back to where I just was */ c.blur = 2; c.cpu = 1; - c.cpu_min = 4.0f; - c.cpu_full = 60.0f; + c.drop_ghosts = 0; + c.cpu_idle = 0.01f; /* cores; under this nothing is happening */ + c.cpu_min = 0.25f; /* cores, not a share of the machine */ + c.cpu_full = 4.0f; c.dot_count = 14; c.dot_px = 5.0f; c.anim_ms = 160.0f; @@ -300,7 +304,7 @@ static Cfg cfg_defaults(void) c.quit_on_focus_loss = 1; c.quit_after_action = 0; - /* palette: same family as the appwheel config */ + /* palette: same family as the swas config */ c.bg = rgba(0x0d1117cc); /* dims whatever is behind the overlay*/ c.tile = rgba(0x1e2733f2); /* workspace tile */ c.tile_sel = rgba(0x26313ff2); /* selected workspace tile */ @@ -367,6 +371,8 @@ static void cfg_set(Cfg *c, const char *k, const char *v) else if (key_is(k,"dot_px")) c->dot_px = (float)atof(v); else if (key_is(k,"track")) c->track = atoi(v) != 0; else if (key_is(k,"cpu")) c->cpu = atoi(v) != 0; + else if (key_is(k,"drop_ghosts")) c->drop_ghosts = atoi(v) != 0; + else if (key_is(k,"cpu_idle")) c->cpu_idle = (float)atof(v); else if (key_is(k,"cpu_min")) c->cpu_min = (float)atof(v); else if (key_is(k,"cpu_full")) c->cpu_full = (float)atof(v); else if (key_is(k,"blur")) { @@ -1411,7 +1417,7 @@ static Cfg C; * swbr measures it — a rate needs two samples seconds apart, and swov is only * on screen for a moment — and leaves the answer here. If swbr is not running * the file is stale or missing and nothing is drawn. */ -typedef struct { char name[64]; float pct; } CpuWs; +typedef struct { char name[64]; float cores; } CpuWs; static CpuWs CPU[64]; static int NCPU; @@ -1441,20 +1447,22 @@ static void cpu_load(void) if (!tab) continue; *tab = 0; str_set(CPU[NCPU].name, sizeof(CPU[0].name), line); - CPU[NCPU].pct = (float)atof(tab + 1); + CPU[NCPU].cores = (float)atof(tab + 1); NCPU++; } fclose(f); } -/* how busy, 0..1, or -1 when there is nothing worth drawing */ +/* how busy, 0..1, or -1 when there is nothing worth drawing. + * The number swbr leaves behind is in cores: 1.0 is one core kept busy. */ static float cpu_frac(const char *ws_name) { for (int i = 0; i < NCPU; ++i) { if (strcmp(CPU[i].name, ws_name)) continue; - if (CPU[i].pct < C.cpu_min) return -1.0f; + if (CPU[i].cores < C.cpu_idle) return -1.0f; /* genuinely nothing */ + if (CPU[i].cores < C.cpu_min) return 0.0f; /* a hint, one dot */ float span = C.cpu_full - C.cpu_min; - float f = span > 0.0f ? (CPU[i].pct - C.cpu_min) / span : 1.0f; + float f = span > 0.0f ? (CPU[i].cores - C.cpu_min) / span : 1.0f; return SDL_clamp(f, 0.0f, 1.0f); } return -1.0f; @@ -4126,6 +4134,8 @@ static void draw_workspace(int idx) int cl = SDL_clamp((int)SDL_ceilf(cpu * (float)n), 1, n); SDL_FColor hot = cpu < 0.85f ? C.accent : mix(C.accent, C.urgent, (cpu - 0.85f) / 0.15f); + /* below the scale but not asleep: one dot, faint */ + if (cpu <= 0.0f) hot = with_alpha(mix(C.dim, C.accent, 0.4f), 0.55f); for (int i = 0; i < n; ++i) { bool on = (n - i) <= cl; SDL_FRect dot = { cxr - d * 0.5f, y0 + (float)i * (d + gap), d, d }; @@ -4647,7 +4657,7 @@ static void usage(void) " --backdrop draw the overview behind another window, taking no\n" " input of its own: it fades in, and reads commands on\n" " stdin (hover FX FY, drag on|off, fade in|out, quit).\n" -" This is what appwheel puts behind its wheel\n" +" This is what swas puts behind its wheel\n" " --usage print how long each workspace has been used, and exit\n" " --info print every path and setting swov is using, and exit\n" " -c, --config PATH read this config file instead of the default\n" @@ -5301,7 +5311,14 @@ static bool backdrop_command(char *line) assign_pid_to_ws(pid, ws); return true; } - if (!strcmp(line, "drag on")) { set_ghosts(0, 10); BLUR_WANT = 0.0f; return true; } + if (!strcmp(line, "drag on")) { + /* Offering every free number adds a dozen tiles to the grid, and the + * workspaces you are actually aiming at shrink to a third of their + * size just as you start aiming. Off unless asked for. */ + if (C.drop_ghosts) set_ghosts(0, 10); + BLUR_WANT = 0.0f; + return true; + } if (!strcmp(line, "drag off")) { set_ghosts(-1, -1); BLUR_WANT = 1.0f;