mirror of
https://github.com/tmux/tmux.git
synced 2026-09-18 19:14:47 +00:00
Compare commits
31 Commits
issue-5510
...
local_wind
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3f8598903 | ||
|
|
9b0ad73a4b | ||
|
|
bd8218e85d | ||
|
|
8f3101d820 | ||
|
|
77309c07b0 | ||
|
|
c8e889694d | ||
|
|
b402687fcd | ||
|
|
0530a7d89a | ||
|
|
6bdb9ba54c | ||
|
|
f2bfd611e2 | ||
|
|
9c1d5a080b | ||
|
|
b28244e2fe | ||
|
|
8b3834c34f | ||
|
|
af3e4d2e5b | ||
|
|
c552d1bf16 | ||
|
|
6a1ecdcce3 | ||
|
|
39357c829c | ||
|
|
40381bdcd9 | ||
|
|
7bad4f7722 | ||
|
|
65e811570b | ||
|
|
dd31900f80 | ||
|
|
013ada58c8 | ||
|
|
78dad45f3b | ||
|
|
52b452948f | ||
|
|
267746603a | ||
|
|
b26b240613 | ||
|
|
8e48c889dd | ||
|
|
1b86039df3 | ||
|
|
ff9c89da0c | ||
|
|
fde879c347 | ||
|
|
38808509d5 |
3
.github/workflows/lock.yml
vendored
3
.github/workflows/lock.yml
vendored
@@ -17,8 +17,9 @@ jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'tmux/tmux'
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v6
|
||||
- uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '30'
|
||||
|
||||
6
.github/workflows/regress.yml
vendored
6
.github/workflows/regress.yml
vendored
@@ -38,7 +38,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: dependencies
|
||||
if: runner.os == 'Linux'
|
||||
@@ -81,7 +83,7 @@ jobs:
|
||||
|
||||
- name: logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: regress-logs-${{ matrix.name }}
|
||||
path: regress/logs/*.log
|
||||
|
||||
@@ -85,6 +85,7 @@ endif
|
||||
|
||||
# List of sources.
|
||||
dist_tmux_SOURCES = \
|
||||
active.c \
|
||||
alerts.c \
|
||||
arguments.c \
|
||||
attributes.c \
|
||||
|
||||
737
active.c
Normal file
737
active.c
Normal file
@@ -0,0 +1,737 @@
|
||||
/* $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;
|
||||
}
|
||||
}
|
||||
2
alerts.c
2
alerts.c
@@ -314,7 +314,7 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
|
||||
tty_putcode(&c->tty, TTYC_BEL);
|
||||
if (visual == VISUAL_OFF)
|
||||
continue;
|
||||
if (c->session->curw == wl) {
|
||||
if (active_get_effective_winlink(c, c->session) == wl) {
|
||||
status_message_set(c, -1, 1, 0, 0,
|
||||
"%s in current window", type);
|
||||
} else {
|
||||
|
||||
@@ -93,7 +93,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
if (wl != NULL) {
|
||||
if (wp != NULL)
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
session_set_current(s, wl);
|
||||
active_select_window(c, s, wl);
|
||||
if (wp != NULL)
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
else
|
||||
|
||||
@@ -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 *target = cmdq_get_target(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 winlink *wl = source->wl;
|
||||
struct winlink *current_wl;
|
||||
struct session *src_s = source->s;
|
||||
struct session *dst_s = target->s;
|
||||
struct window_pane *wp = source->wp;
|
||||
struct window *w = wl->window, *old_w = w;
|
||||
char *cause, *cp;
|
||||
int idx = target->idx, before, old_idx = wl->idx;
|
||||
int detached, local;
|
||||
const char *template, *name = args_get(args, 'n');
|
||||
|
||||
if (wp == w->modal) {
|
||||
@@ -117,11 +121,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
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 (target->wl != NULL)
|
||||
idx = winlink_shuffle_up(dst_s, target->wl, before);
|
||||
else
|
||||
idx = winlink_shuffle_up(dst_s, dst_s->curw, before);
|
||||
else {
|
||||
current_wl = active_get_effective_winlink(ac, dst_s);
|
||||
idx = winlink_shuffle_up(dst_s, current_wl, before);
|
||||
}
|
||||
if (idx == -1)
|
||||
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 (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);
|
||||
free(cause);
|
||||
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);
|
||||
if (wl == NULL)
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
@@ -185,9 +203,17 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
window_remove_ref(w, __func__);
|
||||
events_fire_window("window-created", w);
|
||||
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
|
||||
if (!args_has(args, 'd')) {
|
||||
session_select(dst_s, wl->idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
if (!detached) {
|
||||
if (local)
|
||||
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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.52 2026/07/14 19:07:03 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.53 2026/08/31 07:46:55 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -483,7 +483,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *title, *cause = NULL;
|
||||
int flags = 0, starting_choice = 0;
|
||||
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;
|
||||
|
||||
if (args_has(args, 'C')) {
|
||||
@@ -584,13 +584,15 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
u_int px, py, w, h, count = args_count(args);
|
||||
struct args_value *av;
|
||||
struct environ *env = NULL;
|
||||
struct options *o = s->curw->window->options;
|
||||
struct options *o = target->w->options;
|
||||
struct options_entry *oe;
|
||||
|
||||
if (args_has(args, 'C')) {
|
||||
server_client_clear_overlay(tc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (tc->flags & CLIENT_CONTROL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (!modify && tc->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
|
||||
84
cmd-find.c
84
cmd-find.c
@@ -884,13 +884,13 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
|
||||
if (c->session != NULL) {
|
||||
cmd_find_clear_state(fs, flags);
|
||||
|
||||
fs->wp = c->session->curw->window->active;
|
||||
fs->wl = active_get_effective_winlink(c, c->session);
|
||||
fs->wp = active_get_effective_pane(c, fs->wl->window);
|
||||
if (fs->wp == NULL) {
|
||||
cmd_find_from_session(fs, c->session, flags);
|
||||
return (0);
|
||||
}
|
||||
fs->s = c->session;
|
||||
fs->wl = fs->s->curw;
|
||||
fs->w = fs->wl->window;
|
||||
|
||||
cmd_find_log_state(__func__, fs);
|
||||
@@ -931,6 +931,57 @@ unknown_pane:
|
||||
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
|
||||
* 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,
|
||||
const char *target, enum cmd_find_type type, int flags)
|
||||
{
|
||||
struct mouse_event *m;
|
||||
struct client *c;
|
||||
struct cmd_find_state current;
|
||||
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");
|
||||
goto error;
|
||||
}
|
||||
fs->wl = c->session->curw;
|
||||
fs->wp = c->session->curw->window->active;
|
||||
fs->w = c->session->curw->window;
|
||||
fs->wl = active_get_effective_winlink(c, c->session);
|
||||
fs->wp = fs->wl->window->active;
|
||||
fs->w = fs->wl->window;
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Mouse target is a plain = or {mouse}. */
|
||||
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
|
||||
m = &cmdq_get_event(item)->m;
|
||||
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 (cmd_find_target_from_mouse(fs, item, type) != 0) {
|
||||
if (~flags & CMD_FIND_QUIET)
|
||||
cmdq_error(item, "no mouse target");
|
||||
goto error;
|
||||
|
||||
@@ -413,13 +413,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 *target = cmdq_get_target(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 winlink *src_wl, *dst_wl;
|
||||
struct window *src_w, *dst_w;
|
||||
struct window_pane *src_wp, *dst_wp;
|
||||
const char *s;
|
||||
char *cause = NULL;
|
||||
int flags = 0, dst_idx;
|
||||
int flags = 0, dst_idx, local;
|
||||
struct layout_cell *lc;
|
||||
|
||||
dst_s = target->s;
|
||||
@@ -427,6 +430,10 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
dst_wp = target->wp;
|
||||
dst_w = dst_wl->window;
|
||||
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 (args_has(args, 'M'))
|
||||
@@ -512,9 +519,18 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (!args_has(args, 'd')) {
|
||||
window_set_active_pane(dst_w, src_wp, 1);
|
||||
session_select(dst_s, dst_idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
server_redraw_session(dst_s);
|
||||
if (local)
|
||||
active_select_window(ac, dst_s, dst_wl);
|
||||
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
|
||||
server_status_session(dst_s);
|
||||
|
||||
|
||||
@@ -62,12 +62,15 @@ cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *source = cmdq_get_source(item);
|
||||
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');
|
||||
struct session *src = source->s;
|
||||
struct session *dst;
|
||||
struct winlink *wl = source->wl;
|
||||
struct winlink *wl = source->wl, *dstwl, *current_wl;
|
||||
char *cause;
|
||||
int idx, kflag, dflag, sflag, before;
|
||||
int idx, kflag, dflag, sflag, before, local;
|
||||
|
||||
if (args_has(args, 'r')) {
|
||||
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');
|
||||
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');
|
||||
if (args_has(args, 'a') || before) {
|
||||
if (target.wl != NULL)
|
||||
idx = winlink_shuffle_up(dst, target.wl, before);
|
||||
else
|
||||
idx = winlink_shuffle_up(dst, dst->curw, before);
|
||||
else {
|
||||
current_wl = active_get_effective_winlink(ac, dst);
|
||||
idx = winlink_shuffle_up(dst, current_wl, before);
|
||||
}
|
||||
if (idx == -1)
|
||||
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);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
dstwl = winlink_find_by_window(&dst->windows, wl->window);
|
||||
if (cmd_get_entry(self) == &cmd_move_window_entry)
|
||||
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
|
||||
|
||||
@@ -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 spawn_context sc = { 0 };
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct client *ac;
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl, *new_wl = NULL;
|
||||
int idx = target->idx, before, count = args_count(args);
|
||||
int detached, local;
|
||||
char *cause = NULL, *cp, *expanded, *wname = NULL;
|
||||
const char *template, *name;
|
||||
struct cmd_find_state fs;
|
||||
@@ -107,10 +109,15 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(wname);
|
||||
if (args_has(args, 'd'))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (session_set_current(s, new_wl) == 0)
|
||||
server_redraw_session(s);
|
||||
if (active_select_window(c, s, new_wl) == 0) {
|
||||
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)
|
||||
s->curw->window->latest = c;
|
||||
active_get_effective_window(c, s)->latest = c;
|
||||
recalculate_sizes();
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -140,10 +147,16 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.idx = idx;
|
||||
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;
|
||||
if (args_has(args, 'E') || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'd'))
|
||||
if (detached || local)
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
@@ -153,7 +166,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
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);
|
||||
server_redraw_session_group(s);
|
||||
} else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-parse.y,v 1.58 2026/04/27 12:31:11 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-parse.y,v 1.59 2026/08/31 07:51:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -802,6 +802,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||
if (last == NULL) {
|
||||
pr->status = CMD_PARSE_SUCCESS;
|
||||
pr->cmdlist = cmd_list_new();
|
||||
cmd_parse_free_commands(cmds);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -814,6 +815,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||
pi->flags |= CMD_PARSE_NOALIAS;
|
||||
cmd_parse_build_commands(cmds, pi, pr);
|
||||
pi->flags &= ~CMD_PARSE_NOALIAS;
|
||||
cmd_parse_free_commands(cmds);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'c'))
|
||||
tc->pan_window = NULL;
|
||||
else {
|
||||
w = tc->session->curw->window;
|
||||
w = active_get_effective_window(tc, tc->session);
|
||||
if (tc->pan_window != w) {
|
||||
tc->pan_window = w;
|
||||
tc->pan_ox = tty->oox;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.67 2026/07/10 13:38:45 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.68 2026/08/31 07:44:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -92,6 +92,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
server_unzoom_window(w);
|
||||
lc = wp->layout_cell; /* may have been replaced by unzoom */
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause);
|
||||
|
||||
@@ -79,7 +79,10 @@ 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 = cdata->client;
|
||||
struct session *s;
|
||||
struct window_pane *wp = NULL;
|
||||
struct window *w;
|
||||
struct cmd_find_state fs;
|
||||
struct window_mode_entry *wme;
|
||||
|
||||
@@ -90,8 +93,11 @@ cmd_run_shell_print(struct job *job, const char *msg)
|
||||
cmdq_print(cdata->item, "%s", msg);
|
||||
return;
|
||||
}
|
||||
if (cdata->client != NULL && cdata->client->session != NULL)
|
||||
wp = cdata->client->session->curw->window->active;
|
||||
if (c != NULL && c->session != NULL) {
|
||||
s = c->session;
|
||||
w = active_get_effective_window(c, s);
|
||||
wp = active_get_effective_pane(c, w);
|
||||
}
|
||||
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
|
||||
wp = fs.wp;
|
||||
if (wp == NULL)
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -68,10 +68,11 @@ cmd_select_pane_redraw(struct window *w)
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
|
||||
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);
|
||||
else {
|
||||
if (c->session->curw->window == w)
|
||||
if (active_get_effective_window(c, c->session) == w)
|
||||
c->flags |= CLIENT_REDRAWBORDERS;
|
||||
if (session_has(c->session, w))
|
||||
c->flags |= CLIENT_REDRAWSTATUS;
|
||||
@@ -84,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;
|
||||
@@ -137,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);
|
||||
}
|
||||
@@ -152,26 +155,40 @@ 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;
|
||||
int visible, Zflag = args_has(args, 'Z');
|
||||
|
||||
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");
|
||||
@@ -192,8 +209,9 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
visible = window_pane_is_visible(lastwp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
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);
|
||||
}
|
||||
@@ -271,7 +289,8 @@ 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 (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
@@ -279,8 +298,9 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
visible = window_pane_is_visible(wp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
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);
|
||||
|
||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_window_entry = {
|
||||
.name = "select-window",
|
||||
.alias = "selectw",
|
||||
|
||||
.args = { "lnpTt:", 0, 0, NULL },
|
||||
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
|
||||
.args = { "LlSnpTt:", 0, 0, NULL },
|
||||
.usage = "[-LlnpST] " CMD_TARGET_WINDOW_USAGE,
|
||||
|
||||
.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 cmd_find_state *current = cmdq_get_current(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;
|
||||
enum active_mode mode;
|
||||
int next, previous, last, activity;
|
||||
|
||||
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'))
|
||||
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) {
|
||||
activity = args_has(args, 'a');
|
||||
if (next) {
|
||||
if (session_next(s, activity) != 0) {
|
||||
if (active_next_window(c, s, activity) != 0) {
|
||||
cmdq_error(item, "no next window");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else if (previous) {
|
||||
if (session_previous(s, activity) != 0) {
|
||||
if (active_previous_window(c, s, activity) != 0) {
|
||||
cmdq_error(item, "no previous window");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else {
|
||||
if (session_last(s) != 0) {
|
||||
if (active_last_window(c, s) != 0) {
|
||||
cmdq_error(item, "no last window");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
cmd_find_from_session(current, s, 0);
|
||||
server_redraw_session(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);
|
||||
cmdq_insert_hook(s, item, current, "after-select-window");
|
||||
} else {
|
||||
/*
|
||||
* If -T and select-window is invoked on same window as
|
||||
* current, switch to previous window.
|
||||
*/
|
||||
if (args_has(args, 'T') && wl == s->curw) {
|
||||
if (session_last(s) != 0) {
|
||||
current_wl = active_get_effective_winlink(c, s);
|
||||
if (args_has(args, 'T') && wl == current_wl) {
|
||||
if (active_last_window(c, s) != 0) {
|
||||
cmdq_error(item, "no last window");
|
||||
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);
|
||||
server_redraw_session(s);
|
||||
} else if (session_select(s, wl->idx) == 0) {
|
||||
cmd_find_from_session(current, s, 0);
|
||||
server_redraw_session(s);
|
||||
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");
|
||||
}
|
||||
if (c != NULL && c->session != NULL)
|
||||
s->curw->window->latest = c;
|
||||
active_get_effective_window(c, s)->latest = c;
|
||||
recalculate_sizes();
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -48,10 +48,14 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *source = cmdq_get_source(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_group *sg_src, *sg_dst;
|
||||
struct winlink *wl_src = source->wl, *wl_dst = target->wl;
|
||||
struct window *w_src, *w_dst;
|
||||
int local_src, local_dst;
|
||||
|
||||
sg_src = session_group_contains(src);
|
||||
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)
|
||||
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')) {
|
||||
session_select(dst, wl_dst->idx);
|
||||
if (src != dst)
|
||||
session_select(src, wl_src->idx);
|
||||
if (local_dst)
|
||||
active_select_window(ac, dst, wl_dst);
|
||||
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);
|
||||
server_redraw_session_group(src);
|
||||
|
||||
@@ -53,11 +53,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state target;
|
||||
const char *tflag = args_get(args, 't');
|
||||
enum cmd_find_type type;
|
||||
int flags, visible, Zflag = args_has(args, 'Z');
|
||||
int flags, visible, window_target;
|
||||
int Zflag = args_has(args, 'Z');
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct winlink *wl, *current_wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
const char *tablename;
|
||||
@@ -65,8 +66,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct sort_criteria sort_crit;
|
||||
uid_t uid;
|
||||
|
||||
if (tflag != NULL &&
|
||||
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) {
|
||||
window_target = 0;
|
||||
if (tflag != NULL) {
|
||||
if (tflag[strcspn(tflag, ":.%")] != '\0' ||
|
||||
strcmp(tflag, "=") == 0)
|
||||
window_target = 1;
|
||||
}
|
||||
if (window_target) {
|
||||
type = CMD_FIND_PANE;
|
||||
flags = 0;
|
||||
} else {
|
||||
@@ -137,7 +143,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
} else {
|
||||
if (cmdq_get_client(item) == NULL)
|
||||
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;
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
@@ -150,9 +157,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
}
|
||||
if (wl != NULL) {
|
||||
session_set_current(s, wl);
|
||||
cmd_find_from_session(current, s, 0);
|
||||
if (window_target && wl != NULL) {
|
||||
active_select_window(tc, s, wl);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,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. */
|
||||
static void
|
||||
control_client_detached_cb(__unused const char *name, struct event_payload *ep,
|
||||
@@ -359,6 +381,7 @@ control_build_events(void)
|
||||
{ "window-linked", control_window_linked_cb },
|
||||
{ "window-renamed", control_window_renamed_cb },
|
||||
{ "client-session-changed", control_client_session_changed_cb },
|
||||
{ "client-window-changed", control_client_window_changed_cb },
|
||||
{ "client-detached", control_client_detached_cb },
|
||||
{ "session-renamed", control_session_renamed_cb },
|
||||
{ "session-created", control_session_created_cb },
|
||||
|
||||
196
format.c
196
format.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: format.c,v 1.413 2026/08/24 07:26:43 nicm Exp $ */
|
||||
/* $OpenBSD: format.c,v 1.415 2026/08/31 19:34:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -806,7 +806,7 @@ format_cb_window_active_clients(struct format_tree *ft)
|
||||
if (client_session == NULL)
|
||||
continue;
|
||||
|
||||
if (w == client_session->curw->window)
|
||||
if (w == active_get_effective_window(loop, client_session))
|
||||
n++;
|
||||
}
|
||||
|
||||
@@ -838,7 +838,7 @@ format_cb_window_active_clients_list(struct format_tree *ft)
|
||||
if (client_session == NULL)
|
||||
continue;
|
||||
|
||||
if (w == client_session->curw->window) {
|
||||
if (w == active_get_effective_window(loop, client_session)) {
|
||||
if (EVBUFFER_LENGTH(buffer) > 0)
|
||||
evbuffer_add(buffer, ",", 1);
|
||||
evbuffer_add_printf(buffer, "%s", loop->name);
|
||||
@@ -1067,7 +1067,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)));
|
||||
}
|
||||
|
||||
@@ -1118,7 +1119,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)));
|
||||
}
|
||||
|
||||
@@ -1887,6 +1889,37 @@ format_cb_cursor_blinking(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_added. */
|
||||
static void *
|
||||
format_cb_history_added(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL)
|
||||
return (format_printf("%u", ft->wp->base.grid->scroll_added));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_collected. */
|
||||
static void *
|
||||
format_cb_history_collected(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%u", wp->base.grid->scroll_collected));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_generation. */
|
||||
static void *
|
||||
format_cb_history_generation(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%u", wp->base.grid->scroll_generation));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_limit. */
|
||||
static void *
|
||||
format_cb_history_limit(struct format_tree *ft)
|
||||
@@ -2159,14 +2192,45 @@ format_cb_pane_private_modes(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)
|
||||
@@ -2276,6 +2340,19 @@ format_cb_pane_last_output_time(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_output_generation. */
|
||||
static void *
|
||||
format_cb_pane_output_generation(struct format_tree *ft)
|
||||
{
|
||||
unsigned long long value;
|
||||
|
||||
if (ft->wp != NULL) {
|
||||
value = ft->wp->output_generation;
|
||||
return (format_printf("%llu", value));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_prompt_time. */
|
||||
static void *
|
||||
format_cb_pane_last_prompt_time(struct format_tree *ft)
|
||||
@@ -2445,7 +2522,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"));
|
||||
}
|
||||
@@ -3022,11 +3099,48 @@ format_cb_sixel_support(__unused struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_active_window_index(struct format_tree *ft)
|
||||
{
|
||||
if (ft->s != NULL)
|
||||
return (format_printf("%u", ft->s->curw->idx));
|
||||
struct winlink *wl;
|
||||
|
||||
if (ft->s != NULL) {
|
||||
wl = active_get_effective_winlink(ft->c, ft->s);
|
||||
if (wl != NULL)
|
||||
return (format_printf("%u", wl->idx));
|
||||
}
|
||||
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. */
|
||||
static void *
|
||||
format_cb_last_window_index(struct format_tree *ft)
|
||||
@@ -3044,8 +3158,11 @@ format_cb_last_window_index(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_window_active(struct format_tree *ft)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
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("0"));
|
||||
}
|
||||
@@ -3125,7 +3242,7 @@ static void *
|
||||
format_cb_window_flags(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wl != NULL)
|
||||
return (xstrdup(window_printable_flags(ft->wl, 1)));
|
||||
return (xstrdup(window_printable_flags(ft->c, ft->wl, 1)));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -3312,7 +3429,7 @@ static void *
|
||||
format_cb_window_raw_flags(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wl != NULL)
|
||||
return (xstrdup(window_printable_flags(ft->wl, 0)));
|
||||
return (xstrdup(window_printable_flags(ft->c, ft->wl, 0)));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -3522,9 +3639,15 @@ struct format_table_entry {
|
||||
* Only variables which are added by the caller go into the tree.
|
||||
*/
|
||||
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,
|
||||
format_cb_active_window_index
|
||||
},
|
||||
{ "active_window_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_active_window_mode
|
||||
},
|
||||
{ "alternate_on", FORMAT_TABLE_STRING,
|
||||
format_cb_alternate_on
|
||||
},
|
||||
@@ -3663,12 +3786,21 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "cursor_y", FORMAT_TABLE_STRING,
|
||||
format_cb_cursor_y
|
||||
},
|
||||
{ "history_added", FORMAT_TABLE_STRING,
|
||||
format_cb_history_added
|
||||
},
|
||||
{ "history_all_bytes", FORMAT_TABLE_STRING,
|
||||
format_cb_history_all_bytes
|
||||
},
|
||||
{ "history_bytes", FORMAT_TABLE_STRING,
|
||||
format_cb_history_bytes
|
||||
},
|
||||
{ "history_collected", FORMAT_TABLE_STRING,
|
||||
format_cb_history_collected
|
||||
},
|
||||
{ "history_generation", FORMAT_TABLE_STRING,
|
||||
format_cb_history_generation
|
||||
},
|
||||
{ "history_limit", FORMAT_TABLE_STRING,
|
||||
format_cb_history_limit
|
||||
},
|
||||
@@ -3693,6 +3825,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "last_window_index", FORMAT_TABLE_STRING,
|
||||
format_cb_last_window_index
|
||||
},
|
||||
{ "local_active_window", FORMAT_TABLE_STRING,
|
||||
format_cb_local_active_window
|
||||
},
|
||||
{ "mouse_all_flag", FORMAT_TABLE_STRING,
|
||||
format_cb_mouse_all_flag
|
||||
},
|
||||
@@ -3837,6 +3972,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
|
||||
},
|
||||
@@ -3849,6 +3990,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_mode
|
||||
},
|
||||
{ "pane_output_generation", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_output_generation
|
||||
},
|
||||
{ "pane_path", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_path
|
||||
},
|
||||
@@ -5239,15 +5383,18 @@ format_add_window_neighbour(struct format_tree *nft, struct winlink *wl,
|
||||
struct session *s, const char *prefix)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct winlink *current;
|
||||
const char *oname;
|
||||
char *key, *prefixed, *oval;
|
||||
|
||||
current = active_get_effective_winlink(nft->c, s);
|
||||
|
||||
xasprintf(&key, "%s_window_index", prefix);
|
||||
format_add(nft, key, "%u", wl->idx);
|
||||
free(key);
|
||||
|
||||
xasprintf(&key, "%s_window_active", prefix);
|
||||
format_add(nft, key, "%d", wl == s->curw);
|
||||
format_add(nft, key, "%d", wl == current);
|
||||
free(key);
|
||||
|
||||
o = options_first(wl->window->options);
|
||||
@@ -5275,10 +5422,10 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
char *all, *active_fmt, *use, *expanded, *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
struct winlink *wl, **l;
|
||||
struct winlink *wl, **l, *active_wl;
|
||||
struct window *w;
|
||||
int i, n;
|
||||
|
||||
@@ -5287,9 +5434,9 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
||||
if (format_choose(es, fmt, &all, &active_fmt, 0) != 0) {
|
||||
all = xstrdup(fmt);
|
||||
active = NULL;
|
||||
active_fmt = NULL;
|
||||
}
|
||||
|
||||
buffer = evbuffer_new();
|
||||
@@ -5297,12 +5444,13 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
fatalx("out of memory");
|
||||
|
||||
l = sort_get_winlinks_session(s, &n, sc);
|
||||
active_wl = active_get_effective_winlink(ft->c, s);
|
||||
for (i = 0; i < n; i++) {
|
||||
wl = l[i];
|
||||
w = wl->window;
|
||||
format_log(es, "window loop: %u @%u", wl->idx, w->id);
|
||||
if (active != NULL && wl == s->curw)
|
||||
use = active;
|
||||
if (active_fmt != NULL && wl == active_wl)
|
||||
use = active_fmt;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
|
||||
@@ -5311,11 +5459,11 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
/* 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");
|
||||
else
|
||||
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");
|
||||
else
|
||||
format_add(nft, "window_before_active", "0");
|
||||
@@ -5335,7 +5483,7 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
free(active);
|
||||
free(active_fmt);
|
||||
free(all);
|
||||
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
@@ -6923,9 +7071,9 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
|
||||
if (s == NULL && c != NULL)
|
||||
s = c->session;
|
||||
if (wl == NULL && s != NULL)
|
||||
wl = s->curw;
|
||||
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);
|
||||
|
||||
38
grid.c
38
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: grid.c,v 1.156 2026/08/03 12:58:53 nicm Exp $ */
|
||||
/* $OpenBSD: grid.c,v 1.158 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1635,7 +1635,7 @@ grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
|
||||
void
|
||||
grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
|
||||
{
|
||||
u_int yy, ay = 0;
|
||||
u_int yy, ay = 0, ey = gd->hsize + gd->sy - 1;
|
||||
|
||||
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
|
||||
if (ay == wy)
|
||||
@@ -1649,7 +1649,7 @@ grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
|
||||
* until we find the end or the line now containing wx.
|
||||
*/
|
||||
if (wx == UINT_MAX) {
|
||||
while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
|
||||
while (yy < ey && gd->linedata[yy].flags & GRID_LINE_WRAPPED)
|
||||
yy++;
|
||||
wx = gd->linedata[yy].cellused;
|
||||
} else {
|
||||
@@ -1711,21 +1711,29 @@ grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
|
||||
{
|
||||
struct grid_cell gc, tmp_gc;
|
||||
u_int pxx;
|
||||
int has_tab, has_space;
|
||||
|
||||
has_tab = (strchr(set, '\t') != NULL);
|
||||
has_space = (strchr(set, ' ') != NULL);
|
||||
|
||||
grid_get_cell(gd, px, py, &gc);
|
||||
if (strchr(set, '\t')) {
|
||||
if (gc.flags & GRID_FLAG_PADDING) {
|
||||
pxx = px;
|
||||
do
|
||||
grid_get_cell(gd, --pxx, py, &tmp_gc);
|
||||
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
|
||||
if (tmp_gc.flags & GRID_FLAG_TAB)
|
||||
return (tmp_gc.data.width - (px - pxx));
|
||||
} else if (gc.flags & GRID_FLAG_TAB)
|
||||
return (gc.data.width);
|
||||
}
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
if (gc.flags & GRID_FLAG_PADDING) {
|
||||
if (!has_tab && !has_space)
|
||||
return (0);
|
||||
pxx = px;
|
||||
do
|
||||
grid_get_cell(gd, --pxx, py, &tmp_gc);
|
||||
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
|
||||
if (((has_tab || has_space) &&
|
||||
(tmp_gc.flags & GRID_FLAG_TAB)) ||
|
||||
(has_space && utf8_has_whitespace(&tmp_gc.data)))
|
||||
return (tmp_gc.data.width - (px - pxx));
|
||||
return (0);
|
||||
}
|
||||
if ((has_tab || has_space) && (gc.flags & GRID_FLAG_TAB))
|
||||
return (gc.data.width);
|
||||
if (has_space && utf8_has_whitespace(&gc.data))
|
||||
return (gc.data.width == 0 ? 1 : gc.data.width);
|
||||
return (utf8_cstrhas(set, &gc.data));
|
||||
}
|
||||
|
||||
|
||||
6
input.c
6
input.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: input.c,v 1.270 2026/08/17 20:04:00 nicm Exp $ */
|
||||
/* $OpenBSD: input.c,v 1.271 2026/08/31 19:34:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1049,6 +1049,7 @@ input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len)
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
wp->output_generation++;
|
||||
window_update_activity(wp->window);
|
||||
if (~wp->flags & PANE_ACTIVITY) {
|
||||
wp->flags |= PANE_ACTIVITY;
|
||||
@@ -3077,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
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
" 'Rename' 'r' {command-prompt -I '#S' {rename-session -- '%%'}}" \
|
||||
" '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 Window' 'w' {new-window}"
|
||||
#define DEFAULT_WINDOW_MENU \
|
||||
@@ -72,6 +74,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}" \
|
||||
@@ -503,6 +507,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 } }",
|
||||
@@ -524,6 +529,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 }",
|
||||
|
||||
39
layout.c
39
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: layout.c,v 1.97 2026/08/20 09:19:24 nicm Exp $ */
|
||||
/* $OpenBSD: layout.c,v 1.98 2026/08/25 18:38:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -539,6 +539,10 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
|
||||
status = window_get_pane_status(w);
|
||||
|
||||
/* Floating cells do not take space from the tiled layout. */
|
||||
if (!layout_cell_is_tiled(lc) && !layout_cell_has_tiled_child(lc))
|
||||
return (0);
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||
/* Space available in this cell only. */
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
@@ -568,6 +572,9 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
/* Different type: minimum of available space in child cells. */
|
||||
minimum = UINT_MAX;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_cell_is_tiled(lcchild) &&
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
available = layout_resize_check(w, lcchild, type);
|
||||
if (available < minimum)
|
||||
minimum = available;
|
||||
@@ -661,7 +668,7 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
|
||||
|
||||
/* Find and return the nearest neighbour to a cell in a specific direction. */
|
||||
static struct layout_cell *
|
||||
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
||||
layout_cell_get_neighbour_dir(struct layout_cell *lc, int direction)
|
||||
{
|
||||
struct layout_cell *lcn = lc;
|
||||
|
||||
@@ -695,9 +702,9 @@ layout_cell_get_neighbour(struct layout_cell *lc)
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
direction = !direction;
|
||||
|
||||
lcother = layout_cell_get_neighbour_direction(lc, direction);
|
||||
lcother = layout_cell_get_neighbour_dir(lc, direction);
|
||||
if (lcother == NULL)
|
||||
lcother = layout_cell_get_neighbour_direction(lc, !direction);
|
||||
lcother = layout_cell_get_neighbour_dir(lc, !direction);
|
||||
|
||||
return (lcother);
|
||||
}
|
||||
@@ -860,7 +867,7 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
size = lc->g.sx;
|
||||
else
|
||||
size = lc->g.sy;
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
if (layout_cell_is_last_tiled(lc))
|
||||
change = size - new_size;
|
||||
else
|
||||
change = new_size - size;
|
||||
@@ -985,11 +992,11 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
|
||||
if (lcparent == NULL)
|
||||
return;
|
||||
|
||||
/* If this is the last cell, move back one. */
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) {
|
||||
do
|
||||
lc = TAILQ_PREV(lc, layout_cells, entry);
|
||||
while (lc->flags & LAYOUT_CELL_FLOATING);
|
||||
/* If this is the last tiled cell, move back one. */
|
||||
if (layout_cell_is_last_tiled(lc)) {
|
||||
lc = layout_cell_get_neighbour_dir(lc, 0);
|
||||
if (lc == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
layout_resize_layout(wp->window, lc, type, change, opposite);
|
||||
@@ -1007,22 +1014,22 @@ layout_resize_pane_grow(struct window *w, struct layout_cell *lc,
|
||||
lcadd = lc;
|
||||
|
||||
/* Look towards the tail for a suitable cell for reduction. */
|
||||
lcremove = TAILQ_NEXT(lc, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lc, 1);
|
||||
while (lcremove != NULL) {
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size > 0)
|
||||
break;
|
||||
lcremove = TAILQ_NEXT(lcremove, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 1);
|
||||
}
|
||||
|
||||
/* If none found, look towards the head. */
|
||||
if (opposite && lcremove == NULL) {
|
||||
lcremove = TAILQ_PREV(lc, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lc, 0);
|
||||
while (lcremove != NULL) {
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size > 0)
|
||||
break;
|
||||
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 0);
|
||||
}
|
||||
}
|
||||
if (lcremove == NULL)
|
||||
@@ -1050,13 +1057,13 @@ layout_resize_pane_shrink(struct window *w, struct layout_cell *lc,
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size != 0)
|
||||
break;
|
||||
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 0);
|
||||
} while (lcremove != NULL);
|
||||
if (lcremove == NULL)
|
||||
return (0);
|
||||
|
||||
/* And add onto the next cell (from the original cell). */
|
||||
lcadd = TAILQ_NEXT(lc, entry);
|
||||
lcadd = layout_cell_get_neighbour_dir(lc, 1);
|
||||
if (lcadd == NULL)
|
||||
return (0);
|
||||
|
||||
|
||||
2
menu.c
2
menu.c
@@ -586,7 +586,7 @@ menu_display(struct menu *menu, int flags, int starting_choice,
|
||||
struct options *o;
|
||||
|
||||
if (fs == NULL)
|
||||
w = c->session->curw->window;
|
||||
w = active_get_effective_window(c, c->session);
|
||||
else
|
||||
w = fs->w;
|
||||
o = w->options;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: options-table.c,v 1.243 2026/08/25 08:37:08 nicm Exp $ */
|
||||
/* $OpenBSD: options-table.c,v 1.244 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1125,7 +1125,8 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "status-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.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,
|
||||
.separator = ",",
|
||||
.text = "Style of the status line."
|
||||
@@ -1250,7 +1251,8 @@ const struct options_table_entry options_table[] = {
|
||||
* underscore.
|
||||
*/
|
||||
.default_str = "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~",
|
||||
.text = "Characters considered to separate words."
|
||||
.text = "Characters considered to separate words; a space matches "
|
||||
"any character with the Unicode White_Space property."
|
||||
},
|
||||
|
||||
/* Window options. */
|
||||
@@ -1552,8 +1554,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."
|
||||
@@ -1981,6 +1984,8 @@ const struct options_table_entry options_table[] = {
|
||||
"Run when a client is resized."),
|
||||
OPTIONS_TABLE_HOOK("client-session-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", "",
|
||||
"Run when a client switches to a light theme."),
|
||||
OPTIONS_TABLE_HOOK("client-dark-theme", "",
|
||||
|
||||
13
popup.c
13
popup.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: popup.c,v 1.76 2026/07/14 19:07:03 nicm Exp $ */
|
||||
/* $OpenBSD: popup.c,v 1.77 2026/08/28 08:02:16 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -79,7 +79,8 @@ popup_free(struct popup_data *pd)
|
||||
|
||||
if (pd->job != NULL)
|
||||
job_free(pd->job);
|
||||
input_free(pd->ictx);
|
||||
if (pd->ictx != NULL)
|
||||
input_free(pd->ictx);
|
||||
|
||||
free(pd->r.ranges);
|
||||
screen_free(&pd->s);
|
||||
@@ -102,9 +103,9 @@ popup_reapply_styles(struct popup_data *pd)
|
||||
|
||||
if (s == NULL)
|
||||
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. */
|
||||
memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults);
|
||||
@@ -569,9 +570,9 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
struct style sytmp;
|
||||
|
||||
if (s != NULL)
|
||||
o = s->curw->window->options;
|
||||
o = active_get_effective_window(c, s)->options;
|
||||
else
|
||||
o = c->session->curw->window->options;
|
||||
o = active_get_effective_window(c, c->session)->options;
|
||||
|
||||
if (lines == BOX_LINES_DEFAULT)
|
||||
lines = options_get_number(o, "popup-border-lines");
|
||||
|
||||
151
regress/active-window.sh
Normal file
151
regress/active-window.sh
Normal 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
|
||||
@@ -28,7 +28,7 @@ $TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
TMP2=$(mktemp)
|
||||
trap 'rm -f "$TMP" "$TMP2"; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
trap 'rm -f "$TMP" "$TMP2" "$TMP".*; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
# check_ok $cmd...
|
||||
#
|
||||
@@ -270,6 +270,27 @@ if [ $? -eq 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# A write error after a successful open must be reported to the server.
|
||||
dd if=/dev/zero of="$TMP.big" bs=100000 count=1 2>/dev/null
|
||||
check_ok load-buffer -b write-error "$TMP.big"
|
||||
mkfifo "$TMP.fifo" || exit 1
|
||||
dd if="$TMP.fifo" of="$TMP.got" bs=1 count=8 2>/dev/null &
|
||||
reader=$!
|
||||
exec 3>"$TMP.fifo"
|
||||
out=$($TMUX save-buffer -b write-error "$TMP.fifo" 3>&- 2>&1)
|
||||
status=$?
|
||||
exec 3>&-
|
||||
wait "$reader"
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "save-buffer after write error succeeded."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(wc -c <"$TMP.got")" -ne 8 ]; then
|
||||
echo "save-buffer write error test wrote wrong amount."
|
||||
exit 1
|
||||
fi
|
||||
check_ok delete-buffer -b write-error
|
||||
|
||||
# save-buffer - writes to stdout and load-buffer - reads from stdin.
|
||||
out=$($TMUX save-buffer -b sb -)
|
||||
if [ "$out" != "data" ]; then
|
||||
|
||||
163
regress/copy-mode-unicode-whitespace.sh
Executable file
163
regress/copy-mode-unicode-whitespace.sh
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
[ -z "$TMUX" ] || $TMUX kill-server 2>/dev/null
|
||||
exit 1
|
||||
}
|
||||
|
||||
goto_cell()
|
||||
{
|
||||
row=$1
|
||||
column=$2
|
||||
|
||||
$TMUX send-keys -X history-top || fail "$mode: history-top failed"
|
||||
$TMUX send-keys -X start-of-line || fail "$mode: start-of-line failed"
|
||||
[ "$row" -eq 0 ] ||
|
||||
$TMUX send-keys -X -N "$row" cursor-down ||
|
||||
fail "$mode: cursor-down failed"
|
||||
[ "$column" -eq 0 ] ||
|
||||
$TMUX send-keys -X -N "$column" cursor-right ||
|
||||
fail "$mode: cursor-right failed"
|
||||
}
|
||||
|
||||
check_cursor()
|
||||
{
|
||||
expected=$1
|
||||
actual=$($TMUX display-message -p '#{copy_cursor_x},#{copy_cursor_y}')
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected cursor $expected, got $actual"
|
||||
}
|
||||
|
||||
check_word()
|
||||
{
|
||||
row=$1
|
||||
column=$2
|
||||
expected=$3
|
||||
|
||||
goto_cell "$row" "$column"
|
||||
$TMUX set-buffer sentinel || fail "$mode: set-buffer failed"
|
||||
$TMUX send-keys -X select-word || fail "$mode: select-word failed"
|
||||
$TMUX send-keys -X copy-selection || fail "$mode: copy-selection failed"
|
||||
actual=$($TMUX show-buffer 2>/dev/null)
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected word '$expected', got '$actual'"
|
||||
}
|
||||
|
||||
check_next_word()
|
||||
{
|
||||
row=$1
|
||||
expected=$2
|
||||
|
||||
goto_cell "$row" 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: next-word failed"
|
||||
$TMUX set-buffer sentinel || fail "$mode: set-buffer failed"
|
||||
$TMUX send-keys -X select-word || fail "$mode: select-word failed"
|
||||
$TMUX send-keys -X copy-selection || fail "$mode: copy-selection failed"
|
||||
actual=$($TMUX show-buffer 2>/dev/null)
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected next word '$expected', got '$actual'"
|
||||
}
|
||||
|
||||
for mode in emacs vi; do
|
||||
TMUX="$TEST_TMUX -Lunicode-whitespace-$mode-$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -x16 -y20 \
|
||||
"printf 'aa bb\naa\tbb\naa\302\240bb\naa\343\200\200bb\naa:bb\naaaaaaaaaaaaaaa\302\240b\nabcdefghijklmnopq\nhardone\nhardtwo\naa\341\232\200bb\naa\342\200\200bb\naa\342\200\250bb\naa\342\200\251bb\naa\342\200\257bb\naa\342\201\237bb\nxa\302\205b c\n'; exec cat" ||
|
||||
fail "$mode: new-session failed"
|
||||
$TMUX set-option -g window-size manual || fail "$mode: set size failed"
|
||||
$TMUX set-window-option -g mode-keys "$mode" ||
|
||||
fail "$mode: set mode-keys failed"
|
||||
$TMUX set-window-option -g word-separators "" ||
|
||||
fail "$mode: clear word-separators failed"
|
||||
$TMUX copy-mode || fail "$mode: copy-mode failed"
|
||||
|
||||
# ASCII space and TAB retain their existing behaviour.
|
||||
goto_cell 0 0
|
||||
$TMUX send-keys -X next-space || fail "$mode: ASCII next-space failed"
|
||||
check_cursor 3,0
|
||||
goto_cell 1 0
|
||||
$TMUX send-keys -X next-space || fail "$mode: TAB next-space failed"
|
||||
check_cursor 8,1
|
||||
$TMUX send-keys -X previous-space ||
|
||||
fail "$mode: TAB previous-space failed"
|
||||
check_cursor 0,1
|
||||
|
||||
# NBSP is whitespace for selection and word movement.
|
||||
goto_cell 2 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: NBSP next-word failed"
|
||||
check_cursor 3,2
|
||||
$TMUX send-keys -X previous-word ||
|
||||
fail "$mode: NBSP previous-word failed"
|
||||
check_cursor 0,2
|
||||
check_word 2 0 aa
|
||||
goto_cell 2 0
|
||||
$TMUX send-keys -X next-word-end ||
|
||||
fail "$mode: NBSP next-word-end failed"
|
||||
if [ "$mode" = emacs ]; then
|
||||
check_cursor 2,2
|
||||
else
|
||||
check_cursor 1,2
|
||||
fi
|
||||
|
||||
# U+3000 is two columns wide; both its leading and padding cells must be
|
||||
# skipped as one whitespace character in either direction.
|
||||
goto_cell 3 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: U+3000 next-word failed"
|
||||
check_cursor 4,3
|
||||
$TMUX send-keys -X previous-word ||
|
||||
fail "$mode: U+3000 previous-word failed"
|
||||
check_cursor 0,3
|
||||
goto_cell 3 0
|
||||
$TMUX send-keys -X next-space-end ||
|
||||
fail "$mode: U+3000 next-space-end failed"
|
||||
if [ "$mode" = emacs ]; then
|
||||
check_cursor 2,3
|
||||
else
|
||||
check_cursor 1,3
|
||||
fi
|
||||
|
||||
# Other characters in word-separators remain literal when space enables
|
||||
# Unicode whitespace matching.
|
||||
$TMUX set-window-option -g word-separators ': ' ||
|
||||
fail "$mode: set custom word-separators failed"
|
||||
goto_cell 4 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: literal next-word failed"
|
||||
check_cursor 2,4
|
||||
$TMUX set-window-option -g word-separators "" ||
|
||||
fail "$mode: restore word-separators failed"
|
||||
|
||||
# Whitespace in the last column remains a boundary across a soft wrap.
|
||||
goto_cell 5 0
|
||||
$TMUX send-keys -X next-space ||
|
||||
fail "$mode: wrapped NBSP next-space failed"
|
||||
check_cursor 0,6
|
||||
|
||||
# A word split only by a soft wrap remains one word, while a hard line
|
||||
# boundary still terminates selection.
|
||||
check_word 7 0 abcdefghijklmnopq
|
||||
check_word 9 0 hardone
|
||||
|
||||
# Check the remaining representative White_Space ranges and U+0085
|
||||
# combined into a cell with another character.
|
||||
check_next_word 11 bb
|
||||
check_next_word 12 bb
|
||||
check_next_word 13 bb
|
||||
check_next_word 14 bb
|
||||
check_next_word 15 bb
|
||||
check_next_word 16 bb
|
||||
goto_cell 17 0
|
||||
$TMUX send-keys -X next-word ||
|
||||
fail "$mode: combined U+0085 next-word failed"
|
||||
check_cursor 2,17
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
done
|
||||
|
||||
exit 0
|
||||
@@ -199,5 +199,74 @@ must_fail $TMUX resize-pane -t "$id" -x 0
|
||||
must_fail $TMUX resize-pane -t "$id" -y 0
|
||||
$TMUX kill-pane -t "$id" || exit 1
|
||||
|
||||
# --- Tiled pane resize with floating cells in the layout ---
|
||||
|
||||
$TMUX set-option -w -u pane-border-lines || exit 1
|
||||
base=$($TMUX display-message -p '#{pane_id}')
|
||||
|
||||
# A floating cell after the last tiled cell must not become the recipient of a
|
||||
# relative or absolute resize. This is the sequence from GitHub issue 5135.
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 50% -y 50% -X 50% -Y 50% 'sleep 100') ||
|
||||
fail "new-pane for tiled resize test failed"
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for tiled resize test failed"
|
||||
|
||||
$TMUX resize-pane -t "$lower" -U 5 || fail "relative tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 7
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 13
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 10
|
||||
|
||||
$TMUX resize-pane -t "$lower" -y 11 || fail "absolute tiled reset failed"
|
||||
$TMUX resize-pane -t "$lower" -y 16 || fail "absolute tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 7
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 10
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
# A floating cell between tiled siblings must be skipped when finding the cell
|
||||
# which donates space to a resize.
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for middle floating cell test failed"
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 20 -y 8 -X 30 -Y 8 'sleep 100') ||
|
||||
fail "new-pane for middle floating cell test failed"
|
||||
|
||||
$TMUX resize-pane -t "$base" -D 3 || fail "resize past floating cell failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 15
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 6
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
# A small floating child must not limit the available tiled space in a nested
|
||||
# layout with a different split direction.
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for nested floating cell test failed"
|
||||
right=$($TMUX split-window -dhPF '#{pane_id}' -t "$lower" 'sleep 100') ||
|
||||
fail "horizontal split for nested floating cell test failed"
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$lower" \
|
||||
-x 20 -y 3 -X 30 -Y 10 'sleep 100') ||
|
||||
fail "new-pane for nested floating cell test failed"
|
||||
|
||||
$TMUX resize-pane -t "$base" -D 3 || fail "nested tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 15
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$right" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$right" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 1
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$right" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
|
||||
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
|
||||
4
resize.c
4
resize.c
@@ -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.
|
||||
* 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);
|
||||
if (current)
|
||||
return (loop->session->curw->window != w);
|
||||
return (active_get_effective_window(loop, loop->session) != w);
|
||||
return (session_has(loop->session, w) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ static void
|
||||
redraw_set_context(struct client *c, struct redraw_build_ctx *bctx)
|
||||
{
|
||||
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);
|
||||
bctx->c = c;
|
||||
@@ -969,7 +969,7 @@ static struct redraw_scene *
|
||||
redraw_make_scene(struct client *c)
|
||||
{
|
||||
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_scene *scene;
|
||||
struct redraw_build_cell *bc, *last;
|
||||
@@ -1079,7 +1079,7 @@ static struct redraw_scene *
|
||||
redraw_get_scene(struct client *c)
|
||||
{
|
||||
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;
|
||||
u_int ox, oy, sx, sy;
|
||||
|
||||
@@ -1117,7 +1117,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;
|
||||
@@ -1140,7 +1140,7 @@ redraw_get_default_border_style(struct redraw_draw_ctx *dctx,
|
||||
struct grid_cell *dgc = &dctx->default_gc;
|
||||
|
||||
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);
|
||||
style_add(dgc, oo, "pane-border-style", ft);
|
||||
format_free(ft);
|
||||
@@ -1334,7 +1334,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;
|
||||
@@ -1603,14 +1603,16 @@ redraw_set_draw_context(struct redraw_draw_ctx *dctx,
|
||||
struct session *s = c->session;
|
||||
struct options *oo = s->options;
|
||||
struct tty *tty = &c->tty;
|
||||
struct winlink *wl;
|
||||
u_int lines;
|
||||
|
||||
memset(dctx, 0, sizeof *dctx);
|
||||
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->active = s->curw->window->active;
|
||||
dctx->active = active_get_effective_pane(c, wl->window);
|
||||
|
||||
lines = status_line_size(c);
|
||||
if (options_get_number(oo, "status-position") == 0)
|
||||
@@ -1683,7 +1685,7 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
{
|
||||
struct redraw_draw_ctx dctx;
|
||||
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 screen *sl;
|
||||
struct redraw_scene *scene;
|
||||
@@ -1883,7 +1885,7 @@ redraw_screen(struct client *c)
|
||||
flags |= REDRAW_OVERLAY;
|
||||
if (c->flags & CLIENT_REDRAWMENU)
|
||||
flags |= REDRAW_MENU;
|
||||
if (c->session->curw->window->menu != NULL)
|
||||
if (active_get_effective_window(c, c->session)->menu != NULL)
|
||||
flags |= REDRAW_MENU;
|
||||
if (flags != 0)
|
||||
redraw_draw(c, NULL, flags);
|
||||
@@ -1895,7 +1897,7 @@ void
|
||||
redraw_pane(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
@@ -142,7 +142,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (c->session->curw->window != wp->window)
|
||||
if (active_get_effective_window(c, c->session) != wp->window)
|
||||
return (0);
|
||||
if (wp->layout_cell == NULL)
|
||||
return (0);
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-client.c,v 1.508 2026/08/25 06:14:16 nicm Exp $ */
|
||||
/* $OpenBSD: server-client.c,v 1.509 2026/08/28 07:36:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -107,7 +107,7 @@ server_client_set_overlay(struct client *c, u_int delay,
|
||||
c->tty.flags |= TTY_FREEZE;
|
||||
if (c->overlay_mode == NULL)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ server_client_clear_overlay(struct client *c)
|
||||
|
||||
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -379,7 +379,8 @@ server_client_attached_lost(struct client *c)
|
||||
found = NULL;
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
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;
|
||||
if (found == NULL || timercmp(&loop->activity_time,
|
||||
&found->activity_time, >))
|
||||
@@ -460,15 +461,15 @@ server_client_set_session(struct client *c, struct session *s)
|
||||
c->flags |= CLIENT_FOCUSED;
|
||||
|
||||
if (old != NULL && old->curw != NULL)
|
||||
window_update_focus(old->curw->window);
|
||||
window_update_focus(active_get_effective_window(c, old));
|
||||
if (s != NULL) {
|
||||
s->curw->window->latest = c;
|
||||
active_get_effective_window(c, s)->latest = c;
|
||||
recalculate_sizes();
|
||||
window_update_focus(s->curw->window);
|
||||
window_update_focus(active_get_effective_window(c, s));
|
||||
session_update_activity(s, NULL);
|
||||
session_theme_changed(s);
|
||||
gettimeofday(&s->last_attached_time, NULL);
|
||||
s->curw->flags &= ~WINLINK_ALERTFLAGS;
|
||||
active_get_effective_winlink(c, s)->flags &= ~WINLINK_ALERTFLAGS;
|
||||
alerts_check_session(s);
|
||||
tty_update_client_offset(c);
|
||||
status_timer_start(c);
|
||||
@@ -493,6 +494,7 @@ server_client_lost(struct client *c)
|
||||
server_client_clear_overlay(c);
|
||||
status_prompt_clear(c);
|
||||
status_message_clear(c);
|
||||
active_remove_client(c);
|
||||
|
||||
RB_FOREACH_SAFE(cf, client_files, &c->files, cf1) {
|
||||
cf->error = EINTR;
|
||||
@@ -506,6 +508,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);
|
||||
|
||||
@@ -684,7 +687,7 @@ server_client_in_scrollbar_area(struct window_pane *wp, int px, int py)
|
||||
static void
|
||||
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;
|
||||
|
||||
if (type != KEYC_TYPE_MOUSEMOVE)
|
||||
@@ -856,7 +859,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct mouse_event *m = &event->m;
|
||||
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 window_pane *wp, *fwp, *lwp = NULL;
|
||||
u_int x, y, sx, sy, px, py, n, sl_mpos = 0;
|
||||
@@ -1359,7 +1362,7 @@ server_client_update_latest(struct client *c)
|
||||
|
||||
if (c->session == NULL)
|
||||
return;
|
||||
w = c->session->curw->window;
|
||||
w = active_get_effective_window(c, c->session);
|
||||
|
||||
if (w->latest == c)
|
||||
return;
|
||||
@@ -1438,7 +1441,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
||||
/* Check the client is good to accept input. */
|
||||
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
goto out;
|
||||
wl = s->curw;
|
||||
wl = active_get_effective_winlink(c, s);
|
||||
|
||||
/* Update the activity timer. */
|
||||
memcpy(&c->last_activity_time, &c->activity_time,
|
||||
@@ -1499,6 +1502,10 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
||||
TAILQ_EMPTY(&wp->modes))
|
||||
goto forward_key;
|
||||
|
||||
/* Focus events are not keys and cannot be bound. */
|
||||
if (key == KEYC_FOCUS_IN || key == KEYC_FOCUS_OUT)
|
||||
goto forward_key;
|
||||
|
||||
/*
|
||||
* Work out the current key table. If the pane is in a mode, use
|
||||
* the mode table instead of the default key table.
|
||||
@@ -1693,7 +1700,7 @@ out:
|
||||
static int
|
||||
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 mouse_event *m;
|
||||
u_int ox, oy, sx, sy;
|
||||
@@ -1732,6 +1739,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct cmdq_item *item;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
@@ -1802,9 +1810,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)) {
|
||||
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (window_pane_has_prompt(wp) &&
|
||||
window_pane_is_visible(wp))
|
||||
break;
|
||||
@@ -2146,8 +2155,8 @@ static void
|
||||
server_client_reset_state(struct client *c)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp = w->active, *loop;
|
||||
struct window *w = active_get_effective_window(c, c->session);
|
||||
struct window_pane *wp, *loop;
|
||||
struct screen *s = NULL;
|
||||
struct options *oo = c->session->options;
|
||||
int mode = 0, cursor, flags, pane_mode = 0;
|
||||
@@ -2155,6 +2164,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;
|
||||
|
||||
@@ -2426,7 +2436,7 @@ server_client_redraw_timer(__unused int fd, __unused short events,
|
||||
static void
|
||||
server_client_check_modes(struct client *c)
|
||||
{
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct window_mode_entry *wme;
|
||||
|
||||
@@ -2434,6 +2444,7 @@ server_client_check_modes(struct client *c)
|
||||
return;
|
||||
if (~c->flags & CLIENT_REDRAWSTATUS)
|
||||
return;
|
||||
w = active_get_effective_window(c, c->session);
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme != NULL && wme->mode->update != NULL)
|
||||
@@ -2446,7 +2457,7 @@ static int
|
||||
server_client_any_pane_redraw(struct client *c)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w = s->curw->window;
|
||||
struct window *w = active_get_effective_window(c, s);
|
||||
struct window_pane *wp;
|
||||
|
||||
if (c->flags & CLIENT_REDRAWWINDOW)
|
||||
@@ -2464,7 +2475,7 @@ server_client_check_redraw(struct client *c)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct tty *tty = &c->tty;
|
||||
struct window *w = s->curw->window;
|
||||
struct window *w = active_get_effective_window(c, s);
|
||||
struct window_pane *wp;
|
||||
int needed, tflags, mode = tty->mode;
|
||||
struct timeval tv = { .tv_usec = 1000 };
|
||||
@@ -2603,14 +2614,15 @@ static void
|
||||
server_client_set_path(struct client *c)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w = active_get_effective_window(c, s);
|
||||
const char *path;
|
||||
|
||||
if (s->curw == NULL || s->curw->window->active == NULL)
|
||||
if (w == NULL || w->active == NULL)
|
||||
return;
|
||||
if (s->curw->window->active->base.path == NULL)
|
||||
if (w->active->base.path == NULL)
|
||||
path = "";
|
||||
else
|
||||
path = s->curw->window->active->base.path;
|
||||
path = w->active->base.path;
|
||||
if (c->path == NULL || strcmp(path, c->path) != 0) {
|
||||
free(c->path);
|
||||
c->path = xstrdup(path);
|
||||
@@ -2623,11 +2635,12 @@ static void
|
||||
server_client_set_progress_bar(struct client *c)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w = active_get_effective_window(c, s);
|
||||
struct progress_bar *pane_pb;
|
||||
|
||||
if (s->curw == NULL || s->curw->window->active == NULL)
|
||||
if (w == NULL || w->active == NULL)
|
||||
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 &&
|
||||
pane_pb->progress == c->progress_bar.progress)
|
||||
return;
|
||||
@@ -3164,6 +3177,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;
|
||||
@@ -3179,6 +3193,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';
|
||||
@@ -3217,7 +3232,8 @@ server_client_print(struct client *c, int parse, struct evbuffer *evb)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wp = c->session->curw->window->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,
|
||||
|
||||
@@ -122,8 +122,7 @@ server_redraw_window(struct window *w)
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session != NULL &&
|
||||
c->session->curw != NULL &&
|
||||
c->session->curw->window == w)
|
||||
active_get_effective_window(c, c->session) == w)
|
||||
server_redraw_client(c);
|
||||
}
|
||||
}
|
||||
@@ -135,8 +134,7 @@ server_redraw_window_menu(struct window *w)
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session != NULL &&
|
||||
c->session->curw != NULL &&
|
||||
c->session->curw->window == w)
|
||||
active_get_effective_window(c, c->session) == w)
|
||||
c->flags |= CLIENT_REDRAWMENU;
|
||||
}
|
||||
}
|
||||
@@ -148,8 +146,7 @@ server_redraw_window_borders(struct window *w)
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session != NULL &&
|
||||
c->session->curw != NULL &&
|
||||
c->session->curw->window == w)
|
||||
active_get_effective_window(c, c->session) == w)
|
||||
c->flags |= CLIENT_REDRAWBORDERS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ session_destroy(struct session *s, int notify, const char *from)
|
||||
if (s->curw == NULL)
|
||||
return;
|
||||
s->curw = NULL;
|
||||
active_remove_session(s);
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
if (notify)
|
||||
|
||||
59
tmux.1
59
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1159 2026/08/25 08:37:08 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1163 2026/09/01 12:49:49 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: August 25 2026 $
|
||||
.Dd $Mdocdate: September 1 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -2208,14 +2208,14 @@ Move to the end of the next word.
|
||||
.Xc
|
||||
Same as
|
||||
.Ic next\-word
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic next\-space\-end
|
||||
(vi: E)
|
||||
.Xc
|
||||
Same as
|
||||
.Ic next\-word\-end
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic other\-end
|
||||
(vi: o)
|
||||
@@ -2289,7 +2289,7 @@ Move to the previous word.
|
||||
.Xc
|
||||
Same as
|
||||
.Ic previous\-word
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic rectangle\-on
|
||||
.Xc
|
||||
@@ -2574,8 +2574,8 @@ Word separators can be customized with the
|
||||
session option.
|
||||
Next word moves to the start of the next word, next word end to the end of the
|
||||
next word and previous word to the start of the previous word.
|
||||
The three next and previous space keys work similarly but use a space alone as
|
||||
the word separator.
|
||||
The three next and previous space keys work similarly but treat all
|
||||
non-whitespace characters as part of a word.
|
||||
Setting
|
||||
.Em word\-separators
|
||||
to the empty string makes next/previous word equivalent to next/previous space.
|
||||
@@ -3993,7 +3993,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
|
||||
@@ -4001,6 +4001,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 ,
|
||||
@@ -4015,6 +4017,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
|
||||
@@ -4038,12 +4049,22 @@ and
|
||||
.Ic swap\-window .
|
||||
.Tg selectw
|
||||
.It Xo Ic select\-window
|
||||
.Op Fl lnpT
|
||||
.Op Fl LlnpST
|
||||
.Op Fl t Ar target\-window
|
||||
.Xc
|
||||
.D1 Pq alias: Ic selectw
|
||||
Select the window at
|
||||
.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 n
|
||||
and
|
||||
@@ -5113,6 +5134,8 @@ Supports
|
||||
title setting.
|
||||
.It usstyle
|
||||
Allows underscore style and colour to be set.
|
||||
.It utf8
|
||||
Supports UTF\-8 output.
|
||||
.El
|
||||
.It Ic terminal\-overrides[] Ar string
|
||||
Allow terminal descriptions read using
|
||||
@@ -5647,6 +5670,11 @@ If set to both, a bell and a message are produced.
|
||||
Sets the session's conception of what characters are considered word
|
||||
separators, for the purposes of the next and previous word commands in
|
||||
copy mode.
|
||||
A space in
|
||||
.Ar string
|
||||
matches any character with the Unicode
|
||||
.Em White_Space
|
||||
property.
|
||||
.El
|
||||
.Pp
|
||||
Available window options are:
|
||||
@@ -7259,7 +7287,10 @@ shows the four frames in turn, changing every 200 milliseconds.
|
||||
The following variables are available, where appropriate:
|
||||
.Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
|
||||
.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_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
|
||||
.It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
|
||||
@@ -7316,7 +7347,10 @@ The following variables are available, where appropriate:
|
||||
.It Li "cursor_very_visible" Ta "" Ta "1 if the cursor is in very visible mode"
|
||||
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
|
||||
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
|
||||
.It Li "history_added" Ta "" Ta "Number of lines scrolled into pane history"
|
||||
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
|
||||
.It Li "history_collected" Ta "" Ta "Number of oldest pane history lines discarded at the history limit"
|
||||
.It Li "history_generation" Ta "" Ta "Generation incremented when pane history is cleared or reflowed"
|
||||
.It Li "history_limit" Ta "" Ta "Maximum window history lines"
|
||||
.It Li "history_size" Ta "" Ta "Size of history in lines"
|
||||
.It Li "hook" Ta "" Ta "Name of running hook, if any"
|
||||
@@ -7410,11 +7444,14 @@ 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"
|
||||
.It Li "pane_modal_flag" Ta "" Ta "1 if pane is modal"
|
||||
.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any"
|
||||
.It Li "pane_output_generation" Ta "" Ta "Generation incremented when pane output is processed"
|
||||
.It Li "pane_path" Ta "" Ta "Path of pane (can be set by application)"
|
||||
.It Li "pane_pid" Ta "" Ta "PID of first process in pane"
|
||||
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
|
||||
@@ -7492,7 +7529,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "uid" Ta "" Ta "Server UID"
|
||||
.It Li "user" Ta "" Ta "Server user"
|
||||
.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_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"
|
||||
|
||||
47
tmux.h
47
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1431 2026/08/25 08:37:08 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1433 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1357,9 +1357,10 @@ struct window_pane {
|
||||
char tty[TTY_NAME_MAX];
|
||||
int status;
|
||||
struct timeval dead_time;
|
||||
struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */
|
||||
struct cmdq_item *wait_item;
|
||||
struct spawn_editor_state *editor;
|
||||
|
||||
uint64_t output_generation;
|
||||
time_t last_output_time;
|
||||
time_t last_prompt_time;
|
||||
time_t cmd_start_time;
|
||||
@@ -2776,6 +2777,42 @@ void events_fire_window(const char *, struct window *);
|
||||
void events_fire_pane(const char *, struct window_pane *);
|
||||
void events_fire_winlink(const char *, struct winlink *);
|
||||
|
||||
/* active.c */
|
||||
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_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 *);
|
||||
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 *,
|
||||
u_int, const char *, struct style_ranges *, int);
|
||||
@@ -2998,7 +3035,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;
|
||||
@@ -3780,7 +3818,7 @@ int window_pane_is_visible(struct window_pane *);
|
||||
int window_pane_exited(struct window_pane *);
|
||||
u_int window_pane_search(struct window_pane *, const char *, 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 *);
|
||||
struct window_pane *window_pane_find_up(struct window_pane *);
|
||||
struct window_pane *window_pane_find_down(struct window_pane *);
|
||||
@@ -4106,6 +4144,7 @@ void session_update_history(struct session *);
|
||||
/* utf8.c */
|
||||
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
|
||||
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
|
||||
int utf8_has_whitespace(const struct utf8_data *);
|
||||
void utf8_update_width_cache(void);
|
||||
utf8_char utf8_build_one(u_char);
|
||||
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-features.c,v 1.42 2026/08/17 14:47:41 nicm Exp $ */
|
||||
/* $OpenBSD: tty-features.c,v 1.43 2026/08/31 12:41:03 kirill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -368,6 +368,13 @@ static const struct tty_feature tty_feature_progressbar = {
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports UTF-8. */
|
||||
static const struct tty_feature tty_feature_utf8 = {
|
||||
"utf8",
|
||||
NULL,
|
||||
0
|
||||
};
|
||||
|
||||
/* Available terminal features. */
|
||||
static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_256,
|
||||
@@ -390,7 +397,8 @@ static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_strikethrough,
|
||||
&tty_feature_sync,
|
||||
&tty_feature_title,
|
||||
&tty_feature_usstyle
|
||||
&tty_feature_usstyle,
|
||||
&tty_feature_utf8
|
||||
};
|
||||
|
||||
/* Parse features for client. */
|
||||
@@ -473,6 +481,9 @@ tty_feature_present(struct tty_term *term, const char *name)
|
||||
u_int i;
|
||||
char *copy;
|
||||
|
||||
if (strcmp(name, "utf8") == 0)
|
||||
return ((term->tty->client->flags & CLIENT_UTF8) != 0);
|
||||
|
||||
for (i = 0; i < nitems(tty_features); i++) {
|
||||
tf = tty_features[i];
|
||||
if (strcmp(tf->name, name) == 0) {
|
||||
@@ -486,7 +497,8 @@ tty_feature_present(struct tty_term *term, const char *name)
|
||||
* We don't just have the feature flag set. Check if the capabilities
|
||||
* supported by the client are actual set instead.
|
||||
*/
|
||||
if (tf == NULL || strcmp(name, "ignorefkeys") == 0)
|
||||
if (tf == NULL || tf->capabilities == NULL ||
|
||||
strcmp(name, "ignorefkeys") == 0)
|
||||
return (0);
|
||||
if (tf->flags != 0 && (term->flags & tf->flags) != tf->flags)
|
||||
return (0);
|
||||
@@ -534,6 +546,8 @@ tty_apply_features(struct tty_term *term)
|
||||
}
|
||||
}
|
||||
term->flags |= tf->flags;
|
||||
if (tf == &tty_feature_utf8)
|
||||
c->flags |= CLIENT_UTF8;
|
||||
}
|
||||
if ((term->applied_features|feat) == term->applied_features)
|
||||
return (0);
|
||||
|
||||
@@ -1020,12 +1020,12 @@ complete_key:
|
||||
/* Check for focus events. */
|
||||
if (key == KEYC_FOCUS_OUT) {
|
||||
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);
|
||||
} else if (key == KEYC_FOCUS_IN) {
|
||||
c->flags |= CLIENT_FOCUSED;
|
||||
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. */
|
||||
|
||||
21
tty.c
21
tty.c
@@ -955,7 +955,7 @@ int
|
||||
tty_window_bigger(struct tty *tty)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -977,10 +977,11 @@ static int
|
||||
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 = c->session->curw->window;
|
||||
struct window_pane *wp = w->active;
|
||||
struct window *w = active_get_effective_window(c, c->session);
|
||||
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) {
|
||||
@@ -1044,8 +1045,7 @@ tty_update_window_offset(struct window *w)
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session != NULL &&
|
||||
c->session->curw != NULL &&
|
||||
c->session->curw->window == w)
|
||||
active_get_effective_window(c, c->session) == w)
|
||||
tty_update_client_offset(c);
|
||||
}
|
||||
}
|
||||
@@ -1547,7 +1547,7 @@ tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
{
|
||||
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);
|
||||
if (wp->layout_cell == NULL)
|
||||
return (0);
|
||||
@@ -3159,23 +3159,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;
|
||||
|
||||
68
utf8.c
68
utf8.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: utf8.c,v 1.71 2026/05/12 09:37:25 nicm Exp $ */
|
||||
/* $OpenBSD: utf8.c,v 1.72 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -603,6 +603,72 @@ utf8_towc(const struct utf8_data *ud, wchar_t *wc)
|
||||
return (UTF8_DONE);
|
||||
}
|
||||
|
||||
/* Check for a Unicode whitespace character. */
|
||||
int
|
||||
utf8_has_whitespace(const struct utf8_data *ud)
|
||||
{
|
||||
struct utf8_data tmp;
|
||||
wchar_t wc;
|
||||
u_int offset = 0, size;
|
||||
u_char ch;
|
||||
|
||||
while (offset < ud->size) {
|
||||
ch = ud->data[offset];
|
||||
if (ch < 0x80) {
|
||||
wc = ch;
|
||||
size = 1;
|
||||
} else {
|
||||
if (ch >= 0xc2 && ch <= 0xdf)
|
||||
size = 2;
|
||||
else if (ch >= 0xe0 && ch <= 0xef)
|
||||
size = 3;
|
||||
else if (ch >= 0xf0 && ch <= 0xf4)
|
||||
size = 4;
|
||||
else
|
||||
return (0);
|
||||
if (size > ud->size - offset)
|
||||
return (0);
|
||||
|
||||
memset(&tmp, 0, sizeof tmp);
|
||||
memcpy(tmp.data, ud->data + offset, size);
|
||||
tmp.size = tmp.have = size;
|
||||
if (utf8_towc(&tmp, &wc) != UTF8_DONE)
|
||||
return (0);
|
||||
}
|
||||
offset += size;
|
||||
|
||||
switch (wc) {
|
||||
case 0x0009:
|
||||
case 0x000A:
|
||||
case 0x000B:
|
||||
case 0x000C:
|
||||
case 0x000D:
|
||||
case 0x0020:
|
||||
case 0x0085:
|
||||
case 0x00A0:
|
||||
case 0x1680:
|
||||
case 0x2000:
|
||||
case 0x2001:
|
||||
case 0x2002:
|
||||
case 0x2003:
|
||||
case 0x2004:
|
||||
case 0x2005:
|
||||
case 0x2006:
|
||||
case 0x2007:
|
||||
case 0x2008:
|
||||
case 0x2009:
|
||||
case 0x200A:
|
||||
case 0x2028:
|
||||
case 0x2029:
|
||||
case 0x202F:
|
||||
case 0x205F:
|
||||
case 0x3000:
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Convert wide character to UTF-8 character. */
|
||||
enum utf8_state
|
||||
utf8_fromwc(wchar_t wc, struct utf8_data *ud)
|
||||
|
||||
@@ -155,9 +155,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 == c->session->curw->window->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";
|
||||
@@ -167,8 +172,15 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c,
|
||||
option = "pane-border-style";
|
||||
}
|
||||
|
||||
if (!*flag) {
|
||||
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);
|
||||
format_free(ft);
|
||||
*flag = 1;
|
||||
@@ -197,7 +209,7 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width,
|
||||
return (0);
|
||||
|
||||
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");
|
||||
expanded = format_expand_time(ft, fmt);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-client.c,v 1.48 2026/08/05 08:54:56 nicm Exp $ */
|
||||
/* $OpenBSD: window-client.c,v 1.49 2026/08/31 12:41:03 kirill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -102,7 +102,8 @@ static const char *window_client_info_lines[] = {
|
||||
WINDOW_CLIENT_FEATURE(sync) " "
|
||||
WINDOW_CLIENT_FEATURE(title),
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(usstyle),
|
||||
WINDOW_CLIENT_FEATURE(usstyle) " "
|
||||
WINDOW_CLIENT_FEATURE(utf8),
|
||||
"#[#{E:tree-mode-border-style},acs]qqqqqqqqqqqqqqn#{R:q,#{window_width}}#[default]",
|
||||
|
||||
"#[fg=themelightgrey]prefix #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
@@ -268,12 +269,13 @@ window_client_draw_info(__unused void *modedata, void *itemdata,
|
||||
struct window_client_itemdata *item = itemdata;
|
||||
struct client *c = item->c;
|
||||
struct screen *s = ctx->s;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window *w;
|
||||
struct grid_cell gc;
|
||||
u_int cx = s->cx, cy = s->cy, i;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
|
||||
w = active_get_effective_window(c, c->session);
|
||||
ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
|
||||
if (c->tty.term->flags & TERM_INVALIDMS)
|
||||
format_add(ft, "clipboard_invalid", "1");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-copy.c,v 1.426 2026/08/19 19:55:04 nicm Exp $ */
|
||||
/* $OpenBSD: window-copy.c,v 1.429 2026/09/01 13:04:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -2207,15 +2207,76 @@ window_copy_cmd_selection_mode(struct window_copy_cmd_state *cs)
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct options *so = cs->s->options;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct grid_reader gr;
|
||||
const char *s = args_string(cs->wargs, 0);
|
||||
u_int sx, sy, ex, ey, fx, fy, x, y;
|
||||
|
||||
if (s == NULL || strcasecmp(s, "char") == 0 || strcasecmp(s, "c") == 0)
|
||||
data->selflag = SEL_CHAR;
|
||||
else if (strcasecmp(s, "word") == 0 || strcasecmp(s, "w") == 0) {
|
||||
data->separators = options_get_string(so, "word-separators");
|
||||
data->selflag = SEL_WORD;
|
||||
} else if (strcasecmp(s, "line") == 0 || strcasecmp(s, "l") == 0)
|
||||
} else if (strcasecmp(s, "line") == 0 || strcasecmp(s, "l") == 0) {
|
||||
data->selflag = SEL_LINE;
|
||||
if (data->screen.sel == NULL)
|
||||
return (WINDOW_COPY_CMD_MOVE);
|
||||
|
||||
/*
|
||||
* Line selection normally starts with select-line, which sets
|
||||
* up the reset positions used when the cursor changes
|
||||
* direction. Do the same when changing an existing selection
|
||||
* to line mode.
|
||||
*/
|
||||
if (data->cursordrag == CURSORDRAG_SEL) {
|
||||
fx = data->endselx;
|
||||
fy = data->endsely;
|
||||
} else {
|
||||
fx = data->selx;
|
||||
fy = data->sely;
|
||||
}
|
||||
|
||||
sx = data->selx;
|
||||
sy = data->sely;
|
||||
ex = data->endselx;
|
||||
ey = data->endsely;
|
||||
if (ey < sy || (ey == sy && ex < sx)) {
|
||||
x = sx; sx = ex; ex = x;
|
||||
y = sy; sy = ey; ey = y;
|
||||
}
|
||||
grid_reader_start(&gr, data->backing->grid, sx, sy);
|
||||
grid_reader_cursor_start_of_line(&gr, 1);
|
||||
grid_reader_get_cursor(&gr, &sx, &sy);
|
||||
grid_reader_start(&gr, data->backing->grid, ex, ey);
|
||||
grid_reader_cursor_end_of_line(&gr, 1, 0);
|
||||
grid_reader_get_cursor(&gr, &ex, &ey);
|
||||
|
||||
data->rectflag = 0;
|
||||
data->selrx = data->selx = sx;
|
||||
data->selry = data->sely = sy;
|
||||
data->endselrx = data->endselx = ex;
|
||||
data->endselry = data->endsely = ey;
|
||||
|
||||
x = data->cx;
|
||||
y = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
data->dx = fx;
|
||||
data->dy = fy;
|
||||
if (data->cursordrag != CURSORDRAG_NONE &&
|
||||
(y < fy || (y == fy && x < fx))) {
|
||||
data->lineflag = LINE_SEL_RIGHT_LEFT;
|
||||
data->cursordrag = CURSORDRAG_SEL;
|
||||
window_copy_scroll_to(wme, sx, sy, 1);
|
||||
} else {
|
||||
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
||||
if (data->cursordrag != CURSORDRAG_NONE) {
|
||||
data->cursordrag = CURSORDRAG_ENDSEL;
|
||||
x = window_copy_cursor_limit(wme, ey, 0);
|
||||
window_copy_scroll_to(wme, x, ey, 1);
|
||||
}
|
||||
}
|
||||
if (data->cursordrag == CURSORDRAG_NONE)
|
||||
window_copy_set_selection(wme, 0, 0);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_MOVE);
|
||||
}
|
||||
|
||||
@@ -4301,7 +4362,7 @@ window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
|
||||
}
|
||||
if (dlen == 1)
|
||||
buf[bx++] = *d;
|
||||
else {
|
||||
else if (dlen != 0) {
|
||||
memcpy(buf + bx, d, dlen);
|
||||
bx += dlen;
|
||||
}
|
||||
@@ -4851,6 +4912,8 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
|
||||
cflags |= REG_ICASE;
|
||||
if (regcomp(®, sbuf, cflags) != 0) {
|
||||
free(sbuf);
|
||||
free(data->searchmark);
|
||||
data->searchmark = NULL;
|
||||
return (0);
|
||||
}
|
||||
free(sbuf);
|
||||
|
||||
21
window.c
21
window.c
@@ -451,6 +451,7 @@ window_destroy(struct window *w)
|
||||
{
|
||||
log_debug("window @%u destroyed (%d references)", w->id, w->references);
|
||||
|
||||
active_remove_window(w);
|
||||
window_unzoom(w, 0);
|
||||
RB_REMOVE(windows, &windows, w);
|
||||
|
||||
@@ -672,6 +673,7 @@ void
|
||||
window_pane_update_focus(struct window_pane *wp)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w;
|
||||
int focused = 0;
|
||||
|
||||
if (wp != NULL && (~wp->flags & PANE_EXITED)) {
|
||||
@@ -679,10 +681,12 @@ window_pane_update_focus(struct window_pane *wp)
|
||||
focused = 0;
|
||||
else {
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session != NULL &&
|
||||
c->session->attached != 0 &&
|
||||
if (c->session == NULL)
|
||||
continue;
|
||||
w = active_get_effective_window(c, c->session);
|
||||
if (c->session->attached != 0 &&
|
||||
(c->flags & CLIENT_FOCUSED) &&
|
||||
c->session->curw->window == wp->window &&
|
||||
w == wp->window &&
|
||||
c->overlay_draw == NULL &&
|
||||
wp->window->menu == NULL) {
|
||||
focused = 1;
|
||||
@@ -788,7 +792,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;
|
||||
@@ -1287,7 +1292,7 @@ window_destroy_panes(struct window *w)
|
||||
}
|
||||
|
||||
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;
|
||||
static char flags[32];
|
||||
@@ -1302,9 +1307,9 @@ window_printable_flags(struct winlink *wl, int escape)
|
||||
flags[pos++] = '!';
|
||||
if (wl->flags & WINLINK_SILENCE)
|
||||
flags[pos++] = '~';
|
||||
if (wl == s->curw)
|
||||
if (active_is_effective_window(c, s, wl))
|
||||
flags[pos++] = '*';
|
||||
if (wl == TAILQ_FIRST(&s->lastw))
|
||||
if (active_is_last_window(c, s, wl))
|
||||
flags[pos++] = '-';
|
||||
if (server_check_marked() && wl == marked_pane.wl)
|
||||
flags[pos++] = 'M';
|
||||
@@ -2634,7 +2639,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