claim CLI tabs by the command's pid so tab order follows argv order
Command-line tabs fork in a tight loop and connect concurrently, so the first-free-slot claim left the tab order equal to connection order, an unpredictable permutation of the command-line order. Match the new toplevel's client pid to the slot the compositor forked it from (the pid survives the sh -c exec), keeping tab order == command-line order even when clients finish loading out of sequence. Wrapped commands whose exec pid differs from the fork pid fall back to first-free-slot as before. The last tab to map still becomes the active tab.
This commit is contained in:
parent
6fa1c0dfb1
commit
0e57ced16c
1 changed files with 28 additions and 16 deletions
|
|
@ -2160,6 +2160,11 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) {
|
|||
(void)listener;
|
||||
struct wlr_xdg_toplevel *toplevel = data;
|
||||
|
||||
pid_t cpid = -1;
|
||||
if (toplevel->base->client)
|
||||
wl_client_get_credentials(toplevel->base->client->client,
|
||||
&cpid, NULL, NULL);
|
||||
|
||||
struct tabbed_app *app = NULL;
|
||||
/* Prefer a slot prepared by add_tab() (Ctrl+Shift+T): its position was
|
||||
chosen to sit right next to the tab the user launched it from, so an
|
||||
|
|
@ -2167,8 +2172,19 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) {
|
|||
for (int i = 0; i < server.num_apps && !app; i++)
|
||||
if (!server.apps[i]->toplevel && server.apps[i]->pending_claim)
|
||||
app = server.apps[i];
|
||||
/* Otherwise claim the first free slot, as before (CLI startup tabs are
|
||||
claimed in connection order). */
|
||||
/* A command-line startup tab belongs to the slot whose launch pid matches
|
||||
the connecting client, so the tab order mirrors the command-line order
|
||||
even though the clients start concurrently and connect out of sequence.
|
||||
(add_tab()'s tracked pid can also match its own slot, so the
|
||||
pending_claim pass above always wins for those.) */
|
||||
if (!app && cpid > 0)
|
||||
for (int i = 0; i < server.num_apps; i++)
|
||||
if (!server.apps[i]->toplevel && server.apps[i]->pid == cpid) {
|
||||
app = server.apps[i];
|
||||
break;
|
||||
}
|
||||
/* Otherwise claim the first free slot: a client opened by a running app,
|
||||
or a wrapped command whose exec pid differs from the fork pid. */
|
||||
if (!app)
|
||||
for (int i = 0; i < server.num_apps; i++)
|
||||
if (!server.apps[i]->toplevel) {
|
||||
|
|
@ -2218,20 +2234,16 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) {
|
|||
wlr_scene_node_set_enabled(&app->tree->node, false);
|
||||
|
||||
/* [claim] ties the app slot to the *connected client's* PID, so tests
|
||||
can kill the tab that is actually active. App slots are claimed in
|
||||
connection order (first free slot), which is NOT the launch order
|
||||
the [launch] lines use when two clients start concurrently. */
|
||||
pid_t cpid = -1;
|
||||
if (toplevel->base->client)
|
||||
wl_client_get_credentials(toplevel->base->client->client,
|
||||
&cpid, NULL, NULL);
|
||||
/* The client that actually occupies this slot may have been launched by a
|
||||
*different* app entry (slots are claimed in connection order, which is
|
||||
not the launch order used for app->pid). Record its process group so a
|
||||
close signals the right one -- but only when that group is one WE own.
|
||||
An externally started client (e.g. from the compositor's own terminal)
|
||||
shares our process group; adopting it would make close/shutdown group-
|
||||
signal the launcher's whole session. Such clients are killed by pid. */
|
||||
can kill the tab that is actually active. The slot was chosen above by
|
||||
pid match (CLI tabs keep command-line order), by add_tab()'s pending
|
||||
claim, or by the first-free-slot fallback. */
|
||||
/* The client that actually occupies this slot may be the CLI command that
|
||||
forked it, an add_tab() tab, or a fallback-claimed extra. Record its
|
||||
process group so a close signals the right one -- but only when that
|
||||
group is one WE own. An externally started client (e.g. from the
|
||||
compositor's own terminal) shares our process group; adopting it would
|
||||
make close/shutdown group-signal the launcher's whole session. Such
|
||||
clients are killed by pid. */
|
||||
app->client_pid = cpid;
|
||||
pid_t cpg = cpid > 0 ? getpgid(cpid) : -1;
|
||||
app->pgid = (cpg > 0 && cpg != getpgid(0)) ? cpg : -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue