mirror of
https://github.com/tmux/tmux.git
synced 2026-07-31 04:28:58 +00:00
Add local panes as well.
This commit is contained in:
478
active.c
478
active.c
@@ -43,6 +43,26 @@ struct active_window {
|
||||
};
|
||||
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)
|
||||
{
|
||||
@@ -63,22 +83,36 @@ active_window_cmp(struct active_window *aw1, struct active_window *aw2)
|
||||
}
|
||||
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 *);
|
||||
/* 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_get(struct client *c, struct session *s)
|
||||
active_window_get(struct client *c, struct session *s)
|
||||
{
|
||||
struct active_window aw;
|
||||
|
||||
@@ -91,11 +125,11 @@ active_get(struct client *c, struct session *s)
|
||||
|
||||
/* 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)
|
||||
active_window_add(struct client *c, struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct active_window *aw;
|
||||
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw == NULL) {
|
||||
aw = xcalloc(1, sizeof *aw);
|
||||
aw->client = c;
|
||||
@@ -108,9 +142,35 @@ active_add(struct client *c, struct session *s, struct winlink *wl)
|
||||
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_free(struct active_window *aw)
|
||||
active_window_free(struct active_window *aw)
|
||||
{
|
||||
struct active_window_entry *awe;
|
||||
|
||||
@@ -125,7 +185,7 @@ active_free(struct active_window *aw)
|
||||
|
||||
/* Resolve local active window state to a valid winlink. */
|
||||
static struct winlink *
|
||||
active_resolve(struct active_window *aw)
|
||||
active_window_resolve(struct active_window *aw)
|
||||
{
|
||||
struct winlink *wl, *next;
|
||||
u_int window;
|
||||
@@ -141,7 +201,7 @@ active_resolve(struct active_window *aw)
|
||||
window = TAILQ_FIRST(&aw->lastw)->window;
|
||||
|
||||
next = winlink_find_by_window_id(&aw->session->windows, window);
|
||||
active_stack_remove(&aw->lastw, window);
|
||||
active_window_stack_remove(&aw->lastw, window);
|
||||
if (next != NULL) {
|
||||
aw->window = next->window->id;
|
||||
return (next);
|
||||
@@ -152,35 +212,9 @@ active_resolve(struct active_window *aw)
|
||||
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,
|
||||
active_window_changed(struct client *c, struct session *s, struct winlink *wl,
|
||||
struct winlink *old)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
@@ -225,17 +259,114 @@ active_changed(struct client *c, struct session *s, struct winlink *wl,
|
||||
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_get(c, s) != NULL);
|
||||
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_window_mode mode)
|
||||
enum active_mode mode)
|
||||
{
|
||||
struct active_window *aw;
|
||||
struct winlink *wl, *old;
|
||||
@@ -245,17 +376,17 @@ active_set_local_window(struct client *c, struct session *s,
|
||||
|
||||
old = active_get_effective_winlink(c, s);
|
||||
if (mode == ACTIVE_LOCAL) {
|
||||
active_add(c, s, old);
|
||||
active_window_add(c, s, old);
|
||||
if (c != NULL && c->session == s)
|
||||
c->flags |= CLIENT_REDRAWSTATUS;
|
||||
return;
|
||||
}
|
||||
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw != NULL) {
|
||||
active_free(aw);
|
||||
active_window_free(aw);
|
||||
wl = active_get_effective_winlink(c, s);
|
||||
active_changed(c, s, wl, old);
|
||||
active_window_changed(c, s, wl, old);
|
||||
if (c != NULL && c->session == s)
|
||||
c->flags |= CLIENT_REDRAWSTATUS;
|
||||
}
|
||||
@@ -269,9 +400,9 @@ active_get_effective_winlink(struct client *c, struct session *s)
|
||||
|
||||
if (s == NULL)
|
||||
return (NULL);
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw != NULL)
|
||||
return (active_resolve(aw));
|
||||
return (active_window_resolve(aw));
|
||||
return (s->curw);
|
||||
}
|
||||
|
||||
@@ -297,19 +428,19 @@ active_select_window(struct client *c, struct session *s, struct winlink *wl)
|
||||
|
||||
if (wl == NULL)
|
||||
return (-1);
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw == NULL)
|
||||
return (session_set_current(s, wl));
|
||||
|
||||
old = active_resolve(aw);
|
||||
old = active_window_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);
|
||||
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_changed(c, s, wl, old);
|
||||
active_window_changed(c, s, wl, old);
|
||||
return (changed ? 0 : 1);
|
||||
}
|
||||
|
||||
@@ -369,7 +500,7 @@ active_last_window(struct client *c, struct session *s)
|
||||
struct winlink *wl;
|
||||
u_int window;
|
||||
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw == NULL)
|
||||
return (session_last(s));
|
||||
while (!TAILQ_EMPTY(&aw->lastw)) {
|
||||
@@ -378,48 +509,11 @@ active_last_window(struct client *c, struct session *s)
|
||||
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);
|
||||
active_window_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,
|
||||
@@ -437,7 +531,7 @@ active_is_last_window(struct client *c, struct session *s, struct winlink *wl)
|
||||
|
||||
if (wl == NULL)
|
||||
return (0);
|
||||
aw = active_get(c, s);
|
||||
aw = active_window_get(c, s);
|
||||
if (aw == NULL)
|
||||
return (wl == TAILQ_FIRST(&s->lastw));
|
||||
TAILQ_FOREACH(awe, &aw->lastw, entry) {
|
||||
@@ -447,3 +541,197 @@ active_is_last_window(struct client *c, struct session *s, struct winlink *wl)
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,7 +885,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
|
||||
cmd_find_clear_state(fs, flags);
|
||||
|
||||
fs->wl = active_get_effective_winlink(c, c->session);
|
||||
fs->wp = fs->wl->window->active;
|
||||
fs->wp = active_get_effective_pane(c, fs->wl->window);
|
||||
if (fs->wp == NULL) {
|
||||
cmd_find_from_session(fs, c->session, flags);
|
||||
return (0);
|
||||
|
||||
@@ -186,6 +186,7 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
@@ -358,6 +359,7 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
@@ -397,6 +399,7 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ static void
|
||||
cmd_run_shell_print(struct job *job, const char *msg)
|
||||
{
|
||||
struct cmd_run_shell_data *cdata = job_get_data(job);
|
||||
struct client *c;
|
||||
struct client *c = cdata->client;
|
||||
struct session *s;
|
||||
struct window_pane *wp = NULL;
|
||||
struct window *w;
|
||||
@@ -93,11 +93,10 @@ cmd_run_shell_print(struct job *job, const char *msg)
|
||||
cmdq_print(cdata->item, "%s", msg);
|
||||
return;
|
||||
}
|
||||
c = cdata->client;
|
||||
if (c != NULL && c->session != NULL) {
|
||||
s = c->session;
|
||||
w = active_get_effective_window(c, s);
|
||||
wp = w->active;
|
||||
wp = active_get_effective_pane(c, w);
|
||||
}
|
||||
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
|
||||
wp = fs.wp;
|
||||
|
||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_pane_entry = {
|
||||
.name = "select-pane",
|
||||
.alias = "selectp",
|
||||
|
||||
.args = { "DdegLlMmP:RT:t:UZ", 0, 0, NULL }, /* -P and -g deprecated */
|
||||
.usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "DdegLlMmP:RsST:t:UZ", 0, 0, NULL }, /* -P and -g deprecated */
|
||||
.usage = "[-DdeLlMmRsSUZ] [-T title] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -85,6 +85,7 @@ static enum cmd_retval
|
||||
cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
@@ -138,8 +139,9 @@ cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
|
||||
server_status_window(mwp->window);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
window_redraw_active_switch(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
if (!active_has_local_pane(c, wp->window))
|
||||
window_redraw_active_switch(wp->window, wp);
|
||||
active_set_pane(c, wp->window, wp, 1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -153,25 +155,39 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp, *lastwp;
|
||||
struct window_pane *wp = target->wp, *lastwp, *activewp;
|
||||
struct options *oo = wp->options;
|
||||
char *title;
|
||||
const char *style;
|
||||
struct options_entry *o;
|
||||
|
||||
if (args_has(args, 's') || 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'))
|
||||
active_set_pane_mode(c, w, ACTIVE_LOCAL);
|
||||
else
|
||||
active_set_pane_mode(c, w, ACTIVE_SHARED);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
|
||||
/*
|
||||
* Check for no last pane found in case the other pane was
|
||||
* spawned without being visited (for example split-window -d).
|
||||
*/
|
||||
lastwp = TAILQ_FIRST(&w->last_panes);
|
||||
lastwp = active_get_last_pane(c, w);
|
||||
if (lastwp == NULL && window_count_panes(w, 1) == 2) {
|
||||
lastwp = TAILQ_PREV(w->active, window_panes, entry);
|
||||
activewp = active_get_effective_pane(c, w);
|
||||
lastwp = TAILQ_PREV(activewp, window_panes, entry);
|
||||
if (lastwp == NULL)
|
||||
lastwp = TAILQ_NEXT(w->active, entry);
|
||||
lastwp = TAILQ_NEXT(activewp, entry);
|
||||
}
|
||||
if (lastwp == NULL) {
|
||||
cmdq_error(item, "no last pane");
|
||||
@@ -188,8 +204,9 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
} else {
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, lastwp);
|
||||
if (window_set_active_pane(w, lastwp, 1)) {
|
||||
if (!active_has_local_pane(c, w))
|
||||
window_redraw_active_switch(w, lastwp);
|
||||
if (active_set_pane(c, w, lastwp, 1)) {
|
||||
cmd_find_from_winlink(current, wl, 0);
|
||||
cmd_select_pane_redraw(w);
|
||||
}
|
||||
@@ -267,12 +284,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (wp == w->active)
|
||||
activewp = active_get_effective_pane(c, w);
|
||||
if (wp == activewp)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (window_set_active_pane(w, wp, 1))
|
||||
if (!active_has_local_pane(c, w))
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (active_set_pane(c, w, wp, 1))
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
cmdq_insert_hook(s, item, current, "after-select-pane");
|
||||
cmd_select_pane_redraw(w);
|
||||
|
||||
@@ -90,7 +90,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct winlink *wl = target->wl, *current_wl;
|
||||
struct session *s = target->s;
|
||||
enum active_window_mode mode;
|
||||
enum active_mode mode;
|
||||
int next, previous, last, activity;
|
||||
|
||||
next = (cmd_get_entry(self) == &cmd_next_window_entry);
|
||||
|
||||
49
format.c
49
format.c
@@ -1061,7 +1061,8 @@ format_cb_pane_fg(struct format_tree *ft)
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
|
||||
tty_default_colours(&gc, wp, NULL);
|
||||
tty_default_colours(&gc, wp,
|
||||
active_get_effective_pane(ft->c, wp->window), NULL);
|
||||
return (xstrdup(colour_tostring(gc.fg)));
|
||||
}
|
||||
|
||||
@@ -1112,7 +1113,8 @@ format_cb_pane_bg(struct format_tree *ft)
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
|
||||
tty_default_colours(&gc, wp, NULL);
|
||||
tty_default_colours(&gc, wp,
|
||||
active_get_effective_pane(ft->c, wp->window), NULL);
|
||||
return (xstrdup(colour_tostring(gc.bg)));
|
||||
}
|
||||
|
||||
@@ -2099,14 +2101,45 @@ format_cb_synchronized_output_flag(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_pane_active(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *active;
|
||||
|
||||
if (ft->wp != NULL) {
|
||||
if (ft->wp == ft->wp->window->active)
|
||||
active = active_get_effective_pane(ft->c, ft->wp->window);
|
||||
if (ft->wp == active)
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_local_active. */
|
||||
static void *
|
||||
format_cb_pane_local_active(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *active;
|
||||
|
||||
if (ft->wp != NULL && active_has_local_pane(ft->c, ft->wp->window)) {
|
||||
active = active_get_effective_pane(ft->c, ft->wp->window);
|
||||
if (ft->wp == active)
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_local_mode. */
|
||||
static void *
|
||||
format_cb_pane_local_mode(struct format_tree *ft)
|
||||
{
|
||||
struct window *w = ft->w;
|
||||
|
||||
if (ft->wp != NULL)
|
||||
w = ft->wp->window;
|
||||
if (active_has_local_pane(ft->c, w))
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
|
||||
/* Callback for pane_at_left. */
|
||||
static void *
|
||||
format_cb_pane_at_left(struct format_tree *ft)
|
||||
@@ -2385,7 +2418,7 @@ static void *
|
||||
format_cb_pane_last(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL) {
|
||||
if (ft->wp == TAILQ_FIRST(&ft->wp->window->last_panes))
|
||||
if (ft->wp == active_get_last_pane(ft->c, ft->wp->window))
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
@@ -3750,6 +3783,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_left", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_left
|
||||
},
|
||||
{ "pane_local_active", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_local_active
|
||||
},
|
||||
{ "pane_local_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_local_mode
|
||||
},
|
||||
{ "pane_marked", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_marked
|
||||
},
|
||||
@@ -6746,7 +6785,7 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
|
||||
if (wl == NULL && s != NULL)
|
||||
wl = active_get_effective_winlink(c, s);
|
||||
if (wp == NULL && wl != NULL)
|
||||
wp = wl->window->active;
|
||||
wp = active_get_effective_pane(c, wl->window);
|
||||
|
||||
if (c != NULL)
|
||||
format_defaults_client(ft, c);
|
||||
|
||||
3
input.c
3
input.c
@@ -3078,7 +3078,8 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
||||
return;
|
||||
c = window_pane_get_fg_control_client(wp);
|
||||
if (c == -1) {
|
||||
tty_default_colours(&defaults, wp, NULL);
|
||||
tty_default_colours(&defaults, wp, wp->window->active,
|
||||
NULL);
|
||||
if (COLOUR_DEFAULT(defaults.fg))
|
||||
c = window_pane_get_fg(wp);
|
||||
else
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
" '#{?#{!:#{pane_floating_flag}},Horizontal Split,}' 'h' {split-window -h}" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Vertical Split,}' 'v' {split-window -v}" \
|
||||
" ''" \
|
||||
" '#{?#{>=:#{window_active_clients},2},#{?pane_local_mode,Shared Active Pane,Local Active Pane},}' 'a' {if -F '#{pane_local_mode}' {select-pane -S} {select-pane -s}}" \
|
||||
" ''" \
|
||||
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Up,}' 'u' {swap-pane -U}" \
|
||||
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Down,}' 'd' {swap-pane -D}" \
|
||||
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \
|
||||
@@ -501,6 +503,7 @@ key_bindings_init(void)
|
||||
|
||||
/* Mouse button 1 down on pane. */
|
||||
"bind -n MouseDown1Pane { select-pane -t=; send -M }",
|
||||
"bind -n M-MouseDown1Pane { move-pane -P front -t= }",
|
||||
|
||||
/* Mouse button 1 drag on pane. */
|
||||
"bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }",
|
||||
@@ -522,6 +525,7 @@ key_bindings_init(void)
|
||||
|
||||
/* Mouse button 1 on border. */
|
||||
"bind -n MouseDown1Border { select-pane -M }",
|
||||
"bind -n M-MouseDown1Border { move-pane -P front -t= }",
|
||||
|
||||
/* Mouse button 1 drag on border. */
|
||||
"bind -n MouseDrag1Border { resize-pane -M }",
|
||||
|
||||
@@ -1533,8 +1533,9 @@ const struct options_table_entry options_table[] = {
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "fg=#{?pane_modal_flag,themeblue,"
|
||||
"#{?pane_marked,thememagenta,"
|
||||
"#{?pane_local_active,themecyan,"
|
||||
"#{?synchronize-panes,themered,"
|
||||
"#{?pane_in_mode,themeyellow,themegreen}}}}",
|
||||
"#{?pane_in_mode,themeyellow,themegreen}}}}}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the active pane border."
|
||||
|
||||
201
regress/local-pane-selection.sh
Normal file
201
regress/local-pane-selection.sh
Normal file
@@ -0,0 +1,201 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LANG=C.UTF-8
|
||||
LC_ALL=C.UTF-8
|
||||
export TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
TMPDIR=${TMPDIR:-/tmp}/tmux-local-pane.$$
|
||||
mkdir -p "$TMPDIR" || exit 1
|
||||
IN1="$TMPDIR/in1"
|
||||
IN2="$TMPDIR/in2"
|
||||
OUT1="$TMPDIR/out1"
|
||||
OUT2="$TMPDIR/out2"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$TMPDIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
file=$1
|
||||
pattern=$2
|
||||
i=0
|
||||
while [ "$i" -lt 20 ]; do
|
||||
if grep -q "$pattern" "$file"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "missing '$pattern' in $file"
|
||||
cat "$file"
|
||||
return 1
|
||||
}
|
||||
|
||||
send1()
|
||||
{
|
||||
printf '%s\n' "$*" >&3
|
||||
}
|
||||
|
||||
send2()
|
||||
{
|
||||
printf '%s\n' "$*" >&4
|
||||
}
|
||||
|
||||
check_fmt()
|
||||
{
|
||||
out=$($TMUX display-message -p -t "$1" "$2" 2>&1)
|
||||
if [ "$out" != "$3" ]; then
|
||||
echo "Format '$2' for '$1' wrong."
|
||||
echo "Expected: '$3'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -s active -x 80 -y 24 || exit 1
|
||||
$TMUX split-window -d -h -t active:0 || exit 1
|
||||
$TMUX split-window -d -v -t active:0.0 || exit 1
|
||||
style=$($TMUX show-options -wgv pane-active-border-style) || exit 1
|
||||
case "$style" in
|
||||
*pane_local_active*themecyan*) ;;
|
||||
*) fail "pane-active-border-style does not include local active colour" ;;
|
||||
esac
|
||||
|
||||
p0=$($TMUX display-message -p -t active:0.0 '#{pane_id}') || exit 1
|
||||
p1=$($TMUX display-message -p -t active:0.1 '#{pane_id}') || exit 1
|
||||
p2=$($TMUX display-message -p -t active:0.2 '#{pane_id}') || exit 1
|
||||
$TMUX select-pane -t "$p0" || exit 1
|
||||
check_fmt active:0 '#{pane_id}' "$p0"
|
||||
|
||||
mkfifo "$IN1" "$IN2" || exit 1
|
||||
: >"$OUT1"
|
||||
: >"$OUT2"
|
||||
$TMUX -C attach-session -t active <"$IN1" >"$OUT1" 2>&1 &
|
||||
PID1=$!
|
||||
exec 3>"$IN1"
|
||||
|
||||
send1 'display-message -p C1_READY'
|
||||
wait_for "$OUT1" 'C1_READY' || exit 1
|
||||
|
||||
# One attached client cannot enter local mode.
|
||||
send1 'select-pane -s'
|
||||
send1 "select-pane -t $p1"
|
||||
send1 'display-message -p "C1_SINGLE:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
wait_for "$OUT1" "C1_SINGLE:$p1:1:" || exit 1
|
||||
check_fmt active:0 '#{pane_id}' "$p1"
|
||||
send1 "select-pane -t $p0"
|
||||
check_fmt active:0 '#{pane_id}' "$p0"
|
||||
|
||||
$TMUX -C attach-session -t active <"$IN2" >"$OUT2" 2>&1 &
|
||||
PID2=$!
|
||||
exec 4>"$IN2"
|
||||
|
||||
send2 'display-message -p C2_READY'
|
||||
wait_for "$OUT2" 'C2_READY' || exit 1
|
||||
|
||||
# Both clients start in shared mode and see the window active pane.
|
||||
send1 'display-message -p "C1_START:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
send2 'display-message -p "C2_START:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
wait_for "$OUT1" "C1_START:$p0:1:" || exit 1
|
||||
wait_for "$OUT2" "C2_START:$p0:1:" || exit 1
|
||||
|
||||
# Client 1 enters local mode and selects a pane without changing shared state.
|
||||
send1 'select-pane -s'
|
||||
send1 "select-pane -t $p1"
|
||||
send1 'display-message -p "C1_LOCAL:#{pane_id}:#{pane_active}:#{pane_local_active}:#{pane_local_mode}"'
|
||||
send1 "display-message -p -t $p0 \"C1_LOCAL_INACTIVE:#{pane_id}:#{pane_active}:#{pane_local_active}\""
|
||||
wait_for "$OUT1" "C1_LOCAL:$p1:1:1:1" || exit 1
|
||||
wait_for "$OUT1" "C1_LOCAL_INACTIVE:$p0:0:0" || exit 1
|
||||
check_fmt active:0 '#{pane_id}' "$p0"
|
||||
send2 'display-message -p "C2_SHARED:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
wait_for "$OUT2" "C2_SHARED:$p0:1:" || exit 1
|
||||
|
||||
# Client 2 can keep an independent local pane in the same window.
|
||||
send2 'select-pane -s'
|
||||
send2 "select-pane -t $p2"
|
||||
send2 'display-message -p "C2_LOCAL:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
wait_for "$OUT2" "C2_LOCAL:$p2:1:1" || exit 1
|
||||
send1 'display-message -p "C1_STILL:#{pane_id}:#{pane_active}:#{pane_local_active}"'
|
||||
wait_for "$OUT1" "C1_STILL:$p1:1:1" || exit 1
|
||||
|
||||
# Local last-pane history is independent of the shared window history.
|
||||
send1 "select-pane -t $p2"
|
||||
send1 'last-pane'
|
||||
send1 'display-message -p "C1_LAST:#{pane_id}:#{pane_last}"'
|
||||
wait_for "$OUT1" "C1_LAST:$p1:0" || exit 1
|
||||
check_fmt active:0 '#{pane_id}' "$p0"
|
||||
|
||||
# Switching back to shared mode immediately follows window->active.
|
||||
send1 'select-pane -S'
|
||||
send1 'display-message -p "C1_SHARED_AGAIN:#{pane_id}:#{pane_active}"'
|
||||
wait_for "$OUT1" "C1_SHARED_AGAIN:$p0:1" || exit 1
|
||||
send1 "select-pane -t $p1"
|
||||
check_fmt active:0 '#{pane_id}' "$p1"
|
||||
send2 'display-message -p "C2_STILL_LOCAL:#{pane_id}:#{pane_active}"'
|
||||
wait_for "$OUT2" "C2_STILL_LOCAL:$p2:1" || exit 1
|
||||
|
||||
# Local selection survives switching away and back to the window.
|
||||
send2 'new-window -n other'
|
||||
send2 'previous-window'
|
||||
send2 'display-message -p "C2_AFTER_WINDOW_SWITCH:#{pane_id}:#{pane_active}"'
|
||||
wait_for "$OUT2" "C2_AFTER_WINDOW_SWITCH:$p2:1" || exit 1
|
||||
|
||||
# Removing a locally active pane recovers to the shared active pane.
|
||||
$TMUX kill-pane -t "$p2" || exit 1
|
||||
send2 'display-message -p "C2_AFTER_KILL:#{pane_id}:#{pane_active}"'
|
||||
wait_for "$OUT2" "C2_AFTER_KILL:$p1:1" || exit 1
|
||||
|
||||
# Local selection of a floating pane does not raise it unless requested.
|
||||
f1=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 8 -Y 3 \
|
||||
-t active:0 'sleep 100') || exit 1
|
||||
f2=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 12 -Y 5 \
|
||||
-t active:0 'sleep 100') || exit 1
|
||||
check_fmt "$f1" '#{pane_z}' 1
|
||||
check_fmt "$f2" '#{pane_z}' 0
|
||||
send1 'select-pane -s'
|
||||
send1 "select-pane -t $f1"
|
||||
send1 "display-message -p -t $f1 \"C1_FLOAT_LOCAL:#{pane_id}:#{pane_active}:#{pane_z}\""
|
||||
wait_for "$OUT1" "C1_FLOAT_LOCAL:$f1:1:1" || exit 1
|
||||
check_fmt "$f1" '#{pane_z}' 1
|
||||
send1 "select-pane -M -t $f1"
|
||||
send1 "display-message -p -t $f1 \"C1_FLOAT_BORDER:#{pane_id}:#{pane_active}:#{pane_z}\""
|
||||
wait_for "$OUT1" "C1_FLOAT_BORDER:$f1:1:1" || exit 1
|
||||
check_fmt "$f1" '#{pane_z}' 1
|
||||
send1 "move-pane -P front -t $f1"
|
||||
send1 "display-message -p -t $f1 \"C1_FLOAT_RAISE:#{pane_z}\""
|
||||
wait_for "$OUT1" "C1_FLOAT_RAISE:0" || exit 1
|
||||
check_fmt "$f1" '#{pane_z}' 0
|
||||
$TMUX kill-pane -t "$f1" || exit 1
|
||||
$TMUX kill-pane -t "$f2" || exit 1
|
||||
|
||||
# When only one client remains, local mode is cleared.
|
||||
send1 'select-pane -s'
|
||||
send1 "select-pane -t $p0"
|
||||
send1 'display-message -p "C1_LOCAL_BEFORE_DETACH:#{pane_id}:#{pane_local_active}"'
|
||||
wait_for "$OUT1" "C1_LOCAL_BEFORE_DETACH:$p0:1" || exit 1
|
||||
kill "$PID2" 2>/dev/null
|
||||
wait "$PID2" 2>/dev/null
|
||||
send1 'display-message -p "C1_AFTER_DETACH:#{pane_id}:#{pane_local_active}"'
|
||||
wait_for "$OUT1" "C1_AFTER_DETACH:$p1:" || exit 1
|
||||
|
||||
kill "$PID1" 2>/dev/null
|
||||
wait "$PID1" 2>/dev/null
|
||||
$TMUX display-message -p alive >/dev/null 2>&1 || fail "server died"
|
||||
|
||||
exit 0
|
||||
@@ -1114,7 +1114,7 @@ redraw_draw_pane_span(struct redraw_draw_ctx *dctx,
|
||||
struct tty_style_ctx style_ctx;
|
||||
u_int px, py;
|
||||
|
||||
tty_default_colours(&defaults, wp, &style_ctx.dim);
|
||||
tty_default_colours(&defaults, wp, dctx->active, &style_ctx.dim);
|
||||
style_ctx.defaults = &defaults;
|
||||
style_ctx.palette = &wp->palette;
|
||||
style_ctx.hyperlinks = s->hyperlinks;
|
||||
@@ -1323,7 +1323,7 @@ redraw_draw_scrollbar_span(struct redraw_draw_ctx *dctx,
|
||||
memcpy(&slgc, &gc, sizeof slgc);
|
||||
slgc.fg = gc.bg;
|
||||
slgc.bg = gc.fg;
|
||||
tty_default_colours(&pad_gc, wp, NULL);
|
||||
tty_default_colours(&pad_gc, wp, dctx->active, NULL);
|
||||
|
||||
sb_w = sb_style->width;
|
||||
sb_pad = sb_style->pad;
|
||||
@@ -1601,7 +1601,7 @@ redraw_set_draw_context(struct redraw_draw_ctx *dctx,
|
||||
wl = active_get_effective_winlink(c, s);
|
||||
if (server_is_marked(s, wl, marked_pane.wp))
|
||||
dctx->marked = marked_pane.wp;
|
||||
dctx->active = active_get_effective_window(c, s)->active;
|
||||
dctx->active = active_get_effective_pane(c, wl->window);
|
||||
|
||||
lines = status_line_size(c);
|
||||
if (options_get_number(oo, "status-position") == 0)
|
||||
|
||||
@@ -134,7 +134,7 @@ screen_write_redraw_cb(const struct tty_ctx *ttyctx)
|
||||
static int
|
||||
screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
{
|
||||
struct window_pane *wp = ttyctx->arg;
|
||||
struct window_pane *wp = ttyctx->arg, *active;
|
||||
|
||||
if (ttyctx->flags & TTY_CTX_INVISIBLE_PANES) {
|
||||
if (session_has(c->session, wp->window))
|
||||
@@ -160,11 +160,14 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
active = active_get_effective_pane(c, wp->window);
|
||||
if (tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy, &ttyctx->wsx,
|
||||
&ttyctx->wsy))
|
||||
ttyctx->flags |= TTY_CTX_WINDOW_BIGGER;
|
||||
else
|
||||
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
|
||||
tty_default_colours(&ttyctx->defaults, wp, active,
|
||||
&ttyctx->style_ctx.dim);
|
||||
|
||||
ttyctx->xoff = ttyctx->rxoff = wp->xoff;
|
||||
ttyctx->yoff = ttyctx->ryoff = wp->yoff;
|
||||
@@ -296,7 +299,7 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
|
||||
ttyctx->redraw_cb = screen_write_redraw_cb;
|
||||
if (ctx->wp != NULL) {
|
||||
tty_default_colours(&ttyctx->defaults, ctx->wp,
|
||||
&ttyctx->style_ctx.dim);
|
||||
ctx->wp->window->active, &ttyctx->style_ctx.dim);
|
||||
ttyctx->style_ctx.palette = &ctx->wp->palette;
|
||||
ttyctx->set_client_cb = screen_write_set_client_cb;
|
||||
ttyctx->arg = ctx->wp;
|
||||
|
||||
@@ -505,6 +505,7 @@ server_client_lost(struct client *c)
|
||||
server_client_attached_lost(c);
|
||||
events_fire_client("client-detached", c);
|
||||
}
|
||||
active_check_clients();
|
||||
if (c->name != NULL && (c->flags & (CLIENT_CONTROL|CLIENT_TERMINAL)))
|
||||
events_fire_client("client-closed", c);
|
||||
|
||||
@@ -2105,7 +2106,7 @@ server_client_reset_state(struct client *c)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct window *w = active_get_effective_window(c, c->session);
|
||||
struct window_pane *wp = w->active, *loop;
|
||||
struct window_pane *wp, *loop;
|
||||
struct screen *s = NULL;
|
||||
struct options *oo = c->session->options;
|
||||
int mode = 0, cursor, flags, pane_mode = 0;
|
||||
@@ -2113,6 +2114,7 @@ server_client_reset_state(struct client *c)
|
||||
u_int sb_w;
|
||||
struct visible_ranges *r;
|
||||
|
||||
wp = active_get_effective_pane(c, w);
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
return;
|
||||
|
||||
@@ -3074,6 +3076,7 @@ server_client_remove_pane(struct window_pane *wp)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
active_remove_pane(wp);
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->tty.mouse_last_pane == (int)wp->id) {
|
||||
c->tty.mouse_last_pane = -1;
|
||||
@@ -3089,6 +3092,7 @@ server_client_print(struct client *c, int parse, struct evbuffer *evb)
|
||||
{
|
||||
void *data = EVBUFFER_DATA(evb);
|
||||
size_t size = EVBUFFER_LENGTH(evb);
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct window_mode_entry *wme;
|
||||
char *sanitized, *msg, *line, empty = '\0';
|
||||
@@ -3127,7 +3131,8 @@ server_client_print(struct client *c, int parse, struct evbuffer *evb)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wp = active_get_effective_window(c, c->session)->active;
|
||||
w = active_get_effective_window(c, c->session);
|
||||
wp = active_get_effective_pane(c, w);
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme == NULL || wme->mode != &window_view_mode)
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL,
|
||||
|
||||
15
tmux.1
15
tmux.1
@@ -3981,7 +3981,7 @@ applies the last set layout if possible (undoes the most recent layout change).
|
||||
spreads the current pane and any panes next to it out evenly.
|
||||
.Tg selectp
|
||||
.It Xo Ic select\-pane
|
||||
.Op Fl DdeLlMmRUZ
|
||||
.Op Fl ADdeLlMmRsSUZ
|
||||
.Op Fl T Ar title
|
||||
.Op Fl t Ar target\-pane
|
||||
.Xc
|
||||
@@ -3989,6 +3989,8 @@ spreads the current pane and any panes next to it out evenly.
|
||||
Make pane
|
||||
.Ar target\-pane
|
||||
the active pane in its window.
|
||||
.Fl A
|
||||
raises the pane if it is floating.
|
||||
If one of
|
||||
.Fl D ,
|
||||
.Fl L ,
|
||||
@@ -4003,6 +4005,15 @@ keeps the window zoomed if it was zoomed.
|
||||
is the same as using the
|
||||
.Ic last\-pane
|
||||
command.
|
||||
.Fl s
|
||||
switches the client to local pane selection for the target window when more
|
||||
than one client is attached; the pane currently active for the client is
|
||||
retained.
|
||||
Local pane selection is disabled automatically when fewer than two clients
|
||||
remain attached.
|
||||
.Fl S
|
||||
switches the client back to shared pane selection for the target window, so the
|
||||
window's active pane is used.
|
||||
.Fl e
|
||||
enables or
|
||||
.Fl d
|
||||
@@ -7326,6 +7337,8 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_last" Ta "" Ta "1 if last pane"
|
||||
.It Li "pane_last_output_time" Ta "" Ta "Time pane last produced output"
|
||||
.It Li "pane_last_prompt_time" Ta "" Ta "Time most recent OSC 133 prompt began"
|
||||
.It Li "pane_local_active" Ta "" Ta "1 if active pane is client-local"
|
||||
.It Li "pane_local_mode" Ta "" Ta "1 if client has local pane selection"
|
||||
.It Li "pane_left" Ta "" Ta "Left of pane"
|
||||
.It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
|
||||
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
|
||||
|
||||
17
tmux.h
17
tmux.h
@@ -2742,13 +2742,13 @@ void events_fire_pane(const char *, struct window_pane *);
|
||||
void events_fire_winlink(const char *, struct winlink *);
|
||||
|
||||
/* active.c */
|
||||
enum active_window_mode {
|
||||
enum active_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);
|
||||
enum active_mode);
|
||||
struct winlink *active_get_effective_winlink(struct client *,
|
||||
struct session *);
|
||||
struct window *active_get_effective_window(struct client *,
|
||||
@@ -2766,6 +2766,16 @@ int active_is_effective_window(struct client *, struct session *,
|
||||
struct winlink *);
|
||||
int active_is_last_window(struct client *, struct session *,
|
||||
struct winlink *);
|
||||
int active_has_local_pane(struct client *, struct window *);
|
||||
void active_set_pane_mode(struct client *, struct window *,
|
||||
enum active_mode);
|
||||
struct window_pane *active_get_effective_pane(struct client *,
|
||||
struct window *);
|
||||
struct window_pane *active_get_last_pane(struct client *, struct window *);
|
||||
int active_set_pane(struct client *, struct window *,
|
||||
struct window_pane *, int);
|
||||
void active_check_clients(void);
|
||||
void active_remove_pane(struct window_pane *);
|
||||
|
||||
/* format-draw.c */
|
||||
void format_draw(struct screen_write_ctx *, const struct grid_cell *,
|
||||
@@ -2982,7 +2992,8 @@ void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
|
||||
void tty_draw_images(struct client *, struct window_pane *);
|
||||
#endif
|
||||
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
|
||||
void tty_default_colours(struct grid_cell *, struct window_pane *, u_int *);
|
||||
void tty_default_colours(struct grid_cell *, struct window_pane *,
|
||||
struct window_pane *, u_int *);
|
||||
|
||||
/* tty-term.c */
|
||||
extern struct tty_terms tty_terms;
|
||||
|
||||
12
tty.c
12
tty.c
@@ -960,9 +960,10 @@ tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct window *w = active_get_effective_window(c, c->session);
|
||||
struct window_pane *wp = w->active;
|
||||
struct window_pane *wp;
|
||||
u_int cx, cy, lines;
|
||||
|
||||
wp = active_get_effective_pane(c, w);
|
||||
lines = status_line_size(c);
|
||||
|
||||
if (tty->sx >= w->sx && tty->sy - lines >= w->sy) {
|
||||
@@ -3140,23 +3141,24 @@ tty_style_changed(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
tty_default_colours(struct grid_cell *gc, struct window_pane *wp, u_int *dim)
|
||||
tty_default_colours(struct grid_cell *gc, struct window_pane *wp,
|
||||
struct window_pane *active, u_int *dim)
|
||||
{
|
||||
if (wp->flags & PANE_STYLECHANGED)
|
||||
tty_style_changed (wp);
|
||||
|
||||
memcpy(gc, &grid_default_cell, sizeof *gc);
|
||||
if (wp == wp->window->active && wp->cached_active_gc.fg != 8)
|
||||
if (wp == active && wp->cached_active_gc.fg != 8)
|
||||
gc->fg = wp->cached_active_gc.fg;
|
||||
else
|
||||
gc->fg = wp->cached_gc.fg;
|
||||
if (wp == wp->window->active && wp->cached_active_gc.bg != 8)
|
||||
if (wp == active && wp->cached_active_gc.bg != 8)
|
||||
gc->bg = wp->cached_active_gc.bg;
|
||||
else
|
||||
gc->bg = wp->cached_gc.bg;
|
||||
|
||||
if (dim != NULL) {
|
||||
if (wp == wp->window->active)
|
||||
if (wp == active)
|
||||
*dim = wp->cached_active_dim;
|
||||
else
|
||||
*dim = wp->cached_dim;
|
||||
|
||||
@@ -91,9 +91,14 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
|
||||
struct format_tree *ft;
|
||||
const char *option;
|
||||
struct grid_cell *saved;
|
||||
int *flag;
|
||||
struct window *w;
|
||||
struct window_pane *active;
|
||||
int local, *flag;
|
||||
|
||||
if (wp == active_get_effective_window(c, c->session)->active) {
|
||||
w = active_get_effective_window(c, c->session);
|
||||
active = active_get_effective_pane(c, w);
|
||||
local = (wp == active && active_has_local_pane(c, wp->window));
|
||||
if (wp == active) {
|
||||
flag = &wp->active_border_gc_set;
|
||||
saved = &wp->active_border_gc;
|
||||
option = "pane-active-border-style";
|
||||
@@ -103,6 +108,13 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
|
||||
option = "pane-border-style";
|
||||
}
|
||||
|
||||
if (local) {
|
||||
ft = format_create_defaults(NULL, c, s, s->curw, wp);
|
||||
style_apply(gc, wp->options, option, ft);
|
||||
format_free(ft);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!*flag) {
|
||||
ft = format_create_defaults(NULL, c, s, NULL, wp);
|
||||
style_apply(saved, wp->options, option, ft);
|
||||
|
||||
5
window.c
5
window.c
@@ -795,7 +795,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
|
||||
break;
|
||||
|
||||
/* If the pane is floating, move to the front. */
|
||||
if (window_pane_is_floating(wp)) {
|
||||
if (window_pane_is_floating(wp) &&
|
||||
TAILQ_FIRST(&w->z_index) != wp) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
@@ -2578,7 +2579,7 @@ window_pane_get_bg(struct window_pane *wp)
|
||||
|
||||
c = window_pane_get_bg_control_client(wp);
|
||||
if (c == -1) {
|
||||
tty_default_colours(&defaults, wp, NULL);
|
||||
tty_default_colours(&defaults, wp, wp->window->active, NULL);
|
||||
if (COLOUR_DEFAULT(defaults.bg))
|
||||
c = window_get_bg_client(wp);
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user