Add support for local windows for a client.

This commit is contained in:
Nicholas Marriott
2026-07-17 15:48:41 +01:00
parent 6dacc024f0
commit 38808509d5
36 changed files with 1101 additions and 170 deletions

View File

@@ -85,6 +85,7 @@ endif
# List of sources. # List of sources.
dist_tmux_SOURCES = \ dist_tmux_SOURCES = \
active.c \
alerts.c \ alerts.c \
arguments.c \ arguments.c \
attributes.c \ attributes.c \

449
active.c Normal file
View File

@@ -0,0 +1,449 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/* Local last-window stack entry. */
struct active_window_entry {
u_int window;
TAILQ_ENTRY(active_window_entry) entry;
};
/* Local last-window stack. */
TAILQ_HEAD(active_window_stack, active_window_entry);
/* Per-client and per-session local active window state. */
struct active_window {
struct client *client;
struct session *session;
u_int window;
struct active_window_stack lastw;
RB_ENTRY(active_window) entry;
};
RB_HEAD(active_windows, active_window);
static int
active_window_cmp(struct active_window *aw1, struct active_window *aw2)
{
uintptr_t c1 = (uintptr_t)aw1->client;
uintptr_t c2 = (uintptr_t)aw2->client;
uintptr_t s1 = (uintptr_t)aw1->session;
uintptr_t s2 = (uintptr_t)aw2->session;
if (c1 < c2)
return (-1);
if (c1 > c2)
return (1);
if (s1 < s2)
return (-1);
if (s1 > s2)
return (1);
return (0);
}
RB_GENERATE_STATIC(active_windows, active_window, entry, active_window_cmp);
static struct active_window *active_get(struct client *, struct session *);
static struct active_window *active_add(struct client *, struct session *,
struct winlink *);
static void active_free(struct active_window *);
static struct winlink *active_resolve(struct active_window *);
static void active_stack_remove(struct active_window_stack *, u_int);
static void active_stack_push(struct active_window_stack *, u_int);
static void active_changed(struct client *, struct session *,
struct winlink *, struct winlink *);
/* All local active window states. */
static struct active_windows active_windows = RB_INITIALIZER(&active_windows);
/* Find local active window state for a client and session. */
static struct active_window *
active_get(struct client *c, struct session *s)
{
struct active_window aw;
if (c == NULL || s == NULL)
return (NULL);
aw.client = c;
aw.session = s;
return (RB_FIND(active_windows, &active_windows, &aw));
}
/* Add local active window state for a client and session. */
static struct active_window *
active_add(struct client *c, struct session *s, struct winlink *wl)
{
struct active_window *aw;
aw = active_get(c, s);
if (aw == NULL) {
aw = xcalloc(1, sizeof *aw);
aw->client = c;
aw->session = s;
TAILQ_INIT(&aw->lastw);
RB_INSERT(active_windows, &active_windows, aw);
}
if (wl != NULL)
aw->window = wl->window->id;
return (aw);
}
/* Free local active window state. */
static void
active_free(struct active_window *aw)
{
struct active_window_entry *awe;
while (!TAILQ_EMPTY(&aw->lastw)) {
awe = TAILQ_FIRST(&aw->lastw);
TAILQ_REMOVE(&aw->lastw, awe, entry);
free(awe);
}
RB_REMOVE(active_windows, &active_windows, aw);
free(aw);
}
/* Resolve local active window state to a valid winlink. */
static struct winlink *
active_resolve(struct active_window *aw)
{
struct winlink *wl, *next;
u_int window;
if (aw == NULL || aw->session->curw == NULL)
return (NULL);
wl = winlink_find_by_window_id(&aw->session->windows, aw->window);
if (wl != NULL)
return (wl);
while (!TAILQ_EMPTY(&aw->lastw)) {
window = TAILQ_FIRST(&aw->lastw)->window;
next = winlink_find_by_window_id(&aw->session->windows, window);
active_stack_remove(&aw->lastw, window);
if (next != NULL) {
aw->window = next->window->id;
return (next);
}
}
aw->window = aw->session->curw->window->id;
return (aw->session->curw);
}
/* Remove a window from a local last-window stack. */
static void
active_stack_remove(struct active_window_stack *stack, u_int window)
{
struct active_window_entry *awe, *awe1;
TAILQ_FOREACH_SAFE(awe, stack, entry, awe1) {
if (awe->window == window) {
TAILQ_REMOVE(stack, awe, entry);
free(awe);
}
}
}
/* Push a window onto a local last-window stack. */
static void
active_stack_push(struct active_window_stack *stack, u_int window)
{
struct active_window_entry *awe;
active_stack_remove(stack, window);
awe = xcalloc(1, sizeof *awe);
awe->window = window;
TAILQ_INSERT_HEAD(stack, awe, entry);
}
/* Notify the server that a client's effective window changed. */
static void
active_changed(struct client *c, struct session *s, struct winlink *wl,
struct winlink *old)
{
struct event_payload *ep;
struct cmd_find_state fs;
if (wl == NULL || wl == old)
return;
if (options_get_number(global_options, "focus-events")) {
if (old != NULL)
window_update_focus(old->window);
window_update_focus(wl->window);
}
winlink_clear_flags(wl);
window_update_activity(wl->window);
tty_update_window_offset(wl->window);
if (c != NULL && c->session == s)
wl->window->latest = c;
ep = event_payload_create();
cmd_find_from_winlink(&fs, wl, 0);
event_payload_set_target(ep, &fs);
event_payload_set_client(ep, "client", c);
event_payload_set_session(ep, "session", s);
event_payload_set_window(ep, "window", wl->window);
event_payload_set_window(ep, "new_window", wl->window);
event_payload_set_int(ep, "window_index", wl->idx);
event_payload_set_int(ep, "new_window_index", wl->idx);
if (old != NULL) {
event_payload_set_window(ep, "old_window", old->window);
event_payload_set_int(ep, "old_window_index", old->idx);
}
events_fire("client-window-changed", ep);
if (c != NULL) {
c->flags |= CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS|
CLIENT_REDRAWBORDERS;
tty_update_client_offset(c);
status_update_cache(s);
}
recalculate_sizes();
}
/* Return if a client has local window selection for a session. */
int
active_is_local_window(struct client *c, struct session *s)
{
return (active_get(c, s) != NULL);
}
/* Make a client use local or shared window selection for a session. */
void
active_set_local_window(struct client *c, struct session *s,
enum active_window_mode mode)
{
struct active_window *aw;
struct winlink *wl, *old;
if (c == NULL || s == NULL || s->curw == NULL)
return;
old = active_get_effective_winlink(c, s);
if (mode == ACTIVE_LOCAL) {
active_add(c, s, old);
if (c != NULL && c->session == s)
c->flags |= CLIENT_REDRAWSTATUS;
return;
}
aw = active_get(c, s);
if (aw != NULL) {
active_free(aw);
wl = active_get_effective_winlink(c, s);
active_changed(c, s, wl, old);
if (c != NULL && c->session == s)
c->flags |= CLIENT_REDRAWSTATUS;
}
}
/* Return the effective winlink for a client and session. */
struct winlink *
active_get_effective_winlink(struct client *c, struct session *s)
{
struct active_window *aw;
if (s == NULL)
return (NULL);
aw = active_get(c, s);
if (aw != NULL)
return (active_resolve(aw));
return (s->curw);
}
/* Return the effective window for a client and session. */
struct window *
active_get_effective_window(struct client *c, struct session *s)
{
struct winlink *wl;
wl = active_get_effective_winlink(c, s);
if (wl == NULL)
return (NULL);
return (wl->window);
}
/* Select a winlink for a client and session. */
int
active_select_window(struct client *c, struct session *s, struct winlink *wl)
{
struct active_window *aw;
struct winlink *old;
int changed;
if (wl == NULL)
return (-1);
aw = active_get(c, s);
if (aw == NULL)
return (session_set_current(s, wl));
old = active_resolve(aw);
if (old == wl)
return (1);
if (old != NULL)
active_stack_push(&aw->lastw, old->window->id);
active_stack_remove(&aw->lastw, wl->window->id);
aw->window = wl->window->id;
changed = (old != wl);
active_changed(c, s, wl, old);
return (changed ? 0 : 1);
}
/* Select a window by index. */
int
active_select_window_index(struct client *c, struct session *s, int idx)
{
struct winlink *wl;
wl = winlink_find_by_index(&s->windows, idx);
return (active_select_window(c, s, wl));
}
/* Select the next window. */
int
active_next_window(struct client *c, struct session *s, int alert)
{
struct winlink *wl;
wl = active_get_effective_winlink(c, s);
if (wl == NULL)
return (-1);
do {
wl = winlink_next(wl);
if (wl == NULL)
wl = RB_MIN(winlinks, &s->windows);
if (!alert || (wl->flags & WINLINK_ALERTFLAGS))
return (active_select_window(c, s, wl));
} while (wl != active_get_effective_winlink(c, s));
return (-1);
}
/* Select the previous window. */
int
active_previous_window(struct client *c, struct session *s, int alert)
{
struct winlink *wl;
wl = active_get_effective_winlink(c, s);
if (wl == NULL)
return (-1);
do {
wl = winlink_previous(wl);
if (wl == NULL)
wl = RB_MAX(winlinks, &s->windows);
if (!alert || (wl->flags & WINLINK_ALERTFLAGS))
return (active_select_window(c, s, wl));
} while (wl != active_get_effective_winlink(c, s));
return (-1);
}
/* Select the last window. */
int
active_last_window(struct client *c, struct session *s)
{
struct active_window *aw;
struct winlink *wl;
u_int window;
aw = active_get(c, s);
if (aw == NULL)
return (session_last(s));
while (!TAILQ_EMPTY(&aw->lastw)) {
window = TAILQ_FIRST(&aw->lastw)->window;
wl = winlink_find_by_window_id(&s->windows, window);
if (wl != NULL)
return (active_select_window(c, s, wl));
active_stack_remove(&aw->lastw, window);
}
return (-1);
}
/* Remove all state for a client. */
void
active_remove_client(struct client *c)
{
struct active_window *aw, *aw1;
RB_FOREACH_SAFE(aw, active_windows, &active_windows, aw1) {
if (aw->client == c)
active_free(aw);
}
}
/* Remove all state for a session. */
void
active_remove_session(struct session *s)
{
struct active_window *aw, *aw1;
RB_FOREACH_SAFE(aw, active_windows, &active_windows, aw1) {
if (aw->session == s)
active_free(aw);
}
}
/* Remove a window from all local state. */
void
active_remove_window(struct window *w)
{
struct active_window *aw;
RB_FOREACH(aw, active_windows, &active_windows) {
active_stack_remove(&aw->lastw, w->id);
if (aw->window == w->id && aw->session->curw != NULL)
aw->window = aw->session->curw->window->id;
}
}
/* Return if this winlink is the effective winlink. */
int
active_is_effective_window(struct client *c, struct session *s,
struct winlink *wl)
{
return (wl != NULL && wl == active_get_effective_winlink(c, s));
}
/* Return if this winlink is the last effective winlink. */
int
active_is_last_window(struct client *c, struct session *s, struct winlink *wl)
{
struct active_window *aw;
struct active_window_entry *awe;
if (wl == NULL)
return (0);
aw = active_get(c, s);
if (aw == NULL)
return (wl == TAILQ_FIRST(&s->lastw));
TAILQ_FOREACH(awe, &aw->lastw, entry) {
if (winlink_find_by_window_id(&s->windows, awe->window) == NULL)
continue;
return (wl->window->id == awe->window);
}
return (0);
}

View File

@@ -314,7 +314,7 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
tty_putcode(&c->tty, TTYC_BEL); tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF) if (visual == VISUAL_OFF)
continue; continue;
if (c->session->curw == wl) { if (active_get_effective_winlink(c, c->session) == wl) {
status_message_set(c, -1, 1, 0, 0, status_message_set(c, -1, 1, 0, 0,
"%s in current window", type); "%s in current window", type);
} else { } else {

View File

@@ -93,7 +93,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) if (wp != NULL)
window_set_active_pane(wp->window, wp, 1); window_set_active_pane(wp->window, wp, 1);
session_set_current(s, wl); active_select_window(c, s, wl);
if (wp != NULL) if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
else else

View File

@@ -93,14 +93,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item); struct cmd_find_state *source = cmdq_get_source(item);
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct client *ac;
struct winlink *wl = source->wl; struct winlink *wl = source->wl;
struct winlink *current_wl;
struct session *src_s = source->s; struct session *src_s = source->s;
struct session *dst_s = target->s; struct session *dst_s = target->s;
struct window_pane *wp = source->wp; struct window_pane *wp = source->wp;
struct window *w = wl->window, *old_w = w; struct window *w = wl->window, *old_w = w;
char *cause, *cp; char *cause, *cp;
int idx = target->idx, before, old_idx = wl->idx; int idx = target->idx, before, old_idx = wl->idx;
int detached, local;
const char *template, *name = args_get(args, 'n'); const char *template, *name = args_get(args, 'n');
if (wp == w->modal) { if (wp == w->modal) {
@@ -117,11 +121,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
before = args_has(args, 'b'); before = args_has(args, 'b');
ac = tc;
if (ac == NULL || ac->session != dst_s)
ac = c;
detached = args_has(args, 'd');
local = (!detached && active_is_local_window(ac, dst_s));
if (args_has(args, 'a') || before) { if (args_has(args, 'a') || before) {
if (target->wl != NULL) if (target->wl != NULL)
idx = winlink_shuffle_up(dst_s, target->wl, before); idx = winlink_shuffle_up(dst_s, target->wl, before);
else else {
idx = winlink_shuffle_up(dst_s, dst_s->curw, before); current_wl = active_get_effective_winlink(ac, dst_s);
idx = winlink_shuffle_up(dst_s, current_wl, before);
}
if (idx == -1) if (idx == -1)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -129,7 +140,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (window_count_panes(w, 1) == 1) { if (window_count_panes(w, 1) == 1) {
if (server_link_window(src_s, wl, dst_s, idx, 0, if (server_link_window(src_s, wl, dst_s, idx, 0,
!args_has(args, 'd'), &cause) != 0) { !detached && !local, &cause) != 0) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -142,6 +153,13 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
wl = winlink_find_by_window(&dst_s->windows, w); wl = winlink_find_by_window(&dst_s->windows, w);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (local) {
active_select_window(ac, dst_s, wl);
if (ac != NULL && ac->session == dst_s)
cmd_find_from_client(current, ac, 0);
if (ac != NULL && ac->session == dst_s)
server_redraw_client(ac);
}
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx); window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
goto out; goto out;
} }
@@ -183,9 +201,17 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
window_remove_ref(w, __func__); window_remove_ref(w, __func__);
events_fire_window("window-created", w); events_fire_window("window-created", w);
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx); window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
if (!args_has(args, 'd')) { if (!detached) {
session_select(dst_s, wl->idx); if (local)
cmd_find_from_session(current, dst_s, 0); active_select_window(ac, dst_s, wl);
else
session_select(dst_s, wl->idx);
if (local && ac != NULL && ac->session == dst_s)
cmd_find_from_client(current, ac, 0);
else
cmd_find_from_session(current, dst_s, 0);
if (local && ac != NULL && ac->session == dst_s)
server_redraw_client(ac);
} }
server_redraw_session(src_s); server_redraw_session(src_s);

View File

@@ -483,7 +483,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
char *title, *cause = NULL; char *title, *cause = NULL;
int flags = 0, starting_choice = 0; int flags = 0, starting_choice = 0;
u_int px, py, i, count = args_count(args); u_int px, py, i, count = args_count(args);
struct options *o = target->s->curw->window->options; struct options *o = target->w->options;
struct options_entry *oe; struct options_entry *oe;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
@@ -584,7 +584,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
u_int px, py, w, h, count = args_count(args); u_int px, py, w, h, count = args_count(args);
struct args_value *av; struct args_value *av;
struct environ *env = NULL; struct environ *env = NULL;
struct options *o = s->curw->window->options; struct options *o = target->w->options;
struct options_entry *oe; struct options_entry *oe;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {

View File

@@ -884,13 +884,13 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
if (c->session != NULL) { if (c->session != NULL) {
cmd_find_clear_state(fs, flags); cmd_find_clear_state(fs, flags);
fs->wp = c->session->curw->window->active; fs->wl = active_get_effective_winlink(c, c->session);
fs->wp = fs->wl->window->active;
if (fs->wp == NULL) { if (fs->wp == NULL) {
cmd_find_from_session(fs, c->session, flags); cmd_find_from_session(fs, c->session, flags);
return (0); return (0);
} }
fs->s = c->session; fs->s = c->session;
fs->wl = fs->s->curw;
fs->w = fs->wl->window; fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
@@ -931,6 +931,57 @@ unknown_pane:
return (cmd_find_from_nothing(fs, flags)); return (cmd_find_from_nothing(fs, flags));
} }
/* Find state from mouse target. */
static int
cmd_find_target_from_mouse(struct cmd_find_state *fs, struct cmdq_item *item,
enum cmd_find_type type)
{
struct mouse_event *m = &cmdq_get_event(item)->m;
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item);
switch (type) {
case CMD_FIND_PANE:
if (m->s != -1 && m->w == -1 && m->wp == -1 &&
(fs->s = session_find_by_id(m->s)) != NULL) {
if (tc != NULL && tc->session == fs->s)
fs->wl = active_get_effective_winlink(tc, fs->s);
else if (c != NULL && c->session == fs->s)
fs->wl = active_get_effective_winlink(c, fs->s);
else
fs->wl = fs->s->curw;
if (fs->wl != NULL) {
fs->w = fs->wl->window;
fs->wp = fs->w->active;
break;
}
}
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp != NULL) {
fs->w = fs->wl->window;
break;
}
/* FALLTHROUGH */
case CMD_FIND_WINDOW:
case CMD_FIND_SESSION:
fs->wl = cmd_mouse_window(m, &fs->s);
if (fs->s != NULL && m->w == -1 &&
tc != NULL && tc->session == fs->s)
fs->wl = active_get_effective_winlink(tc, fs->s);
else if (fs->s != NULL && m->w == -1 &&
c != NULL && c->session == fs->s)
fs->wl = active_get_effective_winlink(c, fs->s);
if (fs->wl == NULL && fs->s != NULL)
fs->wl = fs->s->curw;
if (fs->wl != NULL) {
fs->w = fs->wl->window;
fs->wp = fs->w->active;
}
break;
}
return (fs->wp == NULL ? -1 : 0);
}
/* /*
* Split target into pieces and resolve for the given type. Fills in the given * Split target into pieces and resolve for the given type. Fills in the given
* state. Returns 0 on success or -1 on error. * state. Returns 0 on success or -1 on error.
@@ -939,7 +990,6 @@ int
cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
const char *target, enum cmd_find_type type, int flags) const char *target, enum cmd_find_type type, int flags)
{ {
struct mouse_event *m;
struct client *c; struct client *c;
struct cmd_find_state current; struct cmd_find_state current;
char *colon, *period, *copy = NULL, tmp[256]; char *colon, *period, *copy = NULL, tmp[256];
@@ -1015,35 +1065,15 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
cmdq_error(item, "no current client"); cmdq_error(item, "no current client");
goto error; goto error;
} }
fs->wl = c->session->curw; fs->wl = active_get_effective_winlink(c, c->session);
fs->wp = c->session->curw->window->active; fs->wp = fs->wl->window->active;
fs->w = c->session->curw->window; fs->w = fs->wl->window;
goto found; goto found;
} }
/* Mouse target is a plain = or {mouse}. */ /* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq_get_event(item)->m; if (cmd_find_target_from_mouse(fs, item, type) != 0) {
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp != NULL) {
fs->w = fs->wl->window;
break;
}
/* FALLTHROUGH */
case CMD_FIND_WINDOW:
case CMD_FIND_SESSION:
fs->wl = cmd_mouse_window(m, &fs->s);
if (fs->wl == NULL && fs->s != NULL)
fs->wl = fs->s->curw;
if (fs->wl != NULL) {
fs->w = fs->wl->window;
fs->wp = fs->w->active;
}
break;
}
if (fs->wp == NULL) {
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no mouse target"); cmdq_error(item, "no mouse target");
goto error; goto error;

View File

@@ -410,13 +410,16 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item); struct cmd_find_state *source = cmdq_get_source(item);
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item);
struct client *ac;
struct session *dst_s; struct session *dst_s;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp; struct window_pane *src_wp, *dst_wp;
const char *s; const char *s;
char *cause = NULL; char *cause = NULL;
int flags = 0, dst_idx; int flags = 0, dst_idx, local;
struct layout_cell *lc; struct layout_cell *lc;
dst_s = target->s; dst_s = target->s;
@@ -424,6 +427,10 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
dst_wp = target->wp; dst_wp = target->wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
ac = tc;
if (ac == NULL || ac->session != dst_s)
ac = c;
local = active_is_local_window(ac, dst_s);
if (cmd_get_entry(self) == &cmd_move_pane_entry) { if (cmd_get_entry(self) == &cmd_move_pane_entry) {
if (args_has(args, 'M')) if (args_has(args, 'M'))
@@ -511,9 +518,18 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp, 1); window_set_active_pane(dst_w, src_wp, 1);
session_select(dst_s, dst_idx); if (local)
cmd_find_from_session(current, dst_s, 0); active_select_window(ac, dst_s, dst_wl);
server_redraw_session(dst_s); else
session_select(dst_s, dst_idx);
if (local && ac != NULL && ac->session == dst_s)
cmd_find_from_client(current, ac, 0);
else
cmd_find_from_session(current, dst_s, 0);
if (local && ac != NULL && ac->session == dst_s)
server_redraw_client(ac);
else
server_redraw_session(dst_s);
} else } else
server_status_session(dst_s); server_status_session(dst_s);

View File

@@ -62,12 +62,15 @@ cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item); struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state target; struct cmd_find_state target;
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item);
struct client *ac;
const char *tflag = args_get(args, 't'); const char *tflag = args_get(args, 't');
struct session *src = source->s; struct session *src = source->s;
struct session *dst; struct session *dst;
struct winlink *wl = source->wl; struct winlink *wl = source->wl, *dstwl, *current_wl;
char *cause; char *cause;
int idx, kflag, dflag, sflag, before; int idx, kflag, dflag, sflag, before, local;
if (args_has(args, 'r')) { if (args_has(args, 'r')) {
if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION, if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION,
@@ -90,23 +93,37 @@ cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
dflag = args_has(args, 'd'); dflag = args_has(args, 'd');
sflag = args_has(args, 's'); sflag = args_has(args, 's');
ac = tc;
if (ac == NULL || ac->session != dst)
ac = c;
local = (!dflag && active_is_local_window(ac, dst));
before = args_has(args, 'b'); before = args_has(args, 'b');
if (args_has(args, 'a') || before) { if (args_has(args, 'a') || before) {
if (target.wl != NULL) if (target.wl != NULL)
idx = winlink_shuffle_up(dst, target.wl, before); idx = winlink_shuffle_up(dst, target.wl, before);
else else {
idx = winlink_shuffle_up(dst, dst->curw, before); current_wl = active_get_effective_winlink(ac, dst);
idx = winlink_shuffle_up(dst, current_wl, before);
}
if (idx == -1) if (idx == -1)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { if (server_link_window(src, wl, dst, idx, kflag, !dflag && !local,
&cause) != 0) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
dstwl = winlink_find_by_window(&dst->windows, wl->window);
if (cmd_get_entry(self) == &cmd_move_window_entry) if (cmd_get_entry(self) == &cmd_move_window_entry)
server_unlink_window(src, wl); server_unlink_window(src, wl);
if (local && dstwl != NULL) {
active_select_window(ac, dst, dstwl);
if (ac != NULL && ac->session == dst)
server_redraw_client(ac);
}
/* /*
* Renumber the winlinks in the src session only, the destination * Renumber the winlinks in the src session only, the destination

View File

@@ -58,9 +58,11 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc = { 0 }; struct spawn_context sc = { 0 };
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct client *ac;
struct session *s = target->s; struct session *s = target->s;
struct winlink *wl = target->wl, *new_wl = NULL; struct winlink *wl = target->wl, *new_wl = NULL;
int idx = target->idx, before, count = args_count(args); int idx = target->idx, before, count = args_count(args);
int detached, local;
char *cause = NULL, *cp, *expanded, *wname = NULL; char *cause = NULL, *cp, *expanded, *wname = NULL;
const char *template, *name; const char *template, *name;
struct cmd_find_state fs; struct cmd_find_state fs;
@@ -107,10 +109,15 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
free(wname); free(wname);
if (args_has(args, 'd')) if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (session_set_current(s, new_wl) == 0) if (active_select_window(c, s, new_wl) == 0) {
server_redraw_session(s); if (active_is_local_window(c, s) && c != NULL &&
c->session == s)
server_redraw_client(c);
else
server_redraw_session(s);
}
if (c != NULL && c->session != NULL) if (c != NULL && c->session != NULL)
s->curw->window->latest = c; active_get_effective_window(c, s)->latest = c;
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -140,10 +147,16 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
sc.idx = idx; sc.idx = idx;
sc.cwd = args_get(args, 'c'); sc.cwd = args_get(args, 'c');
ac = tc;
if (ac == NULL || ac->session != s)
ac = c;
detached = args_has(args, 'd');
local = (!detached && active_is_local_window(ac, s));
sc.flags = 0; sc.flags = 0;
if (args_has(args, 'E') || (count == 1 && *args_string(args, 0) == '\0')) if (args_has(args, 'E') || (count == 1 && *args_string(args, 0) == '\0'))
sc.flags |= SPAWN_EMPTY; sc.flags |= SPAWN_EMPTY;
if (args_has(args, 'd')) if (detached || local)
sc.flags |= SPAWN_DETACHED; sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'k')) if (args_has(args, 'k'))
sc.flags |= SPAWN_KILL; sc.flags |= SPAWN_KILL;
@@ -153,7 +166,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
goto fail; goto fail;
} }
if (!args_has(args, 'd') || new_wl == s->curw) { if (local) {
if (active_select_window(ac, s, new_wl) == 0)
cmd_find_from_winlink(current, new_wl, 0);
if (ac != NULL && ac->session == s)
server_redraw_client(ac);
server_status_session_group(s);
} else if (!detached || new_wl == s->curw) {
cmd_find_from_winlink(current, new_wl, 0); cmd_find_from_winlink(current, new_wl, 0);
server_redraw_session_group(s); server_redraw_session_group(s);
} else } else

View File

@@ -203,7 +203,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'c')) if (args_has(args, 'c'))
tc->pan_window = NULL; tc->pan_window = NULL;
else { else {
w = tc->session->curw->window; w = active_get_effective_window(tc, tc->session);
if (tc->pan_window != w) { if (tc->pan_window != w) {
tc->pan_window = w; tc->pan_window = w;
tc->pan_ox = tty->oox; tc->pan_ox = tty->oox;

View File

@@ -79,7 +79,10 @@ static void
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_print(struct job *job, const char *msg)
{ {
struct cmd_run_shell_data *cdata = job_get_data(job); struct cmd_run_shell_data *cdata = job_get_data(job);
struct client *c;
struct session *s;
struct window_pane *wp = NULL; struct window_pane *wp = NULL;
struct window *w;
struct cmd_find_state fs; struct cmd_find_state fs;
struct window_mode_entry *wme; struct window_mode_entry *wme;
@@ -90,8 +93,12 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg); cmdq_print(cdata->item, "%s", msg);
return; return;
} }
if (cdata->client != NULL && cdata->client->session != NULL) c = cdata->client;
wp = cdata->client->session->curw->window->active; if (c != NULL && c->session != NULL) {
s = c->session;
w = active_get_effective_window(c, s);
wp = w->active;
}
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0) if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
wp = fs.wp; wp = fs.wp;
if (wp == NULL) if (wp == NULL)

View File

@@ -68,10 +68,11 @@ cmd_select_pane_redraw(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (c->flags & CLIENT_CONTROL)) if (c->session == NULL || (c->flags & CLIENT_CONTROL))
continue; continue;
if (c->session->curw->window == w && tty_window_bigger(&c->tty)) if (active_get_effective_window(c, c->session) == w &&
tty_window_bigger(&c->tty))
server_redraw_client(c); server_redraw_client(c);
else { else {
if (c->session->curw->window == w) if (active_get_effective_window(c, c->session) == w)
c->flags |= CLIENT_REDRAWBORDERS; c->flags |= CLIENT_REDRAWBORDERS;
if (session_has(c->session, w)) if (session_has(c->session, w))
c->flags |= CLIENT_REDRAWSTATUS; c->flags |= CLIENT_REDRAWSTATUS;

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_window_entry = {
.name = "select-window", .name = "select-window",
.alias = "selectw", .alias = "selectw",
.args = { "lnpTt:", 0, 0, NULL }, .args = { "LlSnpTt:", 0, 0, NULL },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE, .usage = "[-LlnpST] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -88,8 +88,9 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
struct client *c = cmdq_get_client(item); struct client *c = cmdq_get_client(item);
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl; struct winlink *wl = target->wl, *current_wl;
struct session *s = target->s; struct session *s = target->s;
enum active_window_mode mode;
int next, previous, last, activity; int next, previous, last, activity;
next = (cmd_get_entry(self) == &cmd_next_window_entry); next = (cmd_get_entry(self) == &cmd_next_window_entry);
@@ -102,48 +103,104 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'l')) if (args_has(args, 'l'))
last = 1; last = 1;
if (args_has(args, 'L') || args_has(args, 'S')) {
if (c == NULL || c->session == NULL) {
cmdq_error(item, "no current client");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'S'))
mode = ACTIVE_SHARED;
else
mode = ACTIVE_LOCAL;
active_set_local_window(c, s, mode);
if (!next &&
!previous &&
!last &&
!args_has(args, 't') &&
!args_has(args, 'T')) {
if (current->s == s) {
if (c->session == s)
cmd_find_from_client(current, c, 0);
else
cmd_find_from_session(current, s, 0);
}
if (c->session == s)
server_redraw_client(c);
else
server_redraw_session(s);
cmdq_insert_hook(s, item, current, "after-select-window");
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
}
if (active_is_local_window(c, s))
mode = ACTIVE_LOCAL;
else
mode = ACTIVE_SHARED;
if (next || previous || last) { if (next || previous || last) {
activity = args_has(args, 'a'); activity = args_has(args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (active_next_window(c, s, activity) != 0) {
cmdq_error(item, "no next window"); cmdq_error(item, "no next window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (previous) { } else if (previous) {
if (session_previous(s, activity) != 0) { if (active_previous_window(c, s, activity) != 0) {
cmdq_error(item, "no previous window"); cmdq_error(item, "no previous window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (session_last(s) != 0) { if (active_last_window(c, s) != 0) {
cmdq_error(item, "no last window"); cmdq_error(item, "no last window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
cmd_find_from_session(current, s, 0); if (mode == ACTIVE_LOCAL && c != NULL && c->session == s)
server_redraw_session(s); cmd_find_from_client(current, c, 0);
else
cmd_find_from_session(current, s, 0);
if (mode == ACTIVE_LOCAL && c != NULL && c->session == s)
server_redraw_client(c);
else
server_redraw_session(s);
cmdq_insert_hook(s, item, current, "after-select-window"); cmdq_insert_hook(s, item, current, "after-select-window");
} else { } else {
/* /*
* If -T and select-window is invoked on same window as * If -T and select-window is invoked on same window as
* current, switch to previous window. * current, switch to previous window.
*/ */
if (args_has(args, 'T') && wl == s->curw) { current_wl = active_get_effective_winlink(c, s);
if (session_last(s) != 0) { if (args_has(args, 'T') && wl == current_wl) {
if (active_last_window(c, s) != 0) {
cmdq_error(item, "no last window"); cmdq_error(item, "no last window");
return (-1); return (-1);
} }
if (current->s == s) if (current->s == s) {
if (mode == ACTIVE_LOCAL && c != NULL &&
c->session == s)
cmd_find_from_client(current, c, 0);
else
cmd_find_from_session(current, s, 0);
}
if (mode == ACTIVE_LOCAL && c != NULL && c->session == s)
server_redraw_client(c);
else
server_redraw_session(s);
} else if (active_select_window(c, s, wl) == 0) {
if (mode == ACTIVE_LOCAL && c != NULL && c->session == s)
cmd_find_from_client(current, c, 0);
else
cmd_find_from_session(current, s, 0); cmd_find_from_session(current, s, 0);
server_redraw_session(s); if (mode == ACTIVE_LOCAL && c != NULL && c->session == s)
} else if (session_select(s, wl->idx) == 0) { server_redraw_client(c);
cmd_find_from_session(current, s, 0); else
server_redraw_session(s); server_redraw_session(s);
} }
cmdq_insert_hook(s, item, current, "after-select-window"); cmdq_insert_hook(s, item, current, "after-select-window");
} }
if (c != NULL && c->session != NULL) if (c != NULL && c->session != NULL)
s->curw->window->latest = c; active_get_effective_window(c, s)->latest = c;
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -48,10 +48,14 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item); struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item);
struct client *ac;
struct session *src = source->s, *dst = target->s; struct session *src = source->s, *dst = target->s;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src = source->wl, *wl_dst = target->wl; struct winlink *wl_src = source->wl, *wl_dst = target->wl;
struct window *w_src, *w_dst; struct window *w_src, *w_dst;
int local_src, local_dst;
sg_src = session_group_contains(src); sg_src = session_group_contains(src);
sg_dst = session_group_contains(dst); sg_dst = session_group_contains(dst);
@@ -79,10 +83,22 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
if (marked_pane.wl == wl_src) if (marked_pane.wl == wl_src)
marked_pane.wl = wl_dst; marked_pane.wl = wl_dst;
ac = tc;
if (ac == NULL)
ac = c;
local_dst = active_is_local_window(ac, dst);
local_src = active_is_local_window(ac, src);
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
session_select(dst, wl_dst->idx); if (local_dst)
if (src != dst) active_select_window(ac, dst, wl_dst);
session_select(src, wl_src->idx); else
session_select(dst, wl_dst->idx);
if (src != dst) {
if (local_src)
active_select_window(ac, src, wl_src);
else
session_select(src, wl_src->idx);
}
} }
session_group_synchronize_from(src); session_group_synchronize_from(src);
server_redraw_session_group(src); server_redraw_session_group(src);

View File

@@ -53,11 +53,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state target; struct cmd_find_state target;
const char *tflag = args_get(args, 't'); const char *tflag = args_get(args, 't');
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags, window_target;
struct client *c = cmdq_get_client(item); struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl, *current_wl;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
const char *tablename; const char *tablename;
@@ -65,8 +65,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
struct sort_criteria sort_crit; struct sort_criteria sort_crit;
uid_t uid; uid_t uid;
if (tflag != NULL && window_target = 0;
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) { if (tflag != NULL) {
if (tflag[strcspn(tflag, ":.%")] != '\0' ||
strcmp(tflag, "=") == 0)
window_target = 1;
}
if (window_target) {
type = CMD_FIND_PANE; type = CMD_FIND_PANE;
flags = 0; flags = 0;
} else { } else {
@@ -137,7 +142,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} else { } else {
if (cmdq_get_client(item) == NULL) if (cmdq_get_client(item) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) { if (window_target && wl != NULL && wp != NULL &&
wp != wl->window->active) {
w = wl->window; w = wl->window;
if (window_push_zoom(w, 0, args_has(args, 'Z'))) if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
@@ -146,9 +152,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (window_pop_zoom(w)) if (window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);
} }
if (wl != NULL) { if (window_target && wl != NULL) {
session_set_current(s, wl); active_select_window(tc, s, wl);
cmd_find_from_session(current, s, 0); if (active_is_local_window(tc, s)) {
current_wl = active_get_effective_winlink(tc, s);
cmd_find_from_winlink(current, current_wl, 0);
} else
cmd_find_from_session(current, s, 0);
} }
} }

View File

@@ -215,6 +215,28 @@ control_client_session_changed_cb(__unused const char *name,
} }
} }
/* Notify control clients that a client changed its effective window. */
static void
control_client_window_changed_cb(__unused const char *name,
struct event_payload *ep, __unused void *sink_data)
{
struct client *cc = event_payload_get_client(ep, "client");
struct session *s = event_payload_get_session(ep, "session");
struct window *w = event_payload_get_window(ep, "window");
struct client *c;
if (cc == NULL || s == NULL || w == NULL)
return;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%client-window-changed %s $%u @%u",
cc->name, s->id, w->id);
}
}
/* Notify control clients that a client detached. */ /* Notify control clients that a client detached. */
static void static void
control_client_detached_cb(__unused const char *name, struct event_payload *ep, control_client_detached_cb(__unused const char *name, struct event_payload *ep,
@@ -356,6 +378,7 @@ control_build_events(void)
{ "window-linked", control_window_linked_cb }, { "window-linked", control_window_linked_cb },
{ "window-renamed", control_window_renamed_cb }, { "window-renamed", control_window_renamed_cb },
{ "client-session-changed", control_client_session_changed_cb }, { "client-session-changed", control_client_session_changed_cb },
{ "client-window-changed", control_client_window_changed_cb },
{ "client-detached", control_client_detached_cb }, { "client-detached", control_client_detached_cb },
{ "session-renamed", control_session_renamed_cb }, { "session-renamed", control_session_renamed_cb },
{ "session-created", control_session_created_cb }, { "session-created", control_session_created_cb },

View File

@@ -800,7 +800,7 @@ format_cb_window_active_clients(struct format_tree *ft)
if (client_session == NULL) if (client_session == NULL)
continue; continue;
if (w == client_session->curw->window) if (w == active_get_effective_window(loop, client_session))
n++; n++;
} }
@@ -832,7 +832,7 @@ format_cb_window_active_clients_list(struct format_tree *ft)
if (client_session == NULL) if (client_session == NULL)
continue; continue;
if (w == client_session->curw->window) { if (w == active_get_effective_window(loop, client_session)) {
if (EVBUFFER_LENGTH(buffer) > 0) if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1); evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name); evbuffer_add_printf(buffer, "%s", loop->name);
@@ -2886,11 +2886,48 @@ format_cb_sixel_support(__unused struct format_tree *ft)
static void * static void *
format_cb_active_window_index(struct format_tree *ft) format_cb_active_window_index(struct format_tree *ft)
{ {
if (ft->s != NULL) struct winlink *wl;
return (format_printf("%u", ft->s->curw->idx));
if (ft->s != NULL) {
wl = active_get_effective_winlink(ft->c, ft->s);
if (wl != NULL)
return (format_printf("%u", wl->idx));
}
return (NULL); return (NULL);
} }
/* Callback for active_window_id. */
static void *
format_cb_active_window_id(struct format_tree *ft)
{
struct winlink *wl;
if (ft->s != NULL) {
wl = active_get_effective_winlink(ft->c, ft->s);
if (wl != NULL)
return (format_printf("@%u", wl->window->id));
}
return (NULL);
}
/* Callback for local_active_window. */
static void *
format_cb_local_active_window(struct format_tree *ft)
{
if (ft->c != NULL && ft->s != NULL)
return (format_printf("%d", active_is_local_window(ft->c, ft->s)));
return (xstrdup("0"));
}
/* Callback for active_window_mode. */
static void *
format_cb_active_window_mode(struct format_tree *ft)
{
if (ft->c != NULL && ft->s != NULL && active_is_local_window(ft->c, ft->s))
return (xstrdup("local"));
return (xstrdup("shared"));
}
/* Callback for last_window_index. */ /* Callback for last_window_index. */
static void * static void *
format_cb_last_window_index(struct format_tree *ft) format_cb_last_window_index(struct format_tree *ft)
@@ -2908,8 +2945,11 @@ format_cb_last_window_index(struct format_tree *ft)
static void * static void *
format_cb_window_active(struct format_tree *ft) format_cb_window_active(struct format_tree *ft)
{ {
struct winlink *wl;
if (ft->wl != NULL) { if (ft->wl != NULL) {
if (ft->wl == ft->wl->session->curw) wl = active_get_effective_winlink(ft->c, ft->wl->session);
if (ft->wl == wl)
return (xstrdup("1")); return (xstrdup("1"));
return (xstrdup("0")); return (xstrdup("0"));
} }
@@ -2989,7 +3029,7 @@ static void *
format_cb_window_flags(struct format_tree *ft) format_cb_window_flags(struct format_tree *ft)
{ {
if (ft->wl != NULL) if (ft->wl != NULL)
return (xstrdup(window_printable_flags(ft->wl, 1))); return (xstrdup(window_printable_flags(ft->c, ft->wl, 1)));
return (NULL); return (NULL);
} }
@@ -3176,7 +3216,7 @@ static void *
format_cb_window_raw_flags(struct format_tree *ft) format_cb_window_raw_flags(struct format_tree *ft)
{ {
if (ft->wl != NULL) if (ft->wl != NULL)
return (xstrdup(window_printable_flags(ft->wl, 0))); return (xstrdup(window_printable_flags(ft->c, ft->wl, 0)));
return (NULL); return (NULL);
} }
@@ -3386,9 +3426,15 @@ struct format_table_entry {
* Only variables which are added by the caller go into the tree. * Only variables which are added by the caller go into the tree.
*/ */
static const struct format_table_entry format_table[] = { static const struct format_table_entry format_table[] = {
{ "active_window_id", FORMAT_TABLE_STRING,
format_cb_active_window_id
},
{ "active_window_index", FORMAT_TABLE_STRING, { "active_window_index", FORMAT_TABLE_STRING,
format_cb_active_window_index format_cb_active_window_index
}, },
{ "active_window_mode", FORMAT_TABLE_STRING,
format_cb_active_window_mode
},
{ "alternate_on", FORMAT_TABLE_STRING, { "alternate_on", FORMAT_TABLE_STRING,
format_cb_alternate_on format_cb_alternate_on
}, },
@@ -3557,6 +3603,9 @@ static const struct format_table_entry format_table[] = {
{ "last_window_index", FORMAT_TABLE_STRING, { "last_window_index", FORMAT_TABLE_STRING,
format_cb_last_window_index format_cb_last_window_index
}, },
{ "local_active_window", FORMAT_TABLE_STRING,
format_cb_local_active_window
},
{ "mouse_all_flag", FORMAT_TABLE_STRING, { "mouse_all_flag", FORMAT_TABLE_STRING,
format_cb_mouse_all_flag format_cb_mouse_all_flag
}, },
@@ -5092,15 +5141,18 @@ format_add_window_neighbour(struct format_tree *nft, struct winlink *wl,
struct session *s, const char *prefix) struct session *s, const char *prefix)
{ {
struct options_entry *o; struct options_entry *o;
struct winlink *current;
const char *oname; const char *oname;
char *key, *prefixed, *oval; char *key, *prefixed, *oval;
current = active_get_effective_winlink(nft->c, s);
xasprintf(&key, "%s_window_index", prefix); xasprintf(&key, "%s_window_index", prefix);
format_add(nft, key, "%u", wl->idx); format_add(nft, key, "%u", wl->idx);
free(key); free(key);
xasprintf(&key, "%s_window_active", prefix); xasprintf(&key, "%s_window_active", prefix);
format_add(nft, key, "%d", wl == s->curw); format_add(nft, key, "%d", wl == current);
free(key); free(key);
o = options_first(wl->window->options); o = options_first(wl->window->options);
@@ -5128,10 +5180,10 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
struct cmdq_item *item = ft->item; struct cmdq_item *item = ft->item;
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *all, *active, *use, *expanded, *value; char *all, *active_fmt, *use, *expanded, *value;
struct evbuffer *buffer; struct evbuffer *buffer;
size_t size; size_t size;
struct winlink *wl, **l; struct winlink *wl, **l, *active_wl;
struct window *w; struct window *w;
int i, n; int i, n;
@@ -5140,9 +5192,9 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
return (NULL); return (NULL);
} }
if (format_choose(es, fmt, &all, &active, 0) != 0) { if (format_choose(es, fmt, &all, &active_fmt, 0) != 0) {
all = xstrdup(fmt); all = xstrdup(fmt);
active = NULL; active_fmt = NULL;
} }
buffer = evbuffer_new(); buffer = evbuffer_new();
@@ -5150,12 +5202,13 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
fatalx("out of memory"); fatalx("out of memory");
l = sort_get_winlinks_session(s, &n, sc); l = sort_get_winlinks_session(s, &n, sc);
active_wl = active_get_effective_winlink(ft->c, s);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
wl = l[i]; wl = l[i];
w = wl->window; w = wl->window;
format_log(es, "window loop: %u @%u", wl->idx, w->id); format_log(es, "window loop: %u @%u", wl->idx, w->id);
if (active != NULL && wl == s->curw) if (active_fmt != NULL && wl == active_wl)
use = active; use = active_fmt;
else else
use = all; use = all;
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags); nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
@@ -5164,11 +5217,11 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
format_add(nft, "loop_last_flag", "%d", i == n - 1); format_add(nft, "loop_last_flag", "%d", i == n - 1);
/* Add neighbour window data to the format tree. */ /* Add neighbour window data to the format tree. */
if (i > 0 && l[i - 1] == s->curw) if (i > 0 && l[i - 1] == active_wl)
format_add(nft, "window_after_active", "1"); format_add(nft, "window_after_active", "1");
else else
format_add(nft, "window_after_active", "0"); format_add(nft, "window_after_active", "0");
if (i + 1 < n && l[i + 1] == s->curw) if (i + 1 < n && l[i + 1] == active_wl)
format_add(nft, "window_before_active", "1"); format_add(nft, "window_before_active", "1");
else else
format_add(nft, "window_before_active", "0"); format_add(nft, "window_before_active", "0");
@@ -5188,7 +5241,7 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
free(expanded); free(expanded);
} }
free(active); free(active_fmt);
free(all); free(all);
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
@@ -6691,7 +6744,7 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
if (s == NULL && c != NULL) if (s == NULL && c != NULL)
s = c->session; s = c->session;
if (wl == NULL && s != NULL) if (wl == NULL && s != NULL)
wl = s->curw; wl = active_get_effective_winlink(c, s);
if (wp == NULL && wl != NULL) if (wp == NULL && wl != NULL)
wp = wl->window->active; wp = wl->window->active;

View File

@@ -31,6 +31,8 @@
" 'Rename' 'r' {command-prompt -I '#S' {rename-session -- '%%'}}" \ " 'Rename' 'r' {command-prompt -I '#S' {rename-session -- '%%'}}" \
" 'Detach' 'd' {detach-client}" \ " 'Detach' 'd' {detach-client}" \
" ''" \ " ''" \
" '#{?local_active_window,Shared Window,Local Window}' 'L' {select-window #{?local_active_window,-S,-L}}" \
" ''" \
" 'New Session' 's' {new-session}" \ " 'New Session' 's' {new-session}" \
" 'New Window' 'w' {new-window}" " 'New Window' 'w' {new-window}"
#define DEFAULT_WINDOW_MENU \ #define DEFAULT_WINDOW_MENU \

2
menu.c
View File

@@ -584,7 +584,7 @@ menu_display(struct menu *menu, int flags, int starting_choice,
struct options *o; struct options *o;
if (fs == NULL) if (fs == NULL)
w = c->session->curw->window; w = active_get_effective_window(c, c->session);
else else
w = fs->w; w = fs->w;
o = w->options; o = w->options;

View File

@@ -1115,7 +1115,8 @@ const struct options_table_entry options_table[] = {
{ .name = "status-style", { .name = "status-style",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=themegreen,fg=themeblack", .default_str = "bg=#{?local_active_window,themeblue,themegreen},"
"fg=themeblack",
.flags = OPTIONS_TABLE_IS_STYLE, .flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",", .separator = ",",
.text = "Style of the status line." .text = "Style of the status line."
@@ -1960,6 +1961,8 @@ const struct options_table_entry options_table[] = {
"Run when a client is resized."), "Run when a client is resized."),
OPTIONS_TABLE_HOOK("client-session-changed", "", OPTIONS_TABLE_HOOK("client-session-changed", "",
"Run when a client's attached session is changed."), "Run when a client's attached session is changed."),
OPTIONS_TABLE_HOOK("client-window-changed", "",
"Run when a client's effective window is changed."),
OPTIONS_TABLE_HOOK("client-light-theme", "", OPTIONS_TABLE_HOOK("client-light-theme", "",
"Run when a client switches to a light theme."), "Run when a client switches to a light theme."),
OPTIONS_TABLE_HOOK("client-dark-theme", "", OPTIONS_TABLE_HOOK("client-dark-theme", "",

View File

@@ -102,9 +102,9 @@ popup_reapply_styles(struct popup_data *pd)
if (s == NULL) if (s == NULL)
return; return;
o = s->curw->window->options; o = active_get_effective_window(c, s)->options;
ft = format_create_defaults(NULL, c, s, s->curw, NULL); ft = format_create_defaults(NULL, c, s, NULL, NULL);
/* Reapply popup style from options. */ /* Reapply popup style from options. */
memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults); memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults);
@@ -569,9 +569,9 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
struct style sytmp; struct style sytmp;
if (s != NULL) if (s != NULL)
o = s->curw->window->options; o = active_get_effective_window(c, s)->options;
else else
o = c->session->curw->window->options; o = active_get_effective_window(c, c->session)->options;
if (lines == BOX_LINES_DEFAULT) if (lines == BOX_LINES_DEFAULT)
lines = options_get_number(o, "popup-border-lines"); lines = options_get_number(o, "popup-border-lines");

151
regress/active-window.sh Normal file
View File

@@ -0,0 +1,151 @@
#!/bin/sh
PATH=/bin:/usr/bin
TERM=screen
LC_ALL=C.UTF-8
LANG=C.UTF-8
export TERM LC_ALL LANG
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
TMPDIR=$(mktemp -d)
IN1="$TMPDIR/in1"
IN2="$TMPDIR/in2"
OUT1="$TMPDIR/out1"
OUT2="$TMPDIR/out2"
PID1=
PID2=
cleanup()
{
[ -n "$PID1" ] && kill "$PID1" 2>/dev/null
[ -n "$PID2" ] && kill "$PID2" 2>/dev/null
$TMUX kill-server 2>/dev/null
rm -rf "$TMPDIR"
}
trap cleanup EXIT
fail()
{
echo "$1"
echo "client1:"
cat "$OUT1" 2>/dev/null
echo "client2:"
cat "$OUT2" 2>/dev/null
exit 1
}
wait_for()
{
file=$1
pattern=$2
i=0
while [ "$i" -lt 60 ]; do
if grep -F -- "$pattern" "$file" >/dev/null 2>&1; then
return 0
fi
sleep 0.1
i=$((i + 1))
done
fail "missing '$pattern' in $file"
}
send1()
{
printf '%s\n' "$*" >&3
}
send2()
{
printf '%s\n' "$*" >&4
}
check_server()
{
out=$($TMUX display-message -p -t "$1" "$2")
[ "$out" = "$3" ] || fail "expected '$3' for $1 $2, got '$out'"
}
$TMUX kill-server 2>/dev/null
$TMUX new-session -d -s aw -x 80 -y 24 -n w0 || exit 1
$TMUX new-window -d -t aw: -n w1 || exit 1
$TMUX new-window -d -t aw: -n w2 || exit 1
$TMUX new-session -d -s aw2 -x 80 -y 24 -n x0 || exit 1
$TMUX new-window -d -t aw2: -n x1 || exit 1
mkfifo "$IN1" "$IN2" || exit 1
: >"$OUT1"
: >"$OUT2"
$TMUX -C attach-session -t aw <"$IN1" >"$OUT1" 2>&1 &
PID1=$!
$TMUX -C attach-session -t aw <"$IN2" >"$OUT2" 2>&1 &
PID2=$!
exec 3>"$IN1"
exec 4>"$IN2"
send1 'display-message -p C1READY'
send2 'display-message -p C2READY'
wait_for "$OUT1" C1READY
wait_for "$OUT2" C2READY
# Default shared selection: client 1 changes session current, client 2 follows.
send1 'display-message -p "C1A #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT1" 'C1A 0 0 0'
send1 'select-window -t :1'
wait_for "$OUT2" '%session-window-changed $0 @1'
send2 'display-message -p "C2A #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT2" 'C2A 1 0 1'
check_server 'aw:' '#{window_index}' '1'
# Local selection changes only client 1 and becomes the default command target.
send1 'select-window -L'
send1 'select-window -t :2'
send1 'display-message -p "C1B #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT1" 'C1B 2 1 2'
send2 'display-message -p "C2B #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT2" 'C2B 1 0 1'
check_server 'aw:' '#{window_index}' '1'
# Local last-window history is independent of the session shared stack.
send1 'last-window'
send1 'display-message -p "C1C #{active_window_index} #{window_index}"'
wait_for "$OUT1" 'C1C 1 1'
send1 'next-window'
send1 'display-message -p "C1D #{active_window_index} #{window_index}"'
wait_for "$OUT1" 'C1D 2 2'
check_server 'aw:' '#{window_index}' '1'
# Session switches preserve per-session local selections.
send1 'switch-client -t aw2'
send1 'select-window -L'
send1 'select-window -t :1'
send1 'display-message -p "C1E #{session_name} #{active_window_index} #{local_active_window}"'
wait_for "$OUT1" 'C1E aw2 1 1'
send1 'switch-client -t aw'
send1 'display-message -p "C1F #{session_name} #{active_window_index} #{local_active_window}"'
wait_for "$OUT1" 'C1F aw 2 1'
# Returning to shared mode immediately follows the session current window.
send1 'select-window -S'
send1 'display-message -p "C1G #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT1" 'C1G 1 0 1'
# Invalid local windows recover to a valid session window without changing curw.
send1 'select-window -L'
send1 'select-window -t :2'
$TMUX kill-window -t aw:2 || fail 'kill-window failed'
send1 'display-message -p "C1H #{active_window_index} #{local_active_window} #{window_index}"'
wait_for "$OUT1" 'C1H 1 1 1'
check_server 'aw:' '#{window_index}' '1'
# Creating a window without -d in local mode selects it locally only.
send1 'new-window -n w3'
send1 'display-message -p "C1I #{local_active_window} #{window_name}"'
wait_for "$OUT1" 'C1I 1 w3'
send2 'display-message -p "C2C #{local_active_window} #{window_name}"'
wait_for "$OUT2" 'C2C 0 w1'
check_server 'aw:' '#{window_name}' 'w1'
exit 0

View File

@@ -348,10 +348,10 @@ recalculate_size_skip_client(struct client *loop, __unused int type,
* is not the current window - this is used for aggressive-resize. * is not the current window - this is used for aggressive-resize.
* Otherwise skip any session that doesn't contain the window. * Otherwise skip any session that doesn't contain the window.
*/ */
if (loop->session->curw == NULL) if (active_get_effective_window(loop, loop->session) == NULL)
return (1); return (1);
if (current) if (current)
return (loop->session->curw->window != w); return (active_get_effective_window(loop, loop->session) != w);
return (session_has(loop->session, w) == 0); return (session_has(loop->session, w) == 0);
} }

View File

@@ -295,7 +295,7 @@ static void
redraw_set_context(struct client *c, struct redraw_build_ctx *bctx) redraw_set_context(struct client *c, struct redraw_build_ctx *bctx)
{ {
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
memset(bctx, 0, sizeof *bctx); memset(bctx, 0, sizeof *bctx);
bctx->c = c; bctx->c = c;
@@ -966,7 +966,7 @@ static struct redraw_scene *
redraw_make_scene(struct client *c) redraw_make_scene(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
struct redraw_build_ctx bctx; struct redraw_build_ctx bctx;
struct redraw_scene *scene; struct redraw_scene *scene;
struct redraw_build_cell *bc, *last; struct redraw_build_cell *bc, *last;
@@ -1076,7 +1076,7 @@ static struct redraw_scene *
redraw_get_scene(struct client *c) redraw_get_scene(struct client *c)
{ {
struct redraw_scene *scene = c->redraw_scene; struct redraw_scene *scene = c->redraw_scene;
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
const char *reason = NULL; const char *reason = NULL;
u_int ox, oy, sx, sy; u_int ox, oy, sx, sy;
@@ -1137,7 +1137,7 @@ redraw_get_default_border_style(struct redraw_draw_ctx *dctx,
struct grid_cell *dgc = &dctx->default_gc; struct grid_cell *dgc = &dctx->default_gc;
if (~dctx->flags & REDRAW_DEFAULT_SET) { if (~dctx->flags & REDRAW_DEFAULT_SET) {
ft = format_create_defaults(NULL, c, s, s->curw, NULL); ft = format_create_defaults(NULL, c, s, NULL, NULL);
memcpy(dgc, &grid_default_cell, sizeof *dgc); memcpy(dgc, &grid_default_cell, sizeof *dgc);
style_add(dgc, oo, "pane-border-style", ft); style_add(dgc, oo, "pane-border-style", ft);
format_free(ft); format_free(ft);
@@ -1592,14 +1592,16 @@ redraw_set_draw_context(struct redraw_draw_ctx *dctx,
struct session *s = c->session; struct session *s = c->session;
struct options *oo = s->options; struct options *oo = s->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct winlink *wl;
u_int lines; u_int lines;
memset(dctx, 0, sizeof *dctx); memset(dctx, 0, sizeof *dctx);
dctx->scene = scene; dctx->scene = scene;
if (server_is_marked(s, s->curw, marked_pane.wp)) wl = active_get_effective_winlink(c, s);
if (server_is_marked(s, wl, marked_pane.wp))
dctx->marked = marked_pane.wp; dctx->marked = marked_pane.wp;
dctx->active = s->curw->window->active; dctx->active = active_get_effective_window(c, s)->active;
lines = status_line_size(c); lines = status_line_size(c);
if (options_get_number(oo, "status-position") == 0) if (options_get_number(oo, "status-position") == 0)
@@ -1672,7 +1674,7 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
{ {
struct redraw_draw_ctx dctx; struct redraw_draw_ctx dctx;
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct screen *sl; struct screen *sl;
struct redraw_scene *scene; struct redraw_scene *scene;
@@ -1872,7 +1874,7 @@ redraw_screen(struct client *c)
flags |= REDRAW_OVERLAY; flags |= REDRAW_OVERLAY;
if (c->flags & CLIENT_REDRAWMENU) if (c->flags & CLIENT_REDRAWMENU)
flags |= REDRAW_MENU; flags |= REDRAW_MENU;
if (c->session->curw->window->menu != NULL) if (active_get_effective_window(c, c->session)->menu != NULL)
flags |= REDRAW_MENU; flags |= REDRAW_MENU;
if (flags != 0) if (flags != 0)
redraw_draw(c, NULL, flags); redraw_draw(c, NULL, flags);
@@ -1884,7 +1886,7 @@ void
redraw_pane(struct client *c, struct window_pane *wp) redraw_pane(struct client *c, struct window_pane *wp)
{ {
redraw_draw(c, wp, REDRAW_PANE|REDRAW_PANE_SCROLLBAR); redraw_draw(c, wp, REDRAW_PANE|REDRAW_PANE_SCROLLBAR);
if (c->session->curw->window->menu != NULL) if (active_get_effective_window(c, c->session)->menu != NULL)
redraw_draw(c, NULL, REDRAW_MENU); redraw_draw(c, NULL, REDRAW_MENU);
} }

View File

@@ -142,7 +142,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
return (0); return (0);
} }
if (c->session->curw->window != wp->window) if (active_get_effective_window(c, c->session) != wp->window)
return (0); return (0);
if (wp->layout_cell == NULL) if (wp->layout_cell == NULL)
return (0); return (0);

View File

@@ -105,7 +105,7 @@ server_client_set_overlay(struct client *c, u_int delay,
c->tty.flags |= TTY_FREEZE; c->tty.flags |= TTY_FREEZE;
if (c->overlay_mode == NULL) if (c->overlay_mode == NULL)
c->tty.flags |= TTY_NOCURSOR; c->tty.flags |= TTY_NOCURSOR;
window_update_focus(c->session->curw->window); window_update_focus(active_get_effective_window(c, c->session));
server_redraw_client(c); server_redraw_client(c);
} }
@@ -132,7 +132,7 @@ server_client_clear_overlay(struct client *c)
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR); c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
if (c->session != NULL) if (c->session != NULL)
window_update_focus(c->session->curw->window); window_update_focus(active_get_effective_window(c, c->session));
server_redraw_client(c); server_redraw_client(c);
} }
@@ -376,7 +376,8 @@ server_client_attached_lost(struct client *c)
found = NULL; found = NULL;
TAILQ_FOREACH(loop, &clients, entry) { TAILQ_FOREACH(loop, &clients, entry) {
s = loop->session; s = loop->session;
if (loop == c || s == NULL || s->curw->window != w) if (loop == c || s == NULL ||
active_get_effective_window(loop, s) != w)
continue; continue;
if (found == NULL || timercmp(&loop->activity_time, if (found == NULL || timercmp(&loop->activity_time,
&found->activity_time, >)) &found->activity_time, >))
@@ -457,15 +458,15 @@ server_client_set_session(struct client *c, struct session *s)
c->flags |= CLIENT_FOCUSED; c->flags |= CLIENT_FOCUSED;
if (old != NULL && old->curw != NULL) if (old != NULL && old->curw != NULL)
window_update_focus(old->curw->window); window_update_focus(active_get_effective_window(c, old));
if (s != NULL) { if (s != NULL) {
s->curw->window->latest = c; active_get_effective_window(c, s)->latest = c;
recalculate_sizes(); recalculate_sizes();
window_update_focus(s->curw->window); window_update_focus(active_get_effective_window(c, s));
session_update_activity(s, NULL); session_update_activity(s, NULL);
session_theme_changed(s); session_theme_changed(s);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
s->curw->flags &= ~WINLINK_ALERTFLAGS; active_get_effective_winlink(c, s)->flags &= ~WINLINK_ALERTFLAGS;
alerts_check_session(s); alerts_check_session(s);
tty_update_client_offset(c); tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
@@ -490,6 +491,7 @@ server_client_lost(struct client *c)
server_client_clear_overlay(c); server_client_clear_overlay(c);
status_prompt_clear(c); status_prompt_clear(c);
status_message_clear(c); status_message_clear(c);
active_remove_client(c);
RB_FOREACH_SAFE(cf, client_files, &c->files, cf1) { RB_FOREACH_SAFE(cf, client_files, &c->files, cf1) {
cf->error = EINTR; cf->error = EINTR;
@@ -675,7 +677,7 @@ server_client_in_scrollbar_area(struct window_pane *wp, int px, int py)
static void static void
server_client_update_scrollbar_hover(struct client *c, int type, int px, int py) server_client_update_scrollbar_hover(struct client *c, int type, int px, int py)
{ {
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
struct window_pane *wp; struct window_pane *wp;
if (type != KEYC_TYPE_MOUSEMOVE) if (type != KEYC_TYPE_MOUSEMOVE)
@@ -848,7 +850,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
{ {
struct mouse_event *m = &event->m; struct mouse_event *m = &event->m;
struct session *s = c->session, *fs; struct session *s = c->session, *fs;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
struct winlink *fwl; struct winlink *fwl;
struct window_pane *wp, *fwp, *lwp = NULL; struct window_pane *wp, *fwp, *lwp = NULL;
u_int x, y, sx, sy, px, py, n, sl_mpos = 0; u_int x, y, sx, sy, px, py, n, sl_mpos = 0;
@@ -1346,7 +1348,7 @@ server_client_update_latest(struct client *c)
if (c->session == NULL) if (c->session == NULL)
return; return;
w = c->session->curw->window; w = active_get_effective_window(c, c->session);
if (w->latest == c) if (w->latest == c)
return; return;
@@ -1410,7 +1412,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
goto out; goto out;
wl = s->curw; wl = active_get_effective_winlink(c, s);
/* Update the activity timer. */ /* Update the activity timer. */
memcpy(&c->last_activity_time, &c->activity_time, memcpy(&c->last_activity_time, &c->activity_time,
@@ -1664,7 +1666,7 @@ out:
static int static int
server_client_handle_menu_key(struct client *c, struct key_event *event) server_client_handle_menu_key(struct client *c, struct key_event *event)
{ {
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
struct key_event new_event; struct key_event new_event;
struct mouse_event *m; struct mouse_event *m;
u_int ox, oy, sx, sy; u_int ox, oy, sx, sy;
@@ -1701,6 +1703,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
{ {
struct session *s = c->session; struct session *s = c->session;
struct cmdq_item *item; struct cmdq_item *item;
struct window *w;
struct window_pane *wp; struct window_pane *wp;
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
@@ -1756,9 +1759,10 @@ server_client_handle_key0(struct client *c, struct key_event *event,
} }
} }
wp = s->curw->window->active; w = active_get_effective_window(c, s);
wp = w->active;
if (wp == NULL || !window_pane_has_prompt(wp)) { if (wp == NULL || !window_pane_has_prompt(wp)) {
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (window_pane_has_prompt(wp) && if (window_pane_has_prompt(wp) &&
window_pane_is_visible(wp)) window_pane_is_visible(wp))
break; break;
@@ -2100,7 +2104,7 @@ static void
server_client_reset_state(struct client *c) server_client_reset_state(struct client *c)
{ {
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
struct window_pane *wp = w->active, *loop; struct window_pane *wp = w->active, *loop;
struct screen *s = NULL; struct screen *s = NULL;
struct options *oo = c->session->options; struct options *oo = c->session->options;
@@ -2341,7 +2345,7 @@ server_client_redraw_timer(__unused int fd, __unused short events,
static void static void
server_client_check_modes(struct client *c) server_client_check_modes(struct client *c)
{ {
struct window *w = c->session->curw->window; struct window *w;
struct window_pane *wp; struct window_pane *wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
@@ -2349,6 +2353,7 @@ server_client_check_modes(struct client *c)
return; return;
if (~c->flags & CLIENT_REDRAWSTATUS) if (~c->flags & CLIENT_REDRAWSTATUS)
return; return;
w = active_get_effective_window(c, c->session);
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->update != NULL) if (wme != NULL && wme->mode->update != NULL)
@@ -2361,7 +2366,7 @@ static int
server_client_any_pane_redraw(struct client *c) server_client_any_pane_redraw(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
struct window_pane *wp; struct window_pane *wp;
if (c->flags & CLIENT_REDRAWWINDOW) if (c->flags & CLIENT_REDRAWWINDOW)
@@ -2379,7 +2384,7 @@ server_client_check_redraw(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window *w = s->curw->window; struct window *w = active_get_effective_window(c, s);
struct window_pane *wp; struct window_pane *wp;
int needed, tflags, mode = tty->mode; int needed, tflags, mode = tty->mode;
struct timeval tv = { .tv_usec = 1000 }; struct timeval tv = { .tv_usec = 1000 };
@@ -2510,14 +2515,15 @@ static void
server_client_set_path(struct client *c) server_client_set_path(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct window *w = active_get_effective_window(c, s);
const char *path; const char *path;
if (s->curw == NULL || s->curw->window->active == NULL) if (w == NULL || w->active == NULL)
return; return;
if (s->curw->window->active->base.path == NULL) if (w->active->base.path == NULL)
path = ""; path = "";
else else
path = s->curw->window->active->base.path; path = w->active->base.path;
if (c->path == NULL || strcmp(path, c->path) != 0) { if (c->path == NULL || strcmp(path, c->path) != 0) {
free(c->path); free(c->path);
c->path = xstrdup(path); c->path = xstrdup(path);
@@ -2530,11 +2536,12 @@ static void
server_client_set_progress_bar(struct client *c) server_client_set_progress_bar(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct window *w = active_get_effective_window(c, s);
struct progress_bar *pane_pb; struct progress_bar *pane_pb;
if (s->curw == NULL || s->curw->window->active == NULL) if (w == NULL || w->active == NULL)
return; return;
pane_pb = &s->curw->window->active->base.progress_bar; pane_pb = &w->active->base.progress_bar;
if (pane_pb->state == c->progress_bar.state && if (pane_pb->state == c->progress_bar.state &&
pane_pb->progress == c->progress_bar.progress) pane_pb->progress == c->progress_bar.progress)
return; return;
@@ -3120,7 +3127,7 @@ server_client_print(struct client *c, int parse, struct evbuffer *evb)
goto out; goto out;
} }
wp = c->session->curw->window->active; wp = active_get_effective_window(c, c->session)->active;
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL, window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL,

View File

@@ -122,8 +122,7 @@ server_redraw_window(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && if (c->session != NULL &&
c->session->curw != NULL && active_get_effective_window(c, c->session) == w)
c->session->curw->window == w)
server_redraw_client(c); server_redraw_client(c);
} }
} }
@@ -135,8 +134,7 @@ server_redraw_window_menu(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && if (c->session != NULL &&
c->session->curw != NULL && active_get_effective_window(c, c->session) == w)
c->session->curw->window == w)
c->flags |= CLIENT_REDRAWMENU; c->flags |= CLIENT_REDRAWMENU;
} }
} }
@@ -148,8 +146,7 @@ server_redraw_window_borders(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && if (c->session != NULL &&
c->session->curw != NULL && active_get_effective_window(c, c->session) == w)
c->session->curw->window == w)
c->flags |= CLIENT_REDRAWBORDERS; c->flags |= CLIENT_REDRAWBORDERS;
} }
} }

View File

@@ -203,6 +203,7 @@ session_destroy(struct session *s, int notify, const char *from)
if (s->curw == NULL) if (s->curw == NULL)
return; return;
s->curw = NULL; s->curw = NULL;
active_remove_session(s);
RB_REMOVE(sessions, &sessions, s); RB_REMOVE(sessions, &sessions, s);
if (notify) if (notify)

19
tmux.1
View File

@@ -4026,12 +4026,22 @@ and
.Ic swap\-window . .Ic swap\-window .
.Tg selectw .Tg selectw
.It Xo Ic select\-window .It Xo Ic select\-window
.Op Fl lnpT .Op Fl LlnpST
.Op Fl t Ar target\-window .Op Fl t Ar target\-window
.Xc .Xc
.D1 Pq alias: Ic selectw .D1 Pq alias: Ic selectw
Select the window at Select the window at
.Ar target\-window . .Ar target\-window .
.Fl L
makes the attached client use a local current window for the target session.
Window navigation from that client then changes only that client's effective
window and leaves the session current window unchanged.
.Fl S
returns the client to the shared session current window.
Without
.Fl L ,
the current window is shared by the session and stored in the session.
.Pp
.Fl l , .Fl l ,
.Fl n .Fl n
and and
@@ -7177,7 +7187,10 @@ will be replaced by
The following variables are available, where appropriate: The following variables are available, where appropriate:
.Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX" .Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
.It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with" .It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with"
.It Li "active_window_index" Ta "" Ta "Index of active window in session" .It Li "active_window_id" Ta "" Ta "ID of effective active window"
.It Li "active_window_index" Ta "" Ta "Index of effective active window"
.It Li "local_active_window" Ta "" Ta "1 if client has local window selection"
.It Li "active_window_mode" Ta "" Ta "Window selection mode, shared or local"
.It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen" .It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen"
.It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen" .It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
.It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen" .It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
@@ -7392,7 +7405,7 @@ The following variables are available, where appropriate:
.It Li "uid" Ta "" Ta "Server UID" .It Li "uid" Ta "" Ta "Server UID"
.It Li "user" Ta "" Ta "Server user" .It Li "user" Ta "" Ta "Server user"
.It Li "version" Ta "" Ta "Server version" .It Li "version" Ta "" Ta "Server version"
.It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active" Ta "" Ta "1 if window is the effective active window"
.It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window" .It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window"
.It Li "window_active_clients_list" Ta "" Ta "List of clients viewing this window" .It Li "window_active_clients_list" Ta "" Ta "List of clients viewing this window"
.It Li "window_active_sessions" Ta "" Ta "Number of sessions on which this window is active" .It Li "window_active_sessions" Ta "" Ta "Number of sessions on which this window is active"

28
tmux.h
View File

@@ -2741,6 +2741,32 @@ void events_fire_window(const char *, struct window *);
void events_fire_pane(const char *, struct window_pane *); void events_fire_pane(const char *, struct window_pane *);
void events_fire_winlink(const char *, struct winlink *); void events_fire_winlink(const char *, struct winlink *);
/* active.c */
enum active_window_mode {
ACTIVE_SHARED,
ACTIVE_LOCAL
};
int active_is_local_window(struct client *, struct session *);
void active_set_local_window(struct client *, struct session *,
enum active_window_mode);
struct winlink *active_get_effective_winlink(struct client *,
struct session *);
struct window *active_get_effective_window(struct client *,
struct session *);
int active_select_window(struct client *, struct session *,
struct winlink *);
int active_select_window_index(struct client *, struct session *, int);
int active_next_window(struct client *, struct session *, int);
int active_previous_window(struct client *, struct session *, int);
int active_last_window(struct client *, struct session *);
void active_remove_client(struct client *);
void active_remove_session(struct session *);
void active_remove_window(struct window *);
int active_is_effective_window(struct client *, struct session *,
struct winlink *);
int active_is_last_window(struct client *, struct session *,
struct winlink *);
/* format-draw.c */ /* format-draw.c */
void format_draw(struct screen_write_ctx *, const struct grid_cell *, void format_draw(struct screen_write_ctx *, const struct grid_cell *,
u_int, const char *, struct style_ranges *, int); u_int, const char *, struct style_ranges *, int);
@@ -3733,7 +3759,7 @@ int window_pane_is_visible(struct window_pane *);
int window_pane_exited(struct window_pane *); int window_pane_exited(struct window_pane *);
u_int window_pane_search(struct window_pane *, const char *, int, u_int window_pane_search(struct window_pane *, const char *, int,
int); int);
const char *window_printable_flags(struct winlink *, int); const char *window_printable_flags(struct client *, struct winlink *, int);
const char *window_pane_printable_flags(struct window_pane *); const char *window_pane_printable_flags(struct window_pane *);
struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *);

View File

@@ -1007,12 +1007,12 @@ complete_key:
/* Check for focus events. */ /* Check for focus events. */
if (key == KEYC_FOCUS_OUT) { if (key == KEYC_FOCUS_OUT) {
c->flags &= ~CLIENT_FOCUSED; c->flags &= ~CLIENT_FOCUSED;
window_update_focus(c->session->curw->window); window_update_focus(active_get_effective_window(c, c->session));
events_fire_client("client-focus-out", c); events_fire_client("client-focus-out", c);
} else if (key == KEYC_FOCUS_IN) { } else if (key == KEYC_FOCUS_IN) {
c->flags |= CLIENT_FOCUSED; c->flags |= CLIENT_FOCUSED;
events_fire_client("client-focus-in", c); events_fire_client("client-focus-in", c);
window_update_focus(c->session->curw->window); window_update_focus(active_get_effective_window(c, c->session));
} }
/* Fire the key. */ /* Fire the key. */

9
tty.c
View File

@@ -937,7 +937,7 @@ int
tty_window_bigger(struct tty *tty) tty_window_bigger(struct tty *tty)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
return (tty->sx < w->sx || tty->sy - status_line_size(c) < w->sy); return (tty->sx < w->sx || tty->sy - status_line_size(c) < w->sy);
} }
@@ -959,7 +959,7 @@ static int
tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy) tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct window *w = c->session->curw->window; struct window *w = active_get_effective_window(c, c->session);
struct window_pane *wp = w->active; struct window_pane *wp = w->active;
u_int cx, cy, lines; u_int cx, cy, lines;
@@ -1026,8 +1026,7 @@ tty_update_window_offset(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && if (c->session != NULL &&
c->session->curw != NULL && active_get_effective_window(c, c->session) == w)
c->session->curw->window == w)
tty_update_client_offset(c); tty_update_client_offset(c);
} }
} }
@@ -1529,7 +1528,7 @@ tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
{ {
struct window_pane *wp = ttyctx->arg; struct window_pane *wp = ttyctx->arg;
if (c->session->curw->window != wp->window) if (active_get_effective_window(c, c->session) != wp->window)
return (0); return (0);
if (wp->layout_cell == NULL) if (wp->layout_cell == NULL)
return (0); return (0);

View File

@@ -93,7 +93,7 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
struct grid_cell *saved; struct grid_cell *saved;
int *flag; int *flag;
if (wp == c->session->curw->window->active) { if (wp == active_get_effective_window(c, c->session)->active) {
flag = &wp->active_border_gc_set; flag = &wp->active_border_gc_set;
saved = &wp->active_border_gc; saved = &wp->active_border_gc;
option = "pane-active-border-style"; option = "pane-active-border-style";
@@ -104,7 +104,7 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
} }
if (!*flag) { if (!*flag) {
ft = format_create_defaults(NULL, c, s, s->curw, wp); ft = format_create_defaults(NULL, c, s, NULL, wp);
style_apply(saved, wp->options, option, ft); style_apply(saved, wp->options, option, ft);
format_free(ft); format_free(ft);
*flag = 1; *flag = 1;
@@ -133,7 +133,7 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width,
return (0); return (0);
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS); ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
format_defaults(ft, c, c->session, c->session->curw, wp); format_defaults(ft, c, c->session, NULL, wp);
fmt = options_get_string(wp->options, "pane-border-format"); fmt = options_get_string(wp->options, "pane-border-format");
expanded = format_expand_time(ft, fmt); expanded = format_expand_time(ft, fmt);

View File

@@ -266,12 +266,13 @@ window_client_draw_info(__unused void *modedata, void *itemdata,
struct window_client_itemdata *item = itemdata; struct window_client_itemdata *item = itemdata;
struct client *c = item->c; struct client *c = item->c;
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct window *w = c->session->curw->window; struct window *w;
struct grid_cell gc; struct grid_cell gc;
u_int cx = s->cx, cy = s->cy, i; u_int cx = s->cx, cy = s->cy, i;
struct format_tree *ft; struct format_tree *ft;
char *expanded; char *expanded;
w = active_get_effective_window(c, c->session);
ft = format_create_defaults(NULL, c, NULL, NULL, NULL); ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
screen_write_cursormove(ctx, cx, cy, 0); screen_write_cursormove(ctx, cx, cy, 0);

View File

@@ -453,6 +453,7 @@ window_destroy(struct window *w)
{ {
log_debug("window @%u destroyed (%d references)", w->id, w->references); log_debug("window @%u destroyed (%d references)", w->id, w->references);
active_remove_window(w);
window_unzoom(w, 0); window_unzoom(w, 0);
RB_REMOVE(windows, &windows, w); RB_REMOVE(windows, &windows, w);
@@ -675,6 +676,7 @@ void
window_pane_update_focus(struct window_pane *wp) window_pane_update_focus(struct window_pane *wp)
{ {
struct client *c; struct client *c;
struct window *w;
int focused = 0; int focused = 0;
if (wp != NULL && (~wp->flags & PANE_EXITED)) { if (wp != NULL && (~wp->flags & PANE_EXITED)) {
@@ -682,10 +684,12 @@ window_pane_update_focus(struct window_pane *wp)
focused = 0; focused = 0;
else { else {
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && if (c->session == NULL)
c->session->attached != 0 && continue;
w = active_get_effective_window(c, c->session);
if (c->session->attached != 0 &&
(c->flags & CLIENT_FOCUSED) && (c->flags & CLIENT_FOCUSED) &&
c->session->curw->window == wp->window && w == wp->window &&
c->overlay_draw == NULL && c->overlay_draw == NULL &&
wp->window->menu == NULL) { wp->window->menu == NULL) {
focused = 1; focused = 1;
@@ -1222,7 +1226,7 @@ window_destroy_panes(struct window *w)
} }
const char * const char *
window_printable_flags(struct winlink *wl, int escape) window_printable_flags(struct client *c, struct winlink *wl, int escape)
{ {
struct session *s = wl->session; struct session *s = wl->session;
static char flags[32]; static char flags[32];
@@ -1237,9 +1241,9 @@ window_printable_flags(struct winlink *wl, int escape)
flags[pos++] = '!'; flags[pos++] = '!';
if (wl->flags & WINLINK_SILENCE) if (wl->flags & WINLINK_SILENCE)
flags[pos++] = '~'; flags[pos++] = '~';
if (wl == s->curw) if (active_is_effective_window(c, s, wl))
flags[pos++] = '*'; flags[pos++] = '*';
if (wl == TAILQ_FIRST(&s->lastw)) if (active_is_last_window(c, s, wl))
flags[pos++] = '-'; flags[pos++] = '-';
if (server_check_marked() && wl == marked_pane.wl) if (server_check_marked() && wl == marked_pane.wl)
flags[pos++] = 'M'; flags[pos++] = 'M';