mirror of
https://github.com/tmux/tmux.git
synced 2026-07-22 16:52:42 +00:00
738 lines
18 KiB
C
738 lines
18 KiB
C
/* $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);
|
|
|
|
/* Pane entry in a client-local last-pane stack. */
|
|
struct active_pane_entry {
|
|
struct window_pane *wp;
|
|
TAILQ_ENTRY(active_pane_entry) entry;
|
|
};
|
|
TAILQ_HEAD(active_pane_stack, active_pane_entry);
|
|
|
|
/* Per-client and per-window local active pane state. */
|
|
struct active_pane {
|
|
struct client *client;
|
|
struct window *window;
|
|
enum active_mode mode;
|
|
struct window_pane *pane;
|
|
struct active_pane_stack last_panes;
|
|
|
|
RB_ENTRY(active_pane) entry;
|
|
};
|
|
RB_HEAD(active_panes, active_pane);
|
|
|
|
/* Compare local active window states by client and session. */
|
|
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);
|
|
|
|
/* Compare local active pane states by client and window. */
|
|
static int
|
|
active_pane_cmp(struct active_pane *ap1, struct active_pane *ap2)
|
|
{
|
|
uintptr_t c1 = (uintptr_t)ap1->client;
|
|
uintptr_t c2 = (uintptr_t)ap2->client;
|
|
uintptr_t w1 = (uintptr_t)ap1->window;
|
|
uintptr_t w2 = (uintptr_t)ap2->window;
|
|
|
|
if (c1 < c2)
|
|
return (-1);
|
|
if (c1 > c2)
|
|
return (1);
|
|
if (w1 < w2)
|
|
return (-1);
|
|
if (w1 > w2)
|
|
return (1);
|
|
return (0);
|
|
}
|
|
RB_GENERATE_STATIC(active_panes, active_pane, entry, active_pane_cmp);
|
|
|
|
/* All local active window states. */
|
|
static struct active_windows active_windows = RB_INITIALIZER(&active_windows);
|
|
|
|
/* All local active pane states. */
|
|
static struct active_panes active_panes = RB_INITIALIZER(&active_panes);
|
|
|
|
/* Find local active window state for a client and session. */
|
|
static struct active_window *
|
|
active_window_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_window_add(struct client *c, struct session *s, struct winlink *wl)
|
|
{
|
|
struct active_window *aw;
|
|
|
|
aw = active_window_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);
|
|
}
|
|
|
|
/* Remove a window from a local last-window stack. */
|
|
static void
|
|
active_window_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_window_stack_push(struct active_window_stack *stack, u_int window)
|
|
{
|
|
struct active_window_entry *awe;
|
|
|
|
active_window_stack_remove(stack, window);
|
|
awe = xcalloc(1, sizeof *awe);
|
|
awe->window = window;
|
|
TAILQ_INSERT_HEAD(stack, awe, entry);
|
|
}
|
|
|
|
/* Free local active window state. */
|
|
static void
|
|
active_window_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_window_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_window_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);
|
|
}
|
|
|
|
/* Notify the server that a client's effective window changed. */
|
|
static void
|
|
active_window_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();
|
|
}
|
|
|
|
/* Find local active pane state for a client and window. */
|
|
static struct active_pane *
|
|
active_pane_get(struct client *c, struct window *w)
|
|
{
|
|
struct active_pane ap;
|
|
|
|
if (c == NULL || w == NULL)
|
|
return (NULL);
|
|
ap.client = c;
|
|
ap.window = w;
|
|
return (RB_FIND(active_panes, &active_panes, &ap));
|
|
}
|
|
|
|
/* Add local active pane state for a client and window. */
|
|
static struct active_pane *
|
|
active_pane_add(struct client *c, struct window *w)
|
|
{
|
|
struct active_pane *ap;
|
|
|
|
ap = active_pane_get(c, w);
|
|
if (ap == NULL) {
|
|
ap = xcalloc(1, sizeof *ap);
|
|
ap->client = c;
|
|
ap->window = w;
|
|
TAILQ_INIT(&ap->last_panes);
|
|
RB_INSERT(active_panes, &active_panes, ap);
|
|
}
|
|
return (ap);
|
|
}
|
|
|
|
/* Remove a pane from a client-local last-pane stack. */
|
|
static void
|
|
active_pane_stack_remove(struct active_pane *ap,
|
|
struct window_pane *wp)
|
|
{
|
|
struct active_pane_entry *ape, *ape1;
|
|
|
|
TAILQ_FOREACH_SAFE(ape, &ap->last_panes, entry, ape1) {
|
|
if (ape->wp == wp) {
|
|
TAILQ_REMOVE(&ap->last_panes, ape, entry);
|
|
free(ape);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Push a pane onto a client-local last-pane stack. */
|
|
static void
|
|
active_pane_stack_push(struct active_pane *ap, struct window_pane *wp)
|
|
{
|
|
struct active_pane_entry *ape;
|
|
|
|
if (wp == NULL)
|
|
return;
|
|
active_pane_stack_remove(ap, wp);
|
|
ape = xcalloc(1, sizeof *ape);
|
|
ape->wp = wp;
|
|
TAILQ_INSERT_HEAD(&ap->last_panes, ape, entry);
|
|
}
|
|
|
|
/* Free local active pane state. */
|
|
static void
|
|
active_pane_free(struct active_pane *ap)
|
|
{
|
|
struct active_pane_entry *ape, *ape1;
|
|
|
|
RB_REMOVE(active_panes, &active_panes, ap);
|
|
TAILQ_FOREACH_SAFE(ape, &ap->last_panes, entry, ape1) {
|
|
TAILQ_REMOVE(&ap->last_panes, ape, entry);
|
|
free(ape);
|
|
}
|
|
free(ap);
|
|
}
|
|
|
|
/* Check whether a pane can be the effective pane for a window. */
|
|
static int
|
|
active_pane_valid(struct window *w, struct window_pane *wp)
|
|
{
|
|
if (w == NULL || wp == NULL || wp->window != w)
|
|
return (0);
|
|
if (!window_has_pane(w, wp))
|
|
return (0);
|
|
if (w->modal != NULL && wp != w->modal)
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
/* Get the shared pane for a window, accounting for modal panes. */
|
|
static struct window_pane *
|
|
active_pane_default(struct window *w)
|
|
{
|
|
if (w == NULL)
|
|
return (NULL);
|
|
if (w->modal != NULL)
|
|
return (w->modal);
|
|
return (w->active);
|
|
}
|
|
|
|
/* Return if a client has local window selection for a session. */
|
|
int
|
|
active_is_local_window(struct client *c, struct session *s)
|
|
{
|
|
return (active_window_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_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_window_add(c, s, old);
|
|
if (c != NULL && c->session == s)
|
|
c->flags |= CLIENT_REDRAWSTATUS;
|
|
return;
|
|
}
|
|
|
|
aw = active_window_get(c, s);
|
|
if (aw != NULL) {
|
|
active_window_free(aw);
|
|
wl = active_get_effective_winlink(c, s);
|
|
active_window_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_window_get(c, s);
|
|
if (aw != NULL)
|
|
return (active_window_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_window_get(c, s);
|
|
if (aw == NULL)
|
|
return (session_set_current(s, wl));
|
|
|
|
old = active_window_resolve(aw);
|
|
if (old == wl)
|
|
return (1);
|
|
if (old != NULL)
|
|
active_window_stack_push(&aw->lastw, old->window->id);
|
|
active_window_stack_remove(&aw->lastw, wl->window->id);
|
|
aw->window = wl->window->id;
|
|
changed = (old != wl);
|
|
active_window_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_window_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_window_stack_remove(&aw->lastw, window);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
/* 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_window_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);
|
|
}
|
|
|
|
/* Return if a client has local pane selection for a window. */
|
|
int
|
|
active_has_local_pane(struct client *c, struct window *w)
|
|
{
|
|
struct active_pane *ap;
|
|
|
|
ap = active_pane_get(c, w);
|
|
return (ap != NULL && ap->mode == ACTIVE_LOCAL);
|
|
}
|
|
|
|
/* Make a client use local or shared pane selection for a window. */
|
|
void
|
|
active_set_pane_mode(struct client *c, struct window *w, enum active_mode mode)
|
|
{
|
|
struct active_pane *ap;
|
|
struct window_pane *wp;
|
|
|
|
if (c == NULL || w == NULL)
|
|
return;
|
|
if (mode == ACTIVE_SHARED) {
|
|
ap = active_pane_get(c, w);
|
|
if (ap != NULL)
|
|
ap->mode = ACTIVE_SHARED;
|
|
server_redraw_client(c);
|
|
server_status_client(c);
|
|
return;
|
|
}
|
|
|
|
if (server_client_how_many() < 2) {
|
|
ap = active_pane_get(c, w);
|
|
if (ap != NULL)
|
|
ap->mode = ACTIVE_SHARED;
|
|
server_redraw_client(c);
|
|
server_status_client(c);
|
|
return;
|
|
}
|
|
|
|
wp = active_get_effective_pane(c, w);
|
|
if (wp == NULL)
|
|
wp = active_pane_default(w);
|
|
ap = active_pane_add(c, w);
|
|
ap->mode = ACTIVE_LOCAL;
|
|
ap->pane = wp;
|
|
server_redraw_client(c);
|
|
server_status_client(c);
|
|
}
|
|
|
|
/* Return the effective active pane for a client and window. */
|
|
struct window_pane *
|
|
active_get_effective_pane(struct client *c, struct window *w)
|
|
{
|
|
struct active_pane *ap;
|
|
struct window_pane *wp;
|
|
|
|
wp = active_pane_default(w);
|
|
ap = active_pane_get(c, w);
|
|
if (ap == NULL || ap->mode != ACTIVE_LOCAL)
|
|
return (wp);
|
|
if (!active_pane_valid(w, ap->pane)) {
|
|
ap->pane = wp;
|
|
if (wp != NULL)
|
|
active_pane_stack_remove(ap, wp);
|
|
return (wp);
|
|
}
|
|
return (ap->pane);
|
|
}
|
|
|
|
/* Return the effective last pane for a client and window. */
|
|
struct window_pane *
|
|
active_get_last_pane(struct client *c, struct window *w)
|
|
{
|
|
struct active_pane *ap;
|
|
struct active_pane_entry *ape, *ape1;
|
|
|
|
if (!active_has_local_pane(c, w))
|
|
return (w == NULL ? NULL : TAILQ_FIRST(&w->last_panes));
|
|
|
|
ap = active_pane_get(c, w);
|
|
TAILQ_FOREACH_SAFE(ape, &ap->last_panes, entry, ape1) {
|
|
if (active_pane_valid(w, ape->wp))
|
|
return (ape->wp);
|
|
TAILQ_REMOVE(&ap->last_panes, ape, entry);
|
|
free(ape);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/* Select a pane using either shared or local state. */
|
|
int
|
|
active_set_pane(struct client *c, struct window *w, struct window_pane *wp,
|
|
int notify)
|
|
{
|
|
struct active_pane *ap;
|
|
struct window_pane *lastwp;
|
|
|
|
if (!active_pane_valid(w, wp))
|
|
return (0);
|
|
if (!active_has_local_pane(c, w))
|
|
return (window_set_active_pane(w, wp, notify));
|
|
|
|
lastwp = active_get_effective_pane(c, w);
|
|
if (wp == lastwp)
|
|
return (0);
|
|
|
|
ap = active_pane_add(c, w);
|
|
active_pane_stack_remove(ap, wp);
|
|
active_pane_stack_push(ap, lastwp);
|
|
ap->pane = wp;
|
|
|
|
if (c != NULL) {
|
|
server_redraw_client(c);
|
|
server_status_client(c);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/* Remove all local pane state if fewer than two clients remain. */
|
|
void
|
|
active_check_clients(void)
|
|
{
|
|
struct active_pane *ap, *ap1;
|
|
|
|
if (server_client_how_many() >= 2)
|
|
return;
|
|
|
|
RB_FOREACH_SAFE(ap, active_panes, &active_panes, ap1) {
|
|
if (ap->mode == ACTIVE_LOCAL) {
|
|
server_redraw_client(ap->client);
|
|
server_status_client(ap->client);
|
|
}
|
|
active_pane_free(ap);
|
|
}
|
|
}
|
|
|
|
/* Remove all state for a client. */
|
|
void
|
|
active_remove_client(struct client *c)
|
|
{
|
|
struct active_window *aw, *aw1;
|
|
struct active_pane *ap, *ap1;
|
|
|
|
RB_FOREACH_SAFE(aw, active_windows, &active_windows, aw1) {
|
|
if (aw->client == c)
|
|
active_window_free(aw);
|
|
}
|
|
RB_FOREACH_SAFE(ap, active_panes, &active_panes, ap1) {
|
|
if (ap->client == c)
|
|
active_pane_free(ap);
|
|
}
|
|
}
|
|
|
|
/* Remove all window 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_window_free(aw);
|
|
}
|
|
}
|
|
|
|
/* Remove a window from all local state. */
|
|
void
|
|
active_remove_window(struct window *w)
|
|
{
|
|
struct active_window *aw;
|
|
struct active_pane *ap, *ap1;
|
|
|
|
RB_FOREACH(aw, active_windows, &active_windows) {
|
|
active_window_stack_remove(&aw->lastw, w->id);
|
|
if (aw->window == w->id && aw->session->curw != NULL)
|
|
aw->window = aw->session->curw->window->id;
|
|
}
|
|
RB_FOREACH_SAFE(ap, active_panes, &active_panes, ap1) {
|
|
if (ap->window == w)
|
|
active_pane_free(ap);
|
|
}
|
|
}
|
|
|
|
/* Remove a pane from all local pane state. */
|
|
void
|
|
active_remove_pane(struct window_pane *wp)
|
|
{
|
|
struct active_pane *ap, *ap1;
|
|
|
|
RB_FOREACH_SAFE(ap, active_panes, &active_panes, ap1) {
|
|
active_pane_stack_remove(ap, wp);
|
|
if (ap->pane == wp)
|
|
ap->pane = NULL;
|
|
}
|
|
}
|