aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-29 14:26:28 +0200
committeruser <user@clank>2026-09-29 14:26:28 +0200
commitca1b5bdf5bf7b5ff01ab515846802b3487599d3a (patch)
treea047fc09bccbe077b98acd0bf2648c2e02616b04 /include
parentpanes: read and write a pane by id, without taking focus (diff)
downloadslosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.tar.gz
slosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.tar.xz
slosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.zip
layouts, moves: build panes without pulling the view to them
Applying a layout landed on the first tab it made, and moving a pane into a tab took focus there. For a program building a pane in the background that is two failures at once: it yanks the view off the human mid-sentence, and it leaves the *next* caller to read focus as "where I am" and put its work in a stranger's tab. `apply-layout focus:false` builds the tabs and keeps looking at whatever was on screen; a layout naming an `active` tab still wins, because that is a statement about where to be. `move-pane` gains `beside` (which pane in the destination to split, rather than whatever it has focused) and `focus:false` -- the two things a caller placing a pane next to *itself* needs. That uncovered a sizing bug that was unreachable before: a pane's size comes from a layout pass, and a tab nobody has looked at never had one, so a pane built in the background stayed 1x1 and its program drew into a single cell. The jump is what used to size it. layout_tab() gives a background tab a real pass, borrowing the tab cursor for its length -- nothing composes, reads input or draws a frame in between.
Diffstat (limited to 'include')
-rw-r--r--include/app.h14
-rw-r--r--include/app_internal.h13
2 files changed, 27 insertions, 0 deletions
diff --git a/include/app.h b/include/app.h
index 6de3d8d..d656d03 100644
--- a/include/app.h
+++ b/include/app.h
@@ -168,6 +168,12 @@ bool app_set_tab_purpose(app_t *a, uint32_t id, const char *purpose,
* Purposes a layout declares are locked (D8). A relative `cwd=` in a *file*
* resolves against that file's directory, so a project's layout can be checked
* in beside the project; text has no directory and keeps meaning what it said. */
+/* Apply the *next* layout without changing which tab is on screen. Consumed by
+ * the one apply that follows, so it cannot leak into a later one. For a program
+ * building panes in the background: landing on the tab it just made moves the
+ * view out from under whoever is watching, and leaves the next caller to read
+ * focus as "where I am". A layout that names an `active` tab still wins. */
+void app_layout_keep_view(app_t *a);
bool app_apply_layout_text(app_t *a, const char *text, bool replace, char *err,
size_t errcap);
bool app_apply_layout_file(app_t *a, const char *path, bool replace, char *err,
@@ -272,6 +278,14 @@ bool app_minimize(app_t *a, uint32_t id);
bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id,
bool rows);
+/* The same move, saying where in the destination to land and whether to take
+ * focus there. `beside_id` is a pane in that tab to split (0 = whatever it has
+ * focused, the old behaviour); `take_focus` false leaves focus, and therefore
+ * the view, exactly where it was. What a program placing a pane beside itself
+ * in the background wants; refused if `beside_id` is not in `tab_id`. */
+bool app_move_pane_beside(app_t *a, uint32_t pane_id, uint32_t tab_id,
+ uint32_t beside_id, bool rows, bool take_focus);
+
/* The same, into a tab of its own; returns that tab's id, or 0 -- including for a
* pane that is already alone in its tab, which has nowhere to go. */
uint32_t app_move_pane_to_new_tab(app_t *a, uint32_t pane_id, const char *name);
diff --git a/include/app_internal.h b/include/app_internal.h
index c699be8..1466c89 100644
--- a/include/app_internal.h
+++ b/include/app_internal.h
@@ -328,6 +328,15 @@ struct app {
* the index is only meaningful once the array has stopped growing. */
size_t restore_tab;
+ /* Set for the duration of one app_apply_layout by `apply-layout focus:false`:
+ * build the tabs but keep looking at whatever was on screen. Applying a
+ * layout otherwise lands on the first tab it made, which for a program
+ * building a pane in the background means yanking the view off the human
+ * mid-sentence -- and, worse, leaving the *next* caller to read focus as
+ * "where I am" and land its own work in a stranger's tab. A layout that
+ * names an `active` tab still wins: that is a statement about where to be. */
+ bool layout_keep_view;
+
/* Set for the duration of one app_apply_layout: every pane it builds starts
* suspended whatever the file said. `open-workspace suspended:true` is the
* "open ten projects, run zero processes" case, which is a different question
@@ -481,6 +490,10 @@ void close_leaf(app_t *a, node_t *leaf);
node_t *first_leaf_of(node_t *n);
void focus_dir(app_t *a, int dx, int dy);
void layout(app_t *a);
+/* One layout pass over a tab by index, including one that is not on screen --
+ * how a pane in a background tab gets a real size instead of the 1x1 it was
+ * born with. Restores the viewed tab's geometry before returning. */
+void layout_tab(app_t *a, size_t ti);
node_t *pane_by_id(app_t *a, uint32_t id);
split_dir_t side_dir(char side);
bool split_fits(node_t *leaf, split_dir_t dir);