diff options
| author | user <user@clank> | 2026-09-02 15:03:53 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-02 15:03:53 +0200 |
| commit | 1a3ba183ae8f2613cae847c8f6460782512acc40 (patch) | |
| tree | 68bdc1e82b25e40452e2400ddcfcd2e6dd05b36e /src | |
| parent | Merge branch 'multiplayer': shared multi-client attach (diff) | |
| download | slosh-1a3ba183ae8f2613cae847c8f6460782512acc40.tar.gz slosh-1a3ba183ae8f2613cae847c8f6460782512acc40.tar.xz slosh-1a3ba183ae8f2613cae847c8f6460782512acc40.zip | |
multi-attach: say who else is watching, and where you are
A small tag in each client's own top-right corner when several
terminals share the session: the viewer count, and on a view that is
a crop being panned by somebody else's cursor, the crop's offset into
the shared screen ("2 clients +12+4") -- which is exactly the moment
a screen moving on its own needs explaining. Stamped per client after
projection, because every terminal has its own count of others and
its own offset; the shared status bar is composed once and can be
cropped out of a panned view anyway. attach_indicator false hides
it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.c | 5 | ||||
| -rw-r--r-- | src/config.c | 7 | ||||
| -rw-r--r-- | src/server.c | 29 |
3 files changed, 41 insertions, 0 deletions
@@ -93,6 +93,11 @@ bool app_cfg_multi_attach(void) { return CFG.multi_attach; } +bool app_cfg_attach_indicator(void) { + ensure_config(); + return CFG.attach_indicator; +} + int app_cfg_size_follows(void) { ensure_config(); return CFG.size_follows; diff --git a/src/config.c b/src/config.c index bfbfdf7..9c06983 100644 --- a/src/config.c +++ b/src/config.c @@ -919,6 +919,7 @@ void config_defaults(config_t *c) { c->status_pad = 4; c->focus_follows_mouse = true; c->multi_attach = true; + c->attach_indicator = true; c->size_follows = SIZE_FOLLOWS_ACTIVE; c->in_band_shaders = false; /* Windows has no VEOF for the line discipline to act on, so ^D there is a @@ -1613,6 +1614,9 @@ char *config_render(const config_t *c) { "multi_attach %s // several terminals at once; off: a new " "client displaces the old\n", yesno(c->multi_attach)); + cb_add(&b, + "attach_indicator %s // top-right tag when others are watching\n", + yesno(c->attach_indicator)); cb_add(&b, "size_follows \"%s\" // or \"smallest\" / \"largest\"\n", c->size_follows == SIZE_FOLLOWS_SMALLEST ? "smallest" : c->size_follows == SIZE_FOLLOWS_LARGEST ? "largest" @@ -1851,6 +1855,7 @@ const char *config_default_path(void) { static const char *const KNOWN_TOP[] = { "include", /* read before the rest, but a name this file understands */ "anim_ms", + "attach_indicator", "bell_indicator", "bell_mark", "close_mark", @@ -2095,6 +2100,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err, 0, c->focus_follows_mouse); c->multi_attach = kdl_arg_bool(kdl_child(root, "multi_attach"), 0, c->multi_attach); + c->attach_indicator = + kdl_arg_bool(kdl_child(root, "attach_indicator"), 0, c->attach_indicator); const char *sizef = kdl_arg(kdl_child(root, "size_follows"), 0, NULL); if (sizef) { if (strcmp(sizef, "active") == 0) diff --git a/src/server.c b/src/server.c index 7443648..472fcdd 100644 --- a/src/server.c +++ b/src/server.c @@ -308,11 +308,40 @@ static void update_viewport(conn_t *c, const screen_t *src) { if (c->shown_rows > c->rows) c->shown_rows = c->rows; } +/* The multi-client tag, stamped into one client's projected view: this is + * per-client chrome (every terminal has its own count of "others", its own + * crop offset), so it cannot live on the shared status bar, which is + * composed once and might be cropped out of a panned view anyway. Top-right + * of the client's own screen, which is always visible; toasts keep the + * bottom-right. Written after projection and before the diff, so it costs + * bytes only when it changes -- and when it disappears, the diff restores + * the shared cells beneath it on its own. */ +static void stamp_indicator(server_t *s, conn_t *c) { + if (!app_cfg_attach_indicator()) return; + size_t viewers = display_count(s); + if (viewers < 2) return; + char tag[48]; + if (c->view_x || c->view_y) + /* The crop's origin in the shared screen: "you are at +col+row of + * something bigger", which is the disorienting case the tag exists for. */ + snprintf(tag, sizeof tag, " %zu clients +%u+%u ", viewers, + (unsigned)c->view_x, (unsigned)c->view_y); + else + snprintf(tag, sizeof tag, " %zu clients ", viewers); + size_t len = strlen(tag); + if (len >= c->view.cols) return; /* a view too narrow to say it in */ + uint16_t x0 = (uint16_t)(c->view.cols - len); + for (size_t i = 0; i < len; i++) + screen_put_utf8(&c->view, (uint16_t)(x0 + i), 0, &tag[i], 1, (color_t){0}, + (color_t){0}, ATTR_DIM | ATTR_INVERSE); +} + static bool push_frame(server_t *s, conn_t *c) { uint16_t old_x = c->view_x, old_y = c->view_y; uint16_t old_cols = c->shown_cols, old_rows = c->shown_rows; update_viewport(c, &s->screen); screen_project(&c->view, &s->screen, c->view_x, c->view_y); + stamp_indicator(s, c); screen_render(&c->view); if (!c->view.out_len) return true; if (!conn_send(c, MSG_OUTPUT, c->view.out, c->view.out_len)) { |
