diff options
| author | user <user@clank> | 2026-09-02 14:57:46 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-02 14:57:46 +0200 |
| commit | bac4b796f3f729d8d76b9c7c973126eac49872f2 (patch) | |
| tree | 0d040eb64e433122f982ea45912eba37ab54822a /include | |
| parent | webdemo: version from contrib/version, published by ship (diff) | |
| parent | multi-attach: the config knobs (diff) | |
| download | slosh-bac4b796f3f729d8d76b9c7c973126eac49872f2.tar.gz slosh-bac4b796f3f729d8d76b9c7c973126eac49872f2.tar.xz slosh-bac4b796f3f729d8d76b9c7c973126eac49872f2.zip | |
Merge branch 'multiplayer': shared multi-client attach
Several terminals can attach to one session at once: the canonical
screen becomes a model projected into every client's own size, with
per-client diff history, input parsing and kitty graphics state. The
active client (newest attach, then last input) sizes the canvas by
default; multi_attach and size_follows in the config control both
halves of the policy.
Diffstat (limited to 'include')
| -rw-r--r-- | include/app.h | 18 | ||||
| -rw-r--r-- | include/config.h | 19 | ||||
| -rw-r--r-- | include/graphics.h | 1 | ||||
| -rw-r--r-- | include/proto.h | 2 | ||||
| -rw-r--r-- | include/slosh.h | 8 |
5 files changed, 47 insertions, 1 deletions
diff --git a/include/app.h b/include/app.h index a203858..b3dd57c 100644 --- a/include/app.h +++ b/include/app.h @@ -5,6 +5,7 @@ #ifndef SLOSH_APP_H #define SLOSH_APP_H +#include "graphics.h" #include "kdl.h" #include "project.h" #include "shader.h" @@ -22,10 +23,16 @@ void app_event(app_t *a, const input_event_t *ev); /* Kitty graphics for this frame: the bytes the client's terminal needs, and * the same thing as JSON for tests. Bytes are borrowed until the next call. */ const char *app_graphics(app_t *a, size_t *len); +/* The same frame for one attached terminal. `state` is that terminal's own + * transmission/deletion history; the viewport is in canonical screen cells. */ +const char *app_graphics_view(app_t *a, graphics_t *state, uint16_t x, + uint16_t y, uint16_t cols, uint16_t rows, + size_t *len); void app_graphics_reset(app_t *a); /* Did the last app_graphics() stream reach the client? Undelivered frames * are regenerated: transmissions repeat and deletions stay owed. */ void app_graphics_commit(app_t *a, bool delivered); +void app_graphics_view_commit(graphics_t *state, bool delivered); char *app_graphics_json(app_t *a); /* Transient announcements, drawn bottom-right and expiring on their own. */ @@ -52,6 +59,11 @@ bool app_reload_config(char *err, size_t errcap); /* The files the config in force was read from: the one that was loaded and * everything it included, existing or not. What the watcher watches. */ size_t app_config_files(const char **out, size_t max); +/* The attach-sharing knobs, read fresh so a config reload changes policy on + * a running session: may several clients attach at once, and whose size the + * shared screen takes (SIZE_FOLLOWS_* in config.h). */ +bool app_cfg_multi_attach(void); +int app_cfg_size_follows(void); /* What the config in force complained about while loading, or "". A complaint is * not a failure -- an include that is not there, a shader nobody has heard of -- * so the session is running either way; this is for saying so. */ @@ -87,6 +99,12 @@ bool app_should_quit(const app_t *a); /* C-a d asks the client to leave while the session keeps running. */ bool app_detach_requested(const app_t *a); void app_clear_detach(app_t *a); +/* A different display took over the shared input stream. End state that cannot + * safely span clients (leader chord, pointer drag and hover position). */ +void app_cancel_client_interaction(app_t *a); +/* A release over client-side filler has no canonical target, but still ends a + * pointer gesture without disturbing that client's keyboard leader state. */ +void app_cancel_client_pointer(app_t *a); size_t app_pane_count(const app_t *a); /* Tabs. A tab is a layout tree; panes in every tab keep running. */ diff --git a/include/config.h b/include/config.h index fee6b2e..9db9c53 100644 --- a/include/config.h +++ b/include/config.h @@ -112,6 +112,13 @@ typedef struct { typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } align_t; +/* size_follows: which attached client sizes the shared screen. */ +enum { + SIZE_FOLLOWS_ACTIVE = 0, /* newest attach, then last input */ + SIZE_FOLLOWS_SMALLEST, /* min over clients: filler, never a crop */ + SIZE_FOLLOWS_LARGEST, /* max over clients: crops, never filler */ +}; + /* How many files one config may be built from: itself plus its includes. Small * and fixed, because a config assembled from more than this many pieces is a * thing nobody can read. */ @@ -306,6 +313,18 @@ typedef struct { uint16_t status_pad; bool focus_follows_mouse; + /* Several terminals may attach to one session at once (the default). + * false restores the classic rule: a new client displaces the one before + * it, which is what anyone using attach-from-elsewhere as "move my session + * here and *close it there*" actually wants. */ + bool multi_attach; + /* Whose size the shared screen takes when several clients are attached: + * the active client (newest attach, then last input -- the default), or + * the smallest / largest attached one. Smallest is the tmux rule: nobody + * is cropped and the roomiest terminal pays in filler; largest gives the + * big display everything and small ones a cursor-following crop. */ + int size_follows; + /* Whether Ctrl-D at an idle shell prompt exits that shell, the way the tty * line discipline would do it on POSIX. * diff --git a/include/graphics.h b/include/graphics.h index 6a338df..13cc5dc 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -66,6 +66,7 @@ typedef struct { uint32_t x_off, y_off; /* offset within the first cell, in pixels */ uint32_t sx, sy, sw, sh; /* source rectangle, in image pixels */ uint32_t px_w, px_h; /* the image's own size */ + uint32_t cell_px_w, cell_px_h; /* canonical pixels represented by a cell */ int format, compression; const uint8_t *data; /* NULL once the client has it */ size_t data_len; diff --git a/include/proto.h b/include/proto.h index 67b45f0..4df52a6 100644 --- a/include/proto.h +++ b/include/proto.h @@ -30,7 +30,7 @@ enum { enum { EXIT_SESSION_ENDED = 0, /* the last pane closed */ EXIT_DETACHED = 1, /* the user detached */ - EXIT_REPLACED = 2, /* another client attached */ + EXIT_REPLACED = 2, /* legacy: retained so new clients speak to old servers */ }; typedef struct { diff --git a/include/slosh.h b/include/slosh.h index e624bda..75aa658 100644 --- a/include/slosh.h +++ b/include/slosh.h @@ -76,6 +76,14 @@ void screen_init(screen_t *s, uint16_t cols, uint16_t rows); void screen_free(screen_t *s); void screen_resize(screen_t *s, uint16_t cols, uint16_t rows); void screen_clear(screen_t *s); +/* Project a canonical screen into a client-sized one. The source starts at + * (x,y); anything beyond its edges is blank filler. Diff history in `dst` is + * deliberately left alone, so every attached terminal advances independently. */ +void screen_project(screen_t *dst, const screen_t *src, uint16_t x, uint16_t y); +/* Move an existing client viewport only as far as needed to keep the canonical + * cursor visible, then clamp it to the canonical screen. */ +void screen_follow_cursor(const screen_t *src, uint16_t cols, uint16_t rows, + uint16_t *x, uint16_t *y); cell_t *screen_at(screen_t *s, uint16_t x, uint16_t y); void screen_put_utf8(screen_t *s, uint16_t x, uint16_t y, const char *txt, size_t len, color_t fg, color_t bg, uint16_t attrs); |
