mirror of
https://github.com/tmux/tmux.git
synced 2026-07-29 03:37:52 +00:00
Merge remote-tracking branch 'origin/master' into command_parser
# Conflicts: # cmd-queue.c # notify.c # options.c
This commit is contained in:
27
.github/workflows/regress.yml
vendored
27
.github/workflows/regress.yml
vendored
@@ -25,12 +25,15 @@ jobs:
|
||||
- name: ubuntu-24.04-x64
|
||||
runner: ubuntu-24.04
|
||||
make: make
|
||||
# - name: ubuntu-24.04-arm64
|
||||
# runner: ubuntu-24.04-arm
|
||||
# make: make
|
||||
# - name: macos-26-arm64
|
||||
# runner: macos-26
|
||||
# make: gmake
|
||||
configure: --enable-utf8proc --enable-asan
|
||||
#- name: ubuntu-24.04-arm64
|
||||
# runner: ubuntu-24.04-arm
|
||||
# make: make
|
||||
# configure: --enable-utf8proc --enable-asan
|
||||
- name: macos-26-arm64
|
||||
runner: macos-26
|
||||
make: gmake
|
||||
configure: --enable-utf8proc --enable-asan
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
@@ -65,11 +68,19 @@ jobs:
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
sh autogen.sh
|
||||
./configure --enable-utf8proc
|
||||
sh autogen.sh
|
||||
./configure ${{ matrix.configure }}
|
||||
${{ matrix.make }} -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
|
||||
- name: test
|
||||
run: |
|
||||
cd regress
|
||||
${{ matrix.make }}
|
||||
|
||||
- name: logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: regress-logs-${{ matrix.name }}
|
||||
path: regress/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ configure
|
||||
core
|
||||
etc/
|
||||
fuzz/*-fuzzer
|
||||
regress/logs/
|
||||
tags
|
||||
tmux
|
||||
tmux.1.*
|
||||
|
||||
17
Makefile.am
17
Makefile.am
@@ -13,7 +13,8 @@ AM_CPPFLAGS += @XOPEN_DEFINES@ \
|
||||
-DTMUX_VERSION='"@VERSION@"' \
|
||||
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \
|
||||
-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
|
||||
-DTMUX_TERM='"@DEFAULT_TERM@"'
|
||||
-DTMUX_TERM='"@DEFAULT_TERM@"' \
|
||||
-DTMUX_MOUSE=1
|
||||
|
||||
# Additional object files.
|
||||
LDADD = $(LIBOBJS)
|
||||
@@ -42,7 +43,8 @@ AM_CPPFLAGS += -DDEBUG
|
||||
endif
|
||||
AM_CPPFLAGS += -iquote.
|
||||
if IS_ASAN
|
||||
AM_CFLAGS += -fsanitize=address
|
||||
AM_CPPFLAGS += -DASAN
|
||||
AM_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||
AM_LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
endif
|
||||
@@ -160,13 +162,16 @@ dist_tmux_SOURCES = \
|
||||
control-notify.c \
|
||||
control.c \
|
||||
environ.c \
|
||||
events-payload.c \
|
||||
events.c \
|
||||
file.c \
|
||||
format.c \
|
||||
format-draw.c \
|
||||
format.c \
|
||||
fuzzy.c \
|
||||
grid-reader.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
hyperlinks.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
@@ -179,15 +184,15 @@ dist_tmux_SOURCES = \
|
||||
log.c \
|
||||
menu.c \
|
||||
mode-tree.c \
|
||||
monitor.c \
|
||||
names.c \
|
||||
notify.c \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
prompt.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
@@ -202,9 +207,9 @@ dist_tmux_SOURCES = \
|
||||
spawn.c \
|
||||
status.c \
|
||||
style.c \
|
||||
tmux-protocol.h \
|
||||
tmux.c \
|
||||
tmux.h \
|
||||
tmux-protocol.h \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
|
||||
1
SECURITY.md
Normal file
1
SECURITY.md
Normal file
@@ -0,0 +1 @@
|
||||
Please report security issues to nicholas.marriott@gmail.com.
|
||||
8
alerts.c
8
alerts.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: alerts.c,v 1.35 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -205,7 +205,7 @@ alerts_check_bell(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "bell-action"))
|
||||
continue;
|
||||
notify_winlink("alert-bell", wl);
|
||||
events_fire_winlink("alert-bell", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -241,7 +241,7 @@ alerts_check_activity(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "activity-action"))
|
||||
continue;
|
||||
notify_winlink("alert-activity", wl);
|
||||
events_fire_winlink("alert-activity", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -277,7 +277,7 @@ alerts_check_silence(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "silence-action"))
|
||||
continue;
|
||||
notify_winlink("alert-silence", wl);
|
||||
events_fire_winlink("alert-silence", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: arguments.c,v 1.66 2026/06/26 09:54:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: attributes.c,v 1.13 2026/07/02 08:51:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
|
||||
|
||||
2
cfg.c
2
cfg.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cfg.c,v 1.89 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
29
client.c
29
client.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: client.c,v 1.166 2026/07/10 15:45:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -257,9 +257,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
pid_t ppid;
|
||||
enum msgtype msg;
|
||||
struct termios tio, saved_tio;
|
||||
size_t size, linesize = 0;
|
||||
ssize_t linelen;
|
||||
char *line = NULL, **caps = NULL, *cause;
|
||||
size_t size;
|
||||
char **caps = NULL, *cause;
|
||||
u_int ncaps = 0;
|
||||
|
||||
/* Set up the initial command. */
|
||||
@@ -410,11 +409,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
client_exec(client_execshell, client_execcmd);
|
||||
}
|
||||
|
||||
/* Restore streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_attached) {
|
||||
if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
@@ -429,15 +423,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
else
|
||||
printf("%%exit\n");
|
||||
fflush(stdout);
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
|
||||
setvbuf(stdin, NULL, _IOLBF, 0);
|
||||
for (;;) {
|
||||
linelen = getline(&line, &linesize, stdin);
|
||||
if (linelen <= 1)
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT)
|
||||
control_wait_exit(STDIN_FILENO);
|
||||
if (client_flags & CLIENT_CONTROLCONTROL) {
|
||||
printf("\033\\");
|
||||
fflush(stdout);
|
||||
@@ -445,6 +432,12 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
}
|
||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
fprintf(stderr, "%s\n", client_exit_message());
|
||||
|
||||
/* Restore the streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
return (client_exitval);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-attach-session.c,v 1.91 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -163,7 +163,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
|
||||
if (~c->flags & CLIENT_CONTROL)
|
||||
proc_send(c->peer, MSG_READY, -1, NULL, 0);
|
||||
notify_client("client-attached", c);
|
||||
events_fire_client("client-attached", c);
|
||||
c->flags |= CLIENT_ATTACHED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-bind-key.c,v 1.47 2025/04/09 07:03:04 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-break-pane.c,v 1.72 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -51,10 +51,9 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
struct window *w, struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
u_int sx = lc->saved_sx, sy = lc->saved_sy;
|
||||
int ox = lc->saved_xoff, oy = lc->saved_yoff;
|
||||
char *cause = NULL;
|
||||
enum pane_lines lines = window_get_pane_lines(w);
|
||||
struct layout_geometry *fg = &lc->fg;
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is already floating");
|
||||
@@ -65,14 +64,13 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
&cause) != 0) {
|
||||
if (layout_floating_args_parse(item, args, lines, w, fg, &cause) != 0) {
|
||||
cmdq_error(item, "failed to float pane: %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
layout_remove_tile(w, lc);
|
||||
layout_set_size(lc, sx, sy, ox, oy);
|
||||
layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff);
|
||||
|
||||
lc->flags |= LAYOUT_CELL_FLOATING;
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
@@ -82,7 +80,7 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -101,7 +99,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *dst_s = target->s;
|
||||
struct window_pane *wp = source->wp;
|
||||
struct window *w = wl->window;
|
||||
char *newname, *cause, *cp;
|
||||
char *cause, *cp;
|
||||
int idx = target->idx, before;
|
||||
const char *template, *name = args_get(args, 'n');
|
||||
|
||||
@@ -153,6 +151,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
layout_close_pane(wp);
|
||||
|
||||
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
||||
window_add_ref(w, __func__);
|
||||
options_set_parent(wp->options, w->options);
|
||||
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||
@@ -160,12 +159,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
w->active = wp;
|
||||
w->latest = tc;
|
||||
|
||||
if (name == NULL) {
|
||||
newname = default_window_name(w);
|
||||
window_set_name(w, newname, 0);
|
||||
free(newname);
|
||||
} else {
|
||||
window_set_name(w, name, 0);
|
||||
free(w->name);
|
||||
if (name == NULL)
|
||||
w->name = default_window_name(w);
|
||||
else {
|
||||
w->name = clean_name(name, 0);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
}
|
||||
|
||||
@@ -176,6 +174,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(dst_s->options, "base-index");
|
||||
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
|
||||
window_remove_ref(w, __func__);
|
||||
if (!args_has(args, 'd')) {
|
||||
session_select(dst_s, wl->idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-capture-pane.c,v 1.67 2026/07/02 10:34:14 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-choose-tree.c,v 1.57 2026/06/26 14:40:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-command-prompt.c,v 1.75 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-confirm-before.c,v 1.61 2026/06/24 10:55:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-copy-mode.c,v 1.53 2026/07/08 08:07:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
|
||||
.name = "copy-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "deHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "dekHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-dekHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.source = { 's', CMD_FIND_PANE, 0 },
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-detach-client.c,v 1.39 2026/05/22 15:22:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.51 2026/07/07 09:45:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -126,6 +126,10 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
format_add(ft, "popup_mouse_y", "%u", event->m.y);
|
||||
}
|
||||
|
||||
/* Position of the previous menu, for -x/-y L. */
|
||||
format_add(ft, "popup_last_x", "%u", tc->menu_last_px);
|
||||
format_add(ft, "popup_last_y", "%u", tc->menu_last_py + h);
|
||||
|
||||
/*
|
||||
* If there are any status lines, add this window position and the
|
||||
* status line position.
|
||||
@@ -238,6 +242,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
xp = "#{popup_pane_left}";
|
||||
else if (strcmp(xp, "M") == 0)
|
||||
xp = "#{popup_mouse_centre_x}";
|
||||
else if (strcmp(xp, "L") == 0)
|
||||
xp = "#{popup_last_x}";
|
||||
else if (strcmp(xp, "W") == 0)
|
||||
xp = "#{popup_window_status_line_x}";
|
||||
p = format_expand(ft, xp);
|
||||
@@ -258,6 +264,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
yp = "#{popup_pane_bottom}";
|
||||
else if (strcmp(yp, "M") == 0)
|
||||
yp = "#{popup_mouse_top}";
|
||||
else if (strcmp(yp, "L") == 0)
|
||||
yp = "#{popup_last_y}";
|
||||
else if (strcmp(yp, "S") == 0)
|
||||
yp = "#{popup_status_line_y}";
|
||||
else if (strcmp(yp, "W") == 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-message.c,v 1.65 2026/02/23 08:46:57 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-panes.c,v 1.56 2026/06/25 16:32:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find-window.c,v 1.56 2023/12/27 20:42:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find.c,v 1.86 2026/07/02 08:47:25 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-if-shell.c,v 1.86 2025/08/01 09:05:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-join-pane.c,v 1.69 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
|
||||
@@ -71,8 +71,9 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
struct window *w = wl->window;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
struct window_pane *owp;
|
||||
int wx = w->sx, wy = w->sy, px = lc->sx;
|
||||
int py = lc->sy, xoff = lc->xoff, yoff = lc->yoff;
|
||||
int wx = w->sx, wy = w->sy;
|
||||
int px = lc->g.sx, py = lc->g.sy;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff;
|
||||
int border = 1;
|
||||
|
||||
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
|
||||
@@ -180,12 +181,12 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -200,7 +201,7 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
const char *errstr, *argval;
|
||||
const char flags[] = { 'U', 'D', 'L', 'R' };
|
||||
char *cause = NULL, flag;
|
||||
int xoff = lc->xoff, yoff = lc->yoff, adjust;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff, adjust;
|
||||
u_int i;
|
||||
enum pane_lines lines = window_pane_get_pane_lines(wp);
|
||||
|
||||
@@ -251,11 +252,11 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
xoff += adjust;
|
||||
}
|
||||
|
||||
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -319,8 +320,8 @@ cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m)
|
||||
ly = m->statusat - 1;
|
||||
|
||||
if (x != lx || y != ly) {
|
||||
lc->xoff += x - lx;
|
||||
lc->yoff += y - ly;
|
||||
lc->g.xoff += x - lx;
|
||||
lc->g.yoff += y - ly;
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
@@ -357,7 +358,46 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if (!window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is not floating");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (w->flags & WINDOW_ZOOMED) {
|
||||
cmdq_error(item, "can't tile a pane while window is zoomed");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
lc->fg.sx = lc->g.sx;
|
||||
lc->fg.sy = lc->g.sy;
|
||||
lc->fg.xoff = lc->g.xoff;
|
||||
lc->fg.yoff = lc->g.yoff;
|
||||
|
||||
if (layout_insert_tile(w, lc) != 0) {
|
||||
cmdq_error(item, "no space for a new pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
lc->flags &= ~LAYOUT_CELL_FLOATING;
|
||||
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
if (!args_has(args, 'd'))
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -412,6 +452,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_unzoom_window(src_w);
|
||||
|
||||
if (src_wp == dst_wp) {
|
||||
if (window_pane_is_floating(src_wp))
|
||||
return (cmd_join_pane_tile(item, args, src_w, src_wp));
|
||||
cmdq_error(item, "source and target panes must be different");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
@@ -459,8 +501,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (window_count_panes(src_w, 1) == 0)
|
||||
server_kill_window(src_w, 1);
|
||||
else
|
||||
notify_window("window-layout-changed", src_w);
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-pane.c,v 1.34 2026/06/09 21:22:22 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-server.c,v 1.20 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-session.c,v 1.31 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-window.c,v 1.30 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-buffers.c,v 1.41 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-clients.c,v 1.42 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-commands.c,v 1.15 2026/02/24 08:22:13 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-keys.c,v 1.78 2026/07/01 13:12:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-panes.c,v 1.40 2026/06/01 14:01:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-sessions.c,v 1.36 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-windows.c,v 1.50 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-load-buffer.c,v 1.66 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-lock-server.c,v 1.31 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-move-window.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-session.c,v 1.152 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -325,7 +325,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
session_group_synchronize_to(s);
|
||||
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
|
||||
}
|
||||
notify_session("session-created", s);
|
||||
events_fire_session("session-created", s);
|
||||
|
||||
/*
|
||||
* Set the client to the new session. If a command client exists, it is
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-window.c,v 1.103 2026/07/08 08:07:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_window_entry = {
|
||||
.name = "new-window",
|
||||
.alias = "neww",
|
||||
|
||||
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
||||
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
||||
.args = { "abc:de:EF:kn:PSt:", 0, -1, NULL },
|
||||
.usage = "[-abdEkPS] [-c start-directory] [-e environment] [-F format] "
|
||||
"[-n window-name] " CMD_TARGET_WINDOW_USAGE
|
||||
" [shell-command [argument ...]]",
|
||||
|
||||
@@ -60,12 +60,19 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl, *new_wl = NULL;
|
||||
int idx = target->idx, before;
|
||||
int idx = target->idx, before, count = args_count(args);
|
||||
char *cause = NULL, *cp, *expanded, *wname = NULL;
|
||||
const char *template, *name;
|
||||
struct cmd_find_state fs;
|
||||
struct args_value *av;
|
||||
|
||||
if (args_has(args, 'E') &&
|
||||
count != 0 &&
|
||||
(count != 1 || *args_string(args, 0) != '\0')) {
|
||||
cmdq_error(item, "command cannot be given for empty pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* If -S and -n are given and -t is not and a single window with this
|
||||
* name already exists, select it.
|
||||
@@ -134,6 +141,8 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = 0;
|
||||
if (args_has(args, 'E') || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'k'))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-parse.y,v 1.58 2026/04/27 12:31:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-paste-buffer.c,v 1.44 2026/03/04 07:19:32 tb Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-pipe-pane.c,v 1.63 2026/04/28 08:47:55 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
70
cmd-queue.c
70
cmd-queue.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-queue.c,v 1.120 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -350,74 +350,53 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
|
||||
|
||||
/* Insert a hook. */
|
||||
void
|
||||
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
cmdq_insert_hook(__unused struct session *s, struct cmdq_item *item,
|
||||
struct cmd_find_state *current, const char *fmt, ...)
|
||||
{
|
||||
struct cmdq_state *state = item->state;
|
||||
struct cmd *cmd = item->cmd;
|
||||
struct args *args = cmd_get_args(cmd);
|
||||
struct args_entry *ae;
|
||||
struct args_value *av;
|
||||
struct options *oo;
|
||||
struct event_payload *ep;
|
||||
va_list ap;
|
||||
char *name, tmp[32], flag, *arguments;
|
||||
u_int i;
|
||||
const char *value;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmdq_state *new_state;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_parse_tree *tree;
|
||||
|
||||
if (item->state->flags & CMDQ_STATE_NOHOOKS)
|
||||
return;
|
||||
if (s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = s->options;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&name, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
log_debug("running hook %s (parent %p)", name, item);
|
||||
|
||||
/*
|
||||
* The hooks get a new state because they should not update the current
|
||||
* target or formats for any subsequent commands.
|
||||
*/
|
||||
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
|
||||
cmdq_add_format(new_state, "hook", "%s", name);
|
||||
ep = event_payload_create();
|
||||
if (current != NULL)
|
||||
event_payload_set_target(ep, current);
|
||||
event_payload_set_pointer(ep, "_cmdq_item", item, NULL, NULL);
|
||||
|
||||
arguments = args_print(args);
|
||||
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
|
||||
event_payload_set_string(ep, "arguments", "%s", arguments);
|
||||
free(arguments);
|
||||
|
||||
for (i = 0; i < args_count(args); i++) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
|
||||
cmdq_add_format(new_state, tmp, "%s", args_string(args, i));
|
||||
xsnprintf(tmp, sizeof tmp, "argument_%u", i);
|
||||
event_payload_set_string(ep, tmp, "%s", args_string(args, i));
|
||||
}
|
||||
flag = args_first(args, &ae);
|
||||
while (flag != 0) {
|
||||
value = args_get(args, flag);
|
||||
if (value == NULL) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
|
||||
cmdq_add_format(new_state, tmp, "1");
|
||||
} else {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
|
||||
cmdq_add_format(new_state, tmp, "%s", value);
|
||||
}
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c", flag);
|
||||
if (value == NULL)
|
||||
event_payload_set_string(ep, tmp, "1");
|
||||
else
|
||||
event_payload_set_string(ep, tmp, "%s", value);
|
||||
|
||||
i = 0;
|
||||
av = args_first_value(args, flag);
|
||||
while (av != NULL) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
|
||||
cmdq_add_format(new_state, tmp, "%s", av->string);
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c_%u", flag, i);
|
||||
event_payload_set_string(ep, tmp, "%s", av->string);
|
||||
i++;
|
||||
av = args_next_value(av);
|
||||
}
|
||||
@@ -425,20 +404,7 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
flag = args_next(&ae);
|
||||
}
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
tree = options_array_item_value(a)->cmd;
|
||||
if (tree != NULL) {
|
||||
new_item = cmd_invoke_get(tree, new_state, NULL);
|
||||
if (item != NULL)
|
||||
item = cmdq_insert_after(item, new_item);
|
||||
else
|
||||
item = cmdq_append(NULL, new_item);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
cmdq_free_state(new_state);
|
||||
events_fire(name, ep);
|
||||
free(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-refresh-client.c,v 1.54 2026/07/05 08:24:00 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -46,36 +46,17 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
||||
static void
|
||||
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
|
||||
{
|
||||
char *copy, *split, *name, *what;
|
||||
enum control_sub_type subtype;
|
||||
int subid = -1;
|
||||
char *name, *format;
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
|
||||
copy = name = xstrdup(value);
|
||||
if ((split = strchr(copy, ':')) == NULL) {
|
||||
control_remove_sub(tc, copy);
|
||||
goto out;
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
control_remove_sub(tc, value);
|
||||
return;
|
||||
}
|
||||
*split++ = '\0';
|
||||
|
||||
what = split;
|
||||
if ((split = strchr(what, ':')) == NULL)
|
||||
goto out;
|
||||
*split++ = '\0';
|
||||
|
||||
if (strcmp(what, "%*") == 0)
|
||||
subtype = CONTROL_SUB_ALL_PANES;
|
||||
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
|
||||
subtype = CONTROL_SUB_PANE;
|
||||
else if (strcmp(what, "@*") == 0)
|
||||
subtype = CONTROL_SUB_ALL_WINDOWS;
|
||||
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
|
||||
subtype = CONTROL_SUB_WINDOW;
|
||||
else
|
||||
subtype = CONTROL_SUB_SESSION;
|
||||
control_add_sub(tc, name, subtype, subid, split);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
control_add_sub(tc, name, type, id, format);
|
||||
free(name);
|
||||
free(format);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-session.c,v 1.39 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -49,6 +49,8 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
char *newname, *tmp;
|
||||
|
||||
tmp = format_single_from_target(item, args_string(args, 0));
|
||||
@@ -69,13 +71,20 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_session(ep, "session", s);
|
||||
event_payload_set_string(ep, "old_name", "%s", s->name);
|
||||
event_payload_set_string(ep, "new_name", "%s", newname);
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
free(s->name);
|
||||
s->name = newname;
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
server_status_session(s);
|
||||
notify_session("session-renamed", s);
|
||||
events_fire("session-renamed", ep);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-window.c,v 1.30 2026/06/29 18:17:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.67 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -182,7 +182,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (lc->parent != NULL)
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -270,10 +270,10 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
|
||||
if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
|
||||
/* Top left corner. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->sy + (ly - y);
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_xoff = x + 1; /* because mouse is on border at xoff - 1 */
|
||||
@@ -283,65 +283,65 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff - 1) {
|
||||
/* Top right corner. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->sy + (ly - y);
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, new_yoff);
|
||||
resizes++;
|
||||
} else if ((lx == left || lx == left + 1) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom left corner. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom right corner. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == right) {
|
||||
/* Right border. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == left) {
|
||||
/* Left border. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, lc->sy, new_xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, lc->g.sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff + sy) {
|
||||
/* Bottom border. */
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, lc->sx, new_sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, lc->g.sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff - 1) {
|
||||
/* Top border (move instead of resize). */
|
||||
new_xoff = lc->xoff + (x - lx);
|
||||
new_xoff = lc->g.xoff + (x - lx);
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, lc->sx, lc->sy, new_xoff, new_yoff);
|
||||
layout_set_size(lc, lc->g.sx, lc->g.sy, new_xoff, new_yoff);
|
||||
resizes++;
|
||||
}
|
||||
if (resizes != 0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-window.c,v 1.10 2023/06/30 13:19:32 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-pane.c,v 1.40 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
||||
.name = "respawn-pane",
|
||||
.alias = "respawnp",
|
||||
|
||||
.args = { "c:e:kt:", 0, -1, NULL },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
.args = { "c:e:Ekt:", 0, -1, NULL },
|
||||
.usage = "[-Ek] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -75,6 +75,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'E'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-window.c,v 1.51 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
||||
.name = "respawn-window",
|
||||
.alias = "respawnw",
|
||||
|
||||
.args = { "c:e:kt:", 0, -1, NULL },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
.args = { "c:e:Ekt:", 0, -1, NULL },
|
||||
.usage = "[-Ek] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
@@ -74,6 +74,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'E'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rotate-window.c,v 1.34 2026/06/22 08:47:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.91 2026/06/01 08:27:37 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-save-buffer.c,v 1.57 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-layout.c,v 1.43 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -139,7 +139,7 @@ changed:
|
||||
free(oldlayout);
|
||||
recalculate_sizes();
|
||||
server_redraw_window(w);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.76 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -80,6 +80,69 @@ cmd_select_pane_redraw(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *wp = target->wp, *lwp = NULL, *mwp;
|
||||
struct session *s = target->s;
|
||||
|
||||
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lwp = marked_pane.wp;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
mwp = marked_pane.wp;
|
||||
|
||||
ep = event_payload_create();
|
||||
if (mwp != NULL)
|
||||
cmd_find_from_pane(&fs, mwp, 0);
|
||||
else if (lwp != NULL)
|
||||
cmd_find_from_pane(&fs, lwp, 0);
|
||||
else
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
if (mwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", mwp);
|
||||
event_payload_set_pane(ep, "new_pane", mwp);
|
||||
event_payload_set_window(ep, "window", mwp->window);
|
||||
} else if (lwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", lwp);
|
||||
event_payload_set_window(ep, "window", lwp->window);
|
||||
} else {
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
}
|
||||
if (lwp != NULL)
|
||||
event_payload_set_pane(ep, "old_pane", lwp);
|
||||
event_payload_set_int(ep, "marked", mwp != NULL);
|
||||
events_fire("marked-pane-changed", ep);
|
||||
|
||||
if (lwp != NULL) {
|
||||
lwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lwp->window);
|
||||
server_status_window(lwp->window);
|
||||
}
|
||||
if (mwp != NULL) {
|
||||
mwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(mwp->window);
|
||||
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);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -88,10 +151,12 @@ cmd_select_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 client *c = cmdq_get_client(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp;
|
||||
struct options *oo = wp->options;
|
||||
char *title;
|
||||
const char *style;
|
||||
@@ -134,38 +199,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'm') || args_has(args, 'M')) {
|
||||
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lastwp = marked_pane.wp;
|
||||
else
|
||||
lastwp = NULL;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
markedwp = marked_pane.wp;
|
||||
|
||||
if (lastwp != NULL) {
|
||||
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lastwp->window);
|
||||
server_status_window(lastwp->window);
|
||||
}
|
||||
if (markedwp != NULL) {
|
||||
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(markedwp->window);
|
||||
server_status_window(markedwp->window);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_has(args, 'm') || args_has(args, 'M'))
|
||||
return (cmd_select_pane_marked_pane(self, item));
|
||||
|
||||
style = args_get(args, 'P');
|
||||
if (style != NULL) {
|
||||
@@ -218,7 +253,13 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
if (screen_set_title(&wp->base, title, 0)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-window.c,v 1.30 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-send-keys.c,v 1.81 2026/06/11 19:13:34 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-server-access.c,v 1.6 2026/06/09 12:58:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Dallas Lyons <dallasdlyons@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-buffer.c,v 1.37 2026/02/15 17:43:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
196
cmd-set-option.c
196
cmd-set-option.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-option.c,v 1.146 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -31,6 +31,10 @@ static enum args_parse_type cmd_set_option_args_parse(struct args *,
|
||||
u_int, char **);
|
||||
static enum cmd_retval cmd_set_option_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_event_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_monitor_exec(struct cmdq_item *,
|
||||
struct args *, int);
|
||||
|
||||
const struct cmd_entry cmd_set_option_entry = {
|
||||
.name = "set-option",
|
||||
@@ -62,8 +66,9 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agpRt:uw", 1, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
|
||||
.args = { "agpERTt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpERTuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
"[hook] [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -72,14 +77,152 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_set_option_args_parse(__unused struct args *args, u_int idx,
|
||||
cmd_set_option_args_parse(struct args *args, u_int idx,
|
||||
__unused char **cause)
|
||||
{
|
||||
if (args_has(args, 'B'))
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
if (idx == 1)
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
return (ARGS_PARSE_STRING);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_event_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct client *c;
|
||||
char *argument;
|
||||
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_count(args) != 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
if (*argument != '@') {
|
||||
cmdq_error(item, "event name must start with @");
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
event_payload_set_target(ep, target);
|
||||
c = cmdq_get_client(item);
|
||||
if (c != NULL)
|
||||
event_payload_set_client(ep, "client", c);
|
||||
if (target->s != NULL)
|
||||
event_payload_set_session(ep, "session", target->s);
|
||||
if (target->w != NULL)
|
||||
event_payload_set_window(ep, "window", target->w);
|
||||
if (target->wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", target->wl->idx);
|
||||
else if (target->idx != -1)
|
||||
event_payload_set_int(ep, "window_index", target->idx);
|
||||
if (target->wp != NULL)
|
||||
event_payload_set_pane(ep, "pane", target->wp);
|
||||
events_fire(argument, ep);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item), fs;
|
||||
struct options *oo;
|
||||
struct options_entry *o;
|
||||
struct session *s = NULL;
|
||||
char *cause = NULL, *name = NULL, *format = NULL;
|
||||
char *expanded = NULL, *newvalue = NULL;
|
||||
const char *value, *old;
|
||||
enum monitor_type type;
|
||||
int id, scope, flags = 0;
|
||||
|
||||
if (args_count(args) > 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
value = args_get(args, 'B');
|
||||
if (args_has(args, 'u')) {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0)
|
||||
name = xstrdup(value);
|
||||
free(format);
|
||||
format = NULL;
|
||||
} else {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
cmdq_error(item, "invalid subscription: %s", value);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (*name != '@') {
|
||||
cmdq_error(item, "monitor hook name must start with @");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
scope = options_scope_from_name(args, window, name, target, &oo,
|
||||
&cause);
|
||||
if (scope == OPTIONS_TABLE_NONE) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
cmd_find_copy_state(&fs, target);
|
||||
|
||||
if (args_has(args, 'u')) {
|
||||
hooks_monitor_remove(oo, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (args_count(args) != 0) {
|
||||
value = args_string(args, 0);
|
||||
if (args_has(args, 'F')) {
|
||||
expanded = format_single_from_target(item, value);
|
||||
value = expanded;
|
||||
}
|
||||
o = options_get_only(oo, name);
|
||||
if (!args_has(args, 'o') || o == NULL) {
|
||||
if (args_has(args, 'a') && o != NULL) {
|
||||
old = options_get_string(oo, name);
|
||||
xasprintf(&newvalue, "%s%s", old, value);
|
||||
value = newvalue;
|
||||
}
|
||||
options_set_string(oo, name, 0, "%s", value);
|
||||
options_push_changes(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (oo != global_options &&
|
||||
oo != global_s_options &&
|
||||
oo != global_w_options)
|
||||
s = target->s;
|
||||
if (args_has(args, 'T'))
|
||||
flags |= MONITOR_NOTIFY_TRUE;
|
||||
hooks_monitor_add(item, oo, name, type, id, format, flags, &fs, s);
|
||||
|
||||
out:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -89,26 +232,34 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *loop;
|
||||
struct options *oo;
|
||||
struct options_entry *parent, *o, *po;
|
||||
char *name, *argument, *expanded = NULL;
|
||||
char *cause;
|
||||
char *name, *argument, *cause;
|
||||
char *expanded = NULL, *array_key = NULL;
|
||||
const char *value;
|
||||
int window, idx, already, error, ambiguous;
|
||||
int window, already, error, ambiguous;
|
||||
int scope;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'E'))
|
||||
return (cmd_set_hook_event_exec(self, item));
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'B'))
|
||||
return (cmd_set_hook_monitor_exec(item, args, window));
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
/* Expand argument. */
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
/* If set-hook -R, fire the hook straight away. */
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
|
||||
notify_hook(item, argument);
|
||||
hooks_run(item, argument);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Parse option name and index. */
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
/* Parse option name and array key. */
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -140,21 +291,23 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
o = options_get_only(oo, name);
|
||||
parent = options_get(oo, name);
|
||||
|
||||
/* Check that array options and indexes match up. */
|
||||
if (idx != -1 && (*name == '@' || !options_is_array(parent))) {
|
||||
/* Check that array options and keys match up. */
|
||||
if (array_key != NULL && (*name == '@' || !options_is_array(parent))) {
|
||||
cmdq_error(item, "not an array: %s", argument);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* With -o, check this option is not already set. */
|
||||
if (!args_has(args, 'u') && args_has(args, 'o')) {
|
||||
if (idx == -1)
|
||||
if (array_key == NULL)
|
||||
already = (o != NULL);
|
||||
else {
|
||||
if (o == NULL)
|
||||
already = 0;
|
||||
else if (options_array_get(o, array_key) != NULL)
|
||||
already = 1;
|
||||
else
|
||||
already = (options_array_get(o, idx) != NULL);
|
||||
already = 0;
|
||||
}
|
||||
if (already) {
|
||||
if (args_has(args, 'q'))
|
||||
@@ -170,7 +323,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
po = options_get_only(loop->options, name);
|
||||
if (po == NULL)
|
||||
continue;
|
||||
if (options_remove_or_default(po, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(po, array_key,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -180,7 +334,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'u') || args_has(args, 'U')) {
|
||||
if (o == NULL)
|
||||
goto out;
|
||||
if (options_remove_or_default(o, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(o, array_key, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -191,7 +345,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(oo, name, append, "%s", value);
|
||||
} else if (idx == -1 && !options_is_array(parent)) {
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry)
|
||||
hooks_add_event(name);
|
||||
} else if (array_key == NULL && !options_is_array(parent)) {
|
||||
error = options_from_string(oo, options_table_entry(parent),
|
||||
options_table_entry(parent)->name, value,
|
||||
args_has(args, 'a'), &cause);
|
||||
@@ -207,7 +363,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
if (o == NULL)
|
||||
o = options_empty(oo, options_table_entry(parent));
|
||||
if (idx == -1) {
|
||||
if (array_key == NULL) {
|
||||
if (!append)
|
||||
options_array_clear(o);
|
||||
if (options_array_assign(o, value, &cause) != 0) {
|
||||
@@ -215,7 +371,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
} else if (options_array_set(o, idx, value, append,
|
||||
} else if (options_array_set(o, array_key, value, append,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
@@ -229,11 +385,13 @@ out:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-messages.c,v 1.37 2025/11/18 08:37:54 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-options.c,v 1.73 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -30,7 +30,11 @@
|
||||
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
|
||||
struct options_entry *, int, int);
|
||||
struct options_entry *, const char *, int);
|
||||
static void cmd_show_hooks_print_monitor(struct cmdq_item *,
|
||||
struct options_entry *);
|
||||
static enum cmd_retval cmd_show_hooks_monitor(struct cmd *, struct cmdq_item *,
|
||||
int, struct options *);
|
||||
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
|
||||
int, struct options *);
|
||||
|
||||
@@ -64,8 +68,8 @@ const struct cmd_entry cmd_show_hooks_entry = {
|
||||
.name = "show-hooks",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gpt:w", 0, 1, NULL },
|
||||
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
.args = { "Bgpt:w", 0, 1, NULL },
|
||||
.usage = "[-Bgpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -80,7 +84,8 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct options *oo;
|
||||
char *argument, *name = NULL, *cause;
|
||||
int window, idx, ambiguous, parent, scope;
|
||||
char *array_key = NULL;
|
||||
int window, ambiguous, parent, scope;
|
||||
struct options_entry *o;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
|
||||
@@ -95,11 +100,14 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B'))
|
||||
return (cmd_show_hooks_monitor(self, item, scope, oo));
|
||||
return (cmd_show_options_all(self, item, scope, oo));
|
||||
}
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -124,8 +132,13 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
parent = 1;
|
||||
} else
|
||||
parent = 0;
|
||||
if (o != NULL)
|
||||
cmd_show_options_print(self, item, o, idx, parent);
|
||||
if (o != NULL) {
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B'))
|
||||
cmd_show_hooks_print_monitor(item, o);
|
||||
else
|
||||
cmd_show_options_print(self, item, o, array_key, parent);
|
||||
}
|
||||
else if (*name == '@') {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -135,26 +148,28 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
out:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
struct options_entry *o, int idx, int parent)
|
||||
struct options_entry *o, const char *array_key, int parent)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct options_array_item *a;
|
||||
const char *name = options_name(o);
|
||||
char *value, *tmp = NULL, *escaped;
|
||||
|
||||
if (idx != -1) {
|
||||
xasprintf(&tmp, "%s[%d]", name, idx);
|
||||
if (array_key != NULL) {
|
||||
xasprintf(&tmp, "%s[%s]", name, array_key);
|
||||
name = tmp;
|
||||
} else {
|
||||
if (options_is_array(o)) {
|
||||
@@ -165,8 +180,8 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
return;
|
||||
}
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
array_key = options_array_item_key(a);
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
@@ -174,7 +189,7 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
}
|
||||
}
|
||||
|
||||
value = options_to_string(o, idx, 0);
|
||||
value = options_to_string(o, array_key, 0);
|
||||
if (args_has(args, 'v'))
|
||||
cmdq_print(item, "%s", value);
|
||||
else if (options_is_string(o)) {
|
||||
@@ -195,6 +210,33 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_hooks_print_monitor(struct cmdq_item *item, struct options_entry *o)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = hooks_monitor_to_string(o);
|
||||
if (value == NULL)
|
||||
return;
|
||||
cmdq_print(item, "%s", value);
|
||||
free(value);
|
||||
}
|
||||
|
||||
/* Show all hook monitors. */
|
||||
static enum cmd_retval
|
||||
cmd_show_hooks_monitor(__unused struct cmd *self, struct cmdq_item *item,
|
||||
__unused int scope, struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
cmd_show_hooks_print_monitor(item, o);
|
||||
o = options_next(o);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
struct options *oo)
|
||||
@@ -203,15 +245,14 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
const struct options_table_entry *oe;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
const char *name;
|
||||
u_int idx;
|
||||
const char *name, *array_key;
|
||||
int parent;
|
||||
|
||||
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
if (options_table_entry(o) == NULL)
|
||||
cmd_show_options_print(self, item, o, -1, 0);
|
||||
cmd_show_options_print(self, item, o, NULL, 0);
|
||||
o = options_next(o);
|
||||
}
|
||||
}
|
||||
@@ -238,7 +279,7 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
parent = 0;
|
||||
|
||||
if (!options_is_array(o))
|
||||
cmd_show_options_print(self, item, o, -1, parent);
|
||||
cmd_show_options_print(self, item, o, NULL, parent);
|
||||
else if ((a = options_array_first(o)) == NULL) {
|
||||
if (!args_has(args, 'v')) {
|
||||
name = options_name(o);
|
||||
@@ -249,8 +290,8 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
}
|
||||
} else {
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
array_key = options_array_item_key(a);
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-prompt-history.c,v 1.5 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Anindya Mukherjee <anindya49@hotmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-source-file.c,v 1.62 2025/11/18 08:42:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-split-window.c,v 1.141 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -81,8 +81,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = target->wp, *new_wp;
|
||||
struct window_pane *wp = target->wp, *new_wp = NULL;
|
||||
struct layout_cell *lc = NULL;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
int input, empty, is_floating, flags = 0;
|
||||
const char *template, *style, *value;
|
||||
@@ -104,7 +105,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
|
||||
input = args_has(args, 'I');
|
||||
if (input)
|
||||
if (input || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
empty = 1;
|
||||
else
|
||||
empty = args_has(args, 'E');
|
||||
@@ -167,6 +168,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
/*
|
||||
* spawn_pane has already torn the half-built pane down (its
|
||||
* fork-failure path removes the pane and destroys the layout
|
||||
* cell), so new_wp is NULL and there is nothing for fail to do.
|
||||
*/
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -212,17 +218,19 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
screen_set_title(&new_wp->base, title, 0);
|
||||
notify_pane("pane-title-changed", new_wp);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, new_wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", new_wp);
|
||||
event_payload_set_window(ep, "window", new_wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
free(title);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
switch (window_pane_start_input(new_wp, item, &cause)) {
|
||||
case -1:
|
||||
server_client_remove_pane(new_wp);
|
||||
if (!is_floating)
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -269,10 +277,20 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
/*
|
||||
* If the pane was spawned before we failed, tear it down here; this
|
||||
* also destroys its layout cell. spawn_pane's own failure path has
|
||||
* already done this, so new_wp is NULL in that case.
|
||||
*/
|
||||
if (new_wp != NULL) {
|
||||
server_client_remove_pane(new_wp);
|
||||
if (!is_floating)
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
}
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
layout_destroy_cell(w, lc, &w->layout_root);
|
||||
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-pane.c,v 1.53 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -42,6 +42,22 @@ const struct cmd_entry cmd_swap_pane_entry = {
|
||||
.exec = cmd_swap_pane_exec
|
||||
};
|
||||
|
||||
static struct window_pane *
|
||||
cmd_swap_pane_next_tiled_pane(struct window_pane *wp)
|
||||
{
|
||||
while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
|
||||
wp = TAILQ_NEXT(wp, entry);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
static struct window_pane *
|
||||
cmd_swap_pane_prev_tiled_pane(struct window_pane *wp)
|
||||
{
|
||||
while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
|
||||
wp = TAILQ_PREV(wp, window_panes, entry);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -62,15 +78,29 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
if (args_has(args, 'D')) {
|
||||
if (window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "cannot swap down on floating pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
src_w = dst_w;
|
||||
src_wp = TAILQ_NEXT(dst_wp, entry);
|
||||
if (src_wp == NULL)
|
||||
src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
|
||||
if (src_wp == NULL) {
|
||||
src_wp = TAILQ_FIRST(&dst_w->panes);
|
||||
src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
|
||||
}
|
||||
} else if (args_has(args, 'U')) {
|
||||
if (window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "cannot swap up on floating pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
src_w = dst_w;
|
||||
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
|
||||
if (src_wp == NULL)
|
||||
src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
|
||||
if (src_wp == NULL) {
|
||||
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
|
||||
src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z')))
|
||||
@@ -79,12 +109,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (src_wp == dst_wp)
|
||||
goto out;
|
||||
|
||||
if (window_pane_is_floating(src_wp) ||
|
||||
window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "cannot swap floating panes");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
server_client_remove_pane(src_wp);
|
||||
server_client_remove_pane(dst_wp);
|
||||
|
||||
@@ -156,9 +180,9 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
redraw_invalidate_scene(dst_w);
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
notify_window("window-layout-changed", src_w);
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
if (src_w != dst_w)
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
out:
|
||||
if (window_pop_zoom(src_w))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-window.c,v 1.29 2025/10/30 13:52:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-switch-client.c,v 1.74 2026/05/22 15:22:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-unbind-key.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
261
cmd-wait-for.c
261
cmd-wait-for.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-wait-for.c,v 1.23 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_wait_for_entry = {
|
||||
.name = "wait-for",
|
||||
.alias = "wait",
|
||||
|
||||
.args = { "LSU", 1, 1, NULL },
|
||||
.usage = "[-L|-S|-U] channel",
|
||||
.args = { "EF:LSUlvw:", 1, 1, NULL },
|
||||
.usage = "[-ELSUlv] [-F format] [-w waiter] name",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_wait_for_exec
|
||||
@@ -46,6 +46,17 @@ struct wait_item {
|
||||
TAILQ_ENTRY(wait_item) entry;
|
||||
};
|
||||
|
||||
struct wait_event_item {
|
||||
struct cmdq_item *item;
|
||||
struct events_sink *sink;
|
||||
char *name;
|
||||
char *filter;
|
||||
int verbose;
|
||||
TAILQ_ENTRY(wait_event_item) entry;
|
||||
};
|
||||
static TAILQ_HEAD(, wait_event_item) wait_event_items =
|
||||
TAILQ_HEAD_INITIALIZER(wait_event_items);
|
||||
|
||||
struct wait_channel {
|
||||
const char *name;
|
||||
int locked;
|
||||
@@ -76,9 +87,28 @@ static enum cmd_retval cmd_wait_for_lock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *,
|
||||
struct args *);
|
||||
static void cmd_wait_for_event_cb(const char *,
|
||||
struct event_payload *, void *);
|
||||
static void cmd_wait_for_event_free(struct wait_event_item *);
|
||||
static enum cmd_retval cmd_wait_for_event_list(struct cmdq_item *,
|
||||
const char *);
|
||||
static enum cmd_retval cmd_wait_for_event_wake(struct cmdq_item *,
|
||||
const char *, struct args *);
|
||||
static enum cmd_retval cmd_wait_for_list(struct cmdq_item *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_wake(struct cmdq_item *, const char *,
|
||||
struct args *, struct wait_channel *);
|
||||
|
||||
static struct wait_channel *cmd_wait_for_add(const char *);
|
||||
static void cmd_wait_for_remove(struct wait_channel *);
|
||||
static void cmd_wait_for_remove_empty(
|
||||
struct wait_channel *);
|
||||
static const char *cmd_wait_for_item_client_name(
|
||||
struct cmdq_item *);
|
||||
static const char *cmd_wait_for_client_name(
|
||||
struct wait_event_item *);
|
||||
|
||||
static struct wait_channel *
|
||||
cmd_wait_for_add(const char *name)
|
||||
@@ -117,16 +147,53 @@ cmd_wait_for_remove(struct wait_channel *wc)
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_remove_empty(struct wait_channel *wc)
|
||||
{
|
||||
if (wc->locked || wc->woken)
|
||||
return;
|
||||
if (!TAILQ_EMPTY(&wc->waiters) || !TAILQ_EMPTY(&wc->lockers))
|
||||
return;
|
||||
|
||||
log_debug("remove empty wait channel %s", wc->name);
|
||||
|
||||
RB_REMOVE(wait_channels, &wait_channels, wc);
|
||||
|
||||
free((void *)wc->name);
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_item_client_name(struct cmdq_item *item)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
|
||||
if (c == NULL || c->name == NULL)
|
||||
return ("");
|
||||
return (c->name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_client_name(struct wait_event_item *wei)
|
||||
{
|
||||
return (cmd_wait_for_item_client_name(wei->item));
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *name = args_string(args, 0);
|
||||
struct wait_channel *wc, find;
|
||||
struct wait_channel *wc, find = { .name = name };
|
||||
|
||||
if (args_has(args, 'E'))
|
||||
return (cmd_wait_for_event(item, name, args));
|
||||
|
||||
find.name = name;
|
||||
wc = RB_FIND(wait_channels, &wait_channels, &find);
|
||||
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_list(item, wc));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_wake(item, name, args, wc));
|
||||
if (args_has(args, 'S'))
|
||||
return (cmd_wait_for_signal(item, name, wc));
|
||||
if (args_has(args, 'L'))
|
||||
@@ -136,6 +203,179 @@ cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (cmd_wait_for_wait(item, name, wc));
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_print(struct wait_event_item *wei, struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
const char *key;
|
||||
char *value;
|
||||
|
||||
epi = event_payload_first(ep);
|
||||
while (epi != NULL) {
|
||||
key = event_payload_item_name(epi);
|
||||
if (*key != '_') {
|
||||
value = event_payload_item_print(epi);
|
||||
cmdq_print(wei->item, "%s=%s", key, value);
|
||||
free(value);
|
||||
}
|
||||
epi = event_payload_next(epi);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(__unused const char *name, struct event_payload *ep,
|
||||
void *item_data)
|
||||
{
|
||||
struct wait_event_item *wei = item_data;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (wei->verbose)
|
||||
cmd_wait_for_event_print(wei, ep);
|
||||
|
||||
if (wei->filter != NULL) {
|
||||
ft = format_create(cmdq_get_client(wei->item), wei->item,
|
||||
FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, NULL);
|
||||
expanded = format_expand(ft, wei->filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_free(struct wait_event_item *wei)
|
||||
{
|
||||
events_remove_sink(wei->sink);
|
||||
free(wei->name);
|
||||
free(wei->filter);
|
||||
free(wei);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event(struct cmdq_item *item, const char *name, struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
const char *filter = args_get(args, 'F');
|
||||
|
||||
if (!hooks_valid_event_name(name)) {
|
||||
cmdq_error(item, "invalid event: %s", name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_event_list(item, name));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_event_wake(item, name, args));
|
||||
|
||||
if (cmdq_get_client(item) == NULL) {
|
||||
cmdq_error(item, "not able to wait");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
wei = xcalloc(1, sizeof *wei);
|
||||
wei->item = item;
|
||||
wei->name = xstrdup(name);
|
||||
wei->filter = (filter != NULL ? xstrdup(filter) : NULL);
|
||||
wei->verbose = args_has(args, 'v');
|
||||
wei->sink = events_add_sink(name, cmd_wait_for_event_cb, wei);
|
||||
TAILQ_INSERT_TAIL(&wait_event_items, wei, entry);
|
||||
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_list(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
|
||||
TAILQ_FOREACH(wei, &wait_event_items, entry) {
|
||||
if (strcmp(wei->name, name) == 0)
|
||||
cmdq_print(item, "%s", cmd_wait_for_client_name(wei));
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_wake(struct cmdq_item *item, const char *name,
|
||||
struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei, *wei1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
if (strcmp(wei->name, name) != 0)
|
||||
continue;
|
||||
if (strcmp(cmd_wait_for_client_name(wei), client_name) != 0)
|
||||
continue;
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cmdq_error(item, "waiter %s not found", client_name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_list(struct cmdq_item *item, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi;
|
||||
|
||||
if (wc == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
TAILQ_FOREACH(wi, &wc->waiters, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
TAILQ_FOREACH(wi, &wc->lockers, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_wake(__unused struct cmdq_item *item, const char *name,
|
||||
struct args *args, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi, *wi1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
if (wc != NULL) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->waiters, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->lockers, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
|
||||
struct wait_channel *wc)
|
||||
@@ -245,6 +485,13 @@ cmd_wait_for_flush(void)
|
||||
{
|
||||
struct wait_channel *wc, *wc1;
|
||||
struct wait_item *wi, *wi1;
|
||||
struct wait_event_item *wei, *wei1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
|
||||
11
cmd.c
11
cmd.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd.c,v 1.186 2026/07/12 20:35:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -646,7 +646,7 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
char ch, *buf;
|
||||
const char *ptr, *cp, quote[] = "\"\\$;~";
|
||||
int replaced, quoted;
|
||||
size_t len;
|
||||
size_t len, slen;
|
||||
|
||||
if (strchr(template, '%') == NULL)
|
||||
return (xstrdup(template));
|
||||
@@ -671,7 +671,10 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
if (quoted)
|
||||
ptr++;
|
||||
|
||||
buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
|
||||
slen = strlen(s);
|
||||
if (slen > SIZE_MAX / 3 || len > SIZE_MAX - (slen * 3) - 1)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + (slen * 3) + 1);
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (quoted && strchr(quote, *cp) != NULL)
|
||||
buf[len++] = '\\';
|
||||
@@ -680,6 +683,8 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
buf[len] = '\0';
|
||||
continue;
|
||||
}
|
||||
if (len > SIZE_MAX - 2)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + 2);
|
||||
buf[len++] = ch;
|
||||
buf[len] = '\0';
|
||||
|
||||
16
colour.c
16
colour.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: colour.c,v 1.35 2026/07/06 14:29:10 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1294,7 +1294,8 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
u_int i, n;
|
||||
union options_value *ov;
|
||||
u_int i;
|
||||
int c;
|
||||
|
||||
if (p == NULL)
|
||||
@@ -1312,12 +1313,11 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
p->default_palette = xcalloc(256, sizeof *p->default_palette);
|
||||
for (i = 0; i < 256; i++)
|
||||
p->default_palette[i] = -1;
|
||||
while (a != NULL) {
|
||||
n = options_array_item_index(a);
|
||||
if (n < 256) {
|
||||
c = options_array_item_value(a)->number;
|
||||
p->default_palette[n] = c;
|
||||
for (i = 0; i < 256; i++) {
|
||||
ov = options_array_getv(o, "%u", i);
|
||||
if (ov != NULL) {
|
||||
c = ov->number;
|
||||
p->default_palette[i] = c;
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +74,14 @@ getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
size_t nbufsiz;
|
||||
ssize_t d = ptr - *buf;
|
||||
|
||||
if (*bufsiz > SIZE_MAX / 2) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
nbufsiz = *bufsiz * 2;
|
||||
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# configure.ac
|
||||
|
||||
AC_INIT([tmux], next-3.7)
|
||||
AC_INIT([tmux], next-3.8)
|
||||
AC_PREREQ([2.60])
|
||||
|
||||
AC_CONFIG_AUX_DIR(etc)
|
||||
@@ -78,7 +78,7 @@ AC_ARG_ENABLE(
|
||||
asan,
|
||||
AS_HELP_STRING(--enable-asan, enable ASAN build flags),
|
||||
,
|
||||
enable_asan=no
|
||||
[case "x$host_os" in *darwin*) enable_asan=yes;; esac]
|
||||
)
|
||||
AM_CONDITIONAL(IS_ASAN, test "x$enable_asan" = xyes)
|
||||
|
||||
|
||||
215
control-notify.c
215
control-notify.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control-notify.c,v 1.37 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -23,31 +23,56 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Should this client be sent events? */
|
||||
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
|
||||
((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \
|
||||
((c) != NULL && \
|
||||
((c)->flags & CLIENT_CONTROL) && \
|
||||
(~(c)->flags & CLIENT_EXIT) && \
|
||||
(c)->control_state != NULL)
|
||||
|
||||
void
|
||||
control_notify_pane_mode_changed(int pane)
|
||||
/* Notify control clients that pane mode changed. */
|
||||
static void
|
||||
control_pane_mode_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct window_pane *wp;
|
||||
struct client *c;
|
||||
char *value;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%pane-mode-changed %%%u", pane);
|
||||
wp = event_payload_get_pane(ep, "pane");
|
||||
if (wp != NULL) {
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
control_write(c, "%%pane-mode-changed %%%u", wp->id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
value = event_payload_print(ep, "pane");
|
||||
if (value == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
control_write(c, "%%pane-mode-changed %s", value);
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_layout_changed(struct window *w)
|
||||
/* Notify control clients that window layout changed. */
|
||||
static void
|
||||
control_window_layout_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
const char *template;
|
||||
char *cp;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
const char *template;
|
||||
char *cp;
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
|
||||
template = "%layout-change #{window_id} #{window_layout} "
|
||||
"#{window_visible_layout} #{window_raw_flags}";
|
||||
@@ -72,12 +97,15 @@ control_notify_window_layout_changed(struct window *w)
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_pane_changed(struct window *w)
|
||||
/* Notify control clients that window pane changed. */
|
||||
static void
|
||||
control_window_pane_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w->active == NULL)
|
||||
if (w == NULL || w->active == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
@@ -88,12 +116,17 @@ control_notify_window_pane_changed(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_unlinked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was unlinked. */
|
||||
static void
|
||||
control_window_unlinked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -106,12 +139,17 @@ control_notify_window_unlinked(__unused struct session *s, struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_linked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was linked. */
|
||||
static void
|
||||
control_window_linked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -124,12 +162,17 @@ control_notify_window_linked(__unused struct session *s, struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_renamed(struct window *w)
|
||||
/* Notify control clients that a window was renamed. */
|
||||
static void
|
||||
control_window_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -145,13 +188,16 @@ control_notify_window_renamed(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_session_changed(struct client *cc)
|
||||
/* Notify control clients that a client changed session. */
|
||||
static void
|
||||
control_client_session_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
|
||||
if (cc->session == NULL)
|
||||
if (cc == NULL || cc->session == NULL)
|
||||
return;
|
||||
s = cc->session;
|
||||
|
||||
@@ -169,22 +215,32 @@ control_notify_client_session_changed(struct client *cc)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_detached(struct client *cc)
|
||||
/* Notify control clients that a client detached. */
|
||||
static void
|
||||
control_client_detached_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
|
||||
if (cc == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
control_write(c, "%%client-detached %s", cc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_renamed(struct session *s)
|
||||
/* Notify control clients that a session was renamed. */
|
||||
static void
|
||||
control_session_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
@@ -193,8 +249,10 @@ control_notify_session_renamed(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_created(__unused struct session *s)
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_created_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
@@ -206,8 +264,10 @@ control_notify_session_created(__unused struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_closed(__unused struct session *s)
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_closed_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
@@ -219,9 +279,12 @@ control_notify_session_closed(__unused struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_window_changed(struct session *s)
|
||||
/* Notify control clients that the current window changed. */
|
||||
static void
|
||||
control_session_window_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
/*
|
||||
@@ -229,7 +292,7 @@ control_notify_session_window_changed(struct session *s)
|
||||
* session has been destroyed (which sets curw to NULL) but is kept
|
||||
* alive by the notification's reference. Skip the notification.
|
||||
*/
|
||||
if (s->curw == NULL)
|
||||
if (s == NULL || s->curw == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
@@ -241,28 +304,68 @@ control_notify_session_window_changed(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_paste_buffer_changed(const char *name)
|
||||
/* Notify control clients that a paste buffer changed. */
|
||||
static void
|
||||
control_paste_buffer_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-changed %s", name);
|
||||
control_write(c, "%%paste-buffer-changed %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_paste_buffer_deleted(const char *name)
|
||||
/* Notify control clients that a paste buffer was deleted. */
|
||||
static void
|
||||
control_paste_buffer_deleted_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-deleted %s", name);
|
||||
control_write(c, "%%paste-buffer-deleted %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build control event sinks. */
|
||||
void
|
||||
control_build_events(void)
|
||||
{
|
||||
/* Control event sink callbacks. */
|
||||
static struct {
|
||||
const char *name;
|
||||
events_cb cb;
|
||||
} events[] = {
|
||||
{ "pane-mode-changed", control_pane_mode_changed_cb },
|
||||
{ "window-layout-changed", control_window_layout_changed_cb },
|
||||
{ "window-pane-changed", control_window_pane_changed_cb },
|
||||
{ "window-unlinked", control_window_unlinked_cb },
|
||||
{ "window-linked", control_window_linked_cb },
|
||||
{ "window-renamed", control_window_renamed_cb },
|
||||
{ "client-session-changed", control_client_session_changed_cb },
|
||||
{ "client-detached", control_client_detached_cb },
|
||||
{ "session-renamed", control_session_renamed_cb },
|
||||
{ "session-created", control_session_created_cb },
|
||||
{ "session-closed", control_session_closed_cb },
|
||||
{ "session-window-changed", control_session_window_changed_cb },
|
||||
{ "paste-buffer-changed", control_paste_buffer_changed_cb },
|
||||
{ "paste-buffer-deleted", control_paste_buffer_deleted_cb }
|
||||
};
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(events); i++)
|
||||
events_add_sink(events[i].name, events[i].cb, NULL);
|
||||
}
|
||||
|
||||
506
control.c
506
control.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control.c,v 1.61 2026/07/10 15:45:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -75,42 +78,6 @@ struct control_pane {
|
||||
};
|
||||
RB_HEAD(control_panes, control_pane);
|
||||
|
||||
/* Subscription pane. */
|
||||
struct control_sub_pane {
|
||||
u_int pane;
|
||||
u_int idx;
|
||||
char *last;
|
||||
|
||||
RB_ENTRY(control_sub_pane) entry;
|
||||
};
|
||||
RB_HEAD(control_sub_panes, control_sub_pane);
|
||||
|
||||
/* Subscription window. */
|
||||
struct control_sub_window {
|
||||
u_int window;
|
||||
u_int idx;
|
||||
char *last;
|
||||
|
||||
RB_ENTRY(control_sub_window) entry;
|
||||
};
|
||||
RB_HEAD(control_sub_windows, control_sub_window);
|
||||
|
||||
/* Control client subscription. */
|
||||
struct control_sub {
|
||||
char *name;
|
||||
char *format;
|
||||
|
||||
enum control_sub_type type;
|
||||
u_int id;
|
||||
|
||||
char *last;
|
||||
struct control_sub_panes panes;
|
||||
struct control_sub_windows windows;
|
||||
|
||||
RB_ENTRY(control_sub) entry;
|
||||
};
|
||||
RB_HEAD(control_subs, control_sub);
|
||||
|
||||
/* Control client state. */
|
||||
struct control_state {
|
||||
struct control_panes panes;
|
||||
@@ -123,8 +90,7 @@ struct control_state {
|
||||
struct bufferevent *read_event;
|
||||
struct bufferevent *write_event;
|
||||
|
||||
struct control_subs subs;
|
||||
struct event subs_timer;
|
||||
struct monitor_set *subs;
|
||||
};
|
||||
|
||||
/* Low and high watermarks. */
|
||||
@@ -154,75 +120,6 @@ control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
|
||||
}
|
||||
RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
|
||||
|
||||
/* Compare client subs. */
|
||||
static int
|
||||
control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2)
|
||||
{
|
||||
return (strcmp(csub1->name, csub2->name));
|
||||
}
|
||||
RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp);
|
||||
|
||||
/* Compare client subscription panes. */
|
||||
static int
|
||||
control_sub_pane_cmp(struct control_sub_pane *csp1,
|
||||
struct control_sub_pane *csp2)
|
||||
{
|
||||
if (csp1->pane < csp2->pane)
|
||||
return (-1);
|
||||
if (csp1->pane > csp2->pane)
|
||||
return (1);
|
||||
if (csp1->idx < csp2->idx)
|
||||
return (-1);
|
||||
if (csp1->idx > csp2->idx)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry,
|
||||
control_sub_pane_cmp);
|
||||
|
||||
/* Compare client subscription windows. */
|
||||
static int
|
||||
control_sub_window_cmp(struct control_sub_window *csw1,
|
||||
struct control_sub_window *csw2)
|
||||
{
|
||||
if (csw1->window < csw2->window)
|
||||
return (-1);
|
||||
if (csw1->window > csw2->window)
|
||||
return (1);
|
||||
if (csw1->idx < csw2->idx)
|
||||
return (-1);
|
||||
if (csw1->idx > csw2->idx)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry,
|
||||
control_sub_window_cmp);
|
||||
|
||||
/* Free a subscription. */
|
||||
static void
|
||||
control_free_sub(struct control_state *cs, struct control_sub *csub)
|
||||
{
|
||||
struct control_sub_pane *csp, *csp1;
|
||||
struct control_sub_window *csw, *csw1;
|
||||
|
||||
RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
|
||||
RB_REMOVE(control_sub_panes, &csub->panes, csp);
|
||||
free(csp->last);
|
||||
free(csp);
|
||||
}
|
||||
RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
|
||||
RB_REMOVE(control_sub_windows, &csub->windows, csw);
|
||||
free(csw->last);
|
||||
free(csw);
|
||||
}
|
||||
free(csub->last);
|
||||
|
||||
RB_REMOVE(control_subs, &cs->subs, csub);
|
||||
free(csub->name);
|
||||
free(csub->format);
|
||||
free(csub);
|
||||
}
|
||||
|
||||
/* Free a block. */
|
||||
static void
|
||||
control_free_block(struct control_state *cs, struct control_block *cb)
|
||||
@@ -481,7 +378,7 @@ control_write_output(struct client *c, struct window_pane *wp)
|
||||
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
||||
return;
|
||||
|
||||
if (c->flags & CONTROL_IGNORE_FLAGS) {
|
||||
if (c->flags & (CONTROL_IGNORE_FLAGS|CLIENT_EXIT)) {
|
||||
cp = control_get_pane(c, wp);
|
||||
if (cp != NULL)
|
||||
goto ignore;
|
||||
@@ -597,6 +494,53 @@ control_all_done(struct client *c)
|
||||
return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the terminal to send an empty line or close, used by a control
|
||||
* client after printing %exit so a wrapping terminal (such as iTerm2) can
|
||||
* finish reading.
|
||||
*/
|
||||
void
|
||||
control_wait_exit(int fd)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
struct evbuffer *evb;
|
||||
char *line;
|
||||
int n;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
for (;;) {
|
||||
line = evbuffer_readln(evb, NULL, EVBUFFER_EOL_LF);
|
||||
if (line != NULL) {
|
||||
if (*line == '\0') { /* empty line, stop */
|
||||
free(line);
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
continue; /* drain buffered lines first */
|
||||
}
|
||||
|
||||
memset(&pfd, 0, sizeof pfd);
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
if (poll(&pfd, 1, INFTIM) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
n = evbuffer_read(evb, fd, -1);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n == -1 && errno != EAGAIN && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
evbuffer_free(evb);
|
||||
}
|
||||
|
||||
/* Flush all blocks until output. */
|
||||
static void
|
||||
control_flush_all_blocks(struct client *c)
|
||||
@@ -772,6 +716,30 @@ control_write_callback(__unused struct bufferevent *bufev, void *data)
|
||||
bufferevent_disable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
/* Write a subscription change. */
|
||||
static void
|
||||
control_sub_change(struct monitor_change *change, __unused void *data)
|
||||
{
|
||||
struct client *c = change->c;
|
||||
struct session *s = change->s;
|
||||
struct winlink *wl = change->wl;
|
||||
struct window_pane *wp = change->wp;
|
||||
struct window *w;
|
||||
|
||||
if (wp != NULL) {
|
||||
w = wp->window;
|
||||
control_write(c, "%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
change->name, s->id, w->id, wl->idx, wp->id, change->value);
|
||||
} else if (wl != NULL) {
|
||||
w = wl->window;
|
||||
control_write(c, "%%subscription-changed %s $%u @%u %u - : %s",
|
||||
change->name, s->id, w->id, wl->idx, change->value);
|
||||
} else {
|
||||
control_write(c, "%%subscription-changed %s $%u - - - : %s",
|
||||
change->name, s->id, change->value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize for control mode. */
|
||||
void
|
||||
control_start(struct client *c)
|
||||
@@ -789,7 +757,7 @@ control_start(struct client *c)
|
||||
RB_INIT(&cs->panes);
|
||||
TAILQ_INIT(&cs->pending_list);
|
||||
TAILQ_INIT(&cs->all_blocks);
|
||||
RB_INIT(&cs->subs);
|
||||
cs->subs = monitor_create_client(c, control_sub_change, NULL);
|
||||
|
||||
cs->read_event = bufferevent_new(c->fd, control_read_callback,
|
||||
control_write_callback, control_error_callback, c);
|
||||
@@ -838,20 +806,16 @@ control_stop(struct client *c)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb, *cb1;
|
||||
struct control_sub *csub, *csub1;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
|
||||
monitor_destroy(cs->subs);
|
||||
|
||||
if (~c->flags & CLIENT_CONTROLCONTROL)
|
||||
bufferevent_free(cs->write_event);
|
||||
bufferevent_free(cs->read_event);
|
||||
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1)
|
||||
control_free_sub(cs, csub);
|
||||
if (evtimer_initialized(&cs->subs_timer))
|
||||
evtimer_del(&cs->subs_timer);
|
||||
|
||||
control_reset_offsets(c);
|
||||
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
||||
control_free_block(cs, cb);
|
||||
@@ -860,313 +824,14 @@ control_stop(struct client *c)
|
||||
free(cs);
|
||||
}
|
||||
|
||||
/* Check session subscription. */
|
||||
static void
|
||||
control_check_subs_session(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
char *value;
|
||||
|
||||
value = format_expand(ft, csub->format);
|
||||
|
||||
if (csub->last != NULL && strcmp(value, csub->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u - - - : %s",
|
||||
csub->name, s->id, value);
|
||||
free(csub->last);
|
||||
csub->last = value;
|
||||
}
|
||||
|
||||
/* Check pane subscription. */
|
||||
static void
|
||||
control_check_subs_pane(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_pane *csp, find;
|
||||
|
||||
wp = window_pane_find_by_id(csub->id);
|
||||
if (wp == NULL || wp->fd == -1)
|
||||
return;
|
||||
w = wp->window;
|
||||
|
||||
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL && strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-panes subscription for a pane. */
|
||||
static void
|
||||
control_check_subs_all_panes_one(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft, struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w = wl->window;
|
||||
char *value;
|
||||
struct control_sub_pane *csp, find;
|
||||
|
||||
value = format_expand(ft, csub->format);
|
||||
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL && strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
|
||||
/* Check window subscription. */
|
||||
static void
|
||||
control_check_subs_window(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_window *csw, find;
|
||||
|
||||
w = window_find_by_id(csub->id);
|
||||
if (w == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-windows subscription for a window. */
|
||||
static void
|
||||
control_check_subs_all_windows_one(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft, struct winlink *wl)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w = wl->window;
|
||||
char *value;
|
||||
struct control_sub_window *csw, find;
|
||||
|
||||
value = format_expand(ft, csub->format);
|
||||
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
}
|
||||
|
||||
/* Check subscriptions timer. */
|
||||
static void
|
||||
control_check_subs_timer(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, *csub1;
|
||||
struct session *s = c->session;
|
||||
struct format_tree *ft;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
int have_session = 0, have_all_panes = 0;
|
||||
int have_all_windows = 0;
|
||||
|
||||
log_debug("%s: timer fired", __func__);
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
/* Find which subscription types are present. */
|
||||
RB_FOREACH(csub, control_subs, &cs->subs) {
|
||||
switch (csub->type) {
|
||||
case CONTROL_SUB_SESSION:
|
||||
have_session = 1;
|
||||
break;
|
||||
case CONTROL_SUB_ALL_PANES:
|
||||
have_all_panes = 1;
|
||||
break;
|
||||
case CONTROL_SUB_ALL_WINDOWS:
|
||||
have_all_windows = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check session subscriptions. */
|
||||
if (have_session) {
|
||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
if (csub->type == CONTROL_SUB_SESSION)
|
||||
control_check_subs_session(c, csub, ft);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
/* Check pane and window subscriptions. */
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
switch (csub->type) {
|
||||
case CONTROL_SUB_PANE:
|
||||
control_check_subs_pane(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_WINDOW:
|
||||
control_check_subs_window(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_SESSION:
|
||||
case CONTROL_SUB_ALL_PANES:
|
||||
case CONTROL_SUB_ALL_WINDOWS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-panes subscriptions. */
|
||||
if (have_all_panes) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||
csub1) {
|
||||
if (csub->type != CONTROL_SUB_ALL_PANES)
|
||||
continue;
|
||||
control_check_subs_all_panes_one(c,
|
||||
csub, ft, wl, wp);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-windows subscriptions. */
|
||||
if (have_all_windows) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||
csub1) {
|
||||
if (csub->type != CONTROL_SUB_ALL_WINDOWS)
|
||||
continue;
|
||||
control_check_subs_all_windows_one(c, csub, ft,
|
||||
wl);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a subscription. */
|
||||
void
|
||||
control_add_sub(struct client *c, const char *name, enum control_sub_type type,
|
||||
control_add_sub(struct client *c, const char *name, enum monitor_type type,
|
||||
int id, const char *format)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, find;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
|
||||
find.name = (char *)name;
|
||||
if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
|
||||
control_free_sub(cs, csub);
|
||||
|
||||
csub = xcalloc(1, sizeof *csub);
|
||||
csub->name = xstrdup(name);
|
||||
csub->type = type;
|
||||
csub->id = id;
|
||||
csub->format = xstrdup(format);
|
||||
RB_INSERT(control_subs, &cs->subs, csub);
|
||||
|
||||
RB_INIT(&csub->panes);
|
||||
RB_INIT(&csub->windows);
|
||||
|
||||
if (!evtimer_initialized(&cs->subs_timer))
|
||||
evtimer_set(&cs->subs_timer, control_check_subs_timer, c);
|
||||
if (!evtimer_pending(&cs->subs_timer, NULL))
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
monitor_add(cs->subs, name, type, id, format, MONITOR_NOTIFY_INITIAL);
|
||||
}
|
||||
|
||||
/* Remove a subscription. */
|
||||
@@ -1174,11 +839,6 @@ void
|
||||
control_remove_sub(struct client *c, const char *name)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, find;
|
||||
|
||||
find.name = (char *)name;
|
||||
if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
|
||||
control_free_sub(cs, csub);
|
||||
if (RB_EMPTY(&cs->subs))
|
||||
evtimer_del(&cs->subs_timer);
|
||||
monitor_remove(cs->subs, name);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: environ.c,v 1.31 2026/06/13 20:07:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
672
events-payload.c
Normal file
672
events-payload.c
Normal file
@@ -0,0 +1,672 @@
|
||||
/* $OpenBSD: events-payload.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* 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 <event.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Event payload item. */
|
||||
struct event_payload_item {
|
||||
char *name;
|
||||
enum event_payload_type type;
|
||||
|
||||
union {
|
||||
char *string;
|
||||
time_t time;
|
||||
int number;
|
||||
u_int unsigned_number;
|
||||
struct client *client;
|
||||
struct session *session;
|
||||
struct window *window;
|
||||
struct window_pane *pane;
|
||||
struct {
|
||||
void *ptr;
|
||||
event_payload_free_cb free_cb;
|
||||
event_payload_print_cb print_cb;
|
||||
} pointer;
|
||||
};
|
||||
|
||||
RB_ENTRY(event_payload_item) entry;
|
||||
};
|
||||
|
||||
RB_HEAD(event_payload_tree, event_payload_item);
|
||||
|
||||
struct event_payload {
|
||||
struct event_payload_tree items;
|
||||
struct cmd_find_state target;
|
||||
};
|
||||
|
||||
static int
|
||||
event_payload_cmp(struct event_payload_item *epi1,
|
||||
struct event_payload_item *epi2)
|
||||
{
|
||||
return (strcmp(epi1->name, epi2->name));
|
||||
}
|
||||
RB_GENERATE_STATIC(event_payload_tree, event_payload_item, entry,
|
||||
event_payload_cmp);
|
||||
|
||||
/* Find an item. */
|
||||
static struct event_payload_item *
|
||||
event_payload_find(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item find = { .name = (char *)name };
|
||||
|
||||
return (RB_FIND(event_payload_tree, &ep->items, &find));
|
||||
}
|
||||
|
||||
/* Free the target in a payload. */
|
||||
static void
|
||||
event_payload_free_target(struct event_payload *ep)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
if (target->s != NULL)
|
||||
session_remove_ref(target->s, __func__);
|
||||
if (target->w != NULL)
|
||||
window_remove_ref(target->w, __func__);
|
||||
if (target->wp != NULL)
|
||||
window_pane_remove_ref(target->wp, __func__);
|
||||
|
||||
cmd_find_clear_state(target, 0);
|
||||
}
|
||||
|
||||
/* Free the value in an item. */
|
||||
static void
|
||||
event_payload_free_value(struct event_payload_item *epi)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
free(epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
server_client_unref(epi->client);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
session_remove_ref(epi->session, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
window_remove_ref(epi->window, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
window_pane_remove_ref(epi->pane, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.free_cb != NULL)
|
||||
epi->pointer.free_cb(epi->pointer.ptr);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set an item. */
|
||||
static void
|
||||
event_payload_set_item(struct event_payload *ep, const char *name,
|
||||
struct event_payload_item *new)
|
||||
{
|
||||
struct event_payload_item *old;
|
||||
|
||||
new->name = xstrdup(name);
|
||||
old = RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
if (old != NULL) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, old);
|
||||
event_payload_free_value(old);
|
||||
free(old->name);
|
||||
free(old);
|
||||
RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an event payload. */
|
||||
struct event_payload *
|
||||
event_payload_create(void)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
|
||||
ep = xcalloc(1, sizeof *ep);
|
||||
RB_INIT(&ep->items);
|
||||
cmd_find_clear_state(&ep->target, 0);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
/* Free an event payload. */
|
||||
void
|
||||
event_payload_free(struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi, *epi1;
|
||||
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH_SAFE(epi, event_payload_tree, &ep->items, epi1) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, epi);
|
||||
event_payload_free_value(epi);
|
||||
free(epi->name);
|
||||
free(epi);
|
||||
}
|
||||
event_payload_free_target(ep);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the target. */
|
||||
void
|
||||
event_payload_set_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
event_payload_free_target(ep);
|
||||
|
||||
if (fs->s != NULL) {
|
||||
session_add_ref(fs->s, __func__);
|
||||
target->s = fs->s;
|
||||
}
|
||||
if (fs->wl != NULL) {
|
||||
target->idx = fs->wl->idx;
|
||||
if (target->s == NULL) {
|
||||
session_add_ref(fs->wl->session, __func__);
|
||||
target->s = fs->wl->session;
|
||||
}
|
||||
} else
|
||||
target->idx = -1;
|
||||
if (fs->w != NULL) {
|
||||
window_add_ref(fs->w, __func__);
|
||||
target->w = fs->w;
|
||||
} else if (fs->wl != NULL) {
|
||||
window_add_ref(fs->wl->window, __func__);
|
||||
target->w = fs->wl->window;
|
||||
}
|
||||
if (fs->wp != NULL) {
|
||||
window_pane_add_ref(fs->wp, __func__);
|
||||
target->wp = fs->wp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the target. */
|
||||
int
|
||||
event_payload_get_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *t = &ep->target;
|
||||
struct winlink *wl = NULL;
|
||||
int flags = fs->flags;
|
||||
|
||||
if (t->idx != -1 &&
|
||||
t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s)) {
|
||||
wl = winlink_find_by_index(&t->s->windows, t->idx);
|
||||
if (wl != NULL && wl->window != t->w)
|
||||
wl = NULL;
|
||||
}
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
fs->s = t->s;
|
||||
fs->w = t->w;
|
||||
fs->wp = t->wp;
|
||||
fs->wl = wl;
|
||||
fs->idx = (wl != NULL ? wl->idx : -1);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL &&
|
||||
t->wp != NULL &&
|
||||
window_has_pane(wl->window, t->wp)) {
|
||||
cmd_find_from_winlink_pane(fs, wl, t->wp, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->wp != NULL &&
|
||||
cmd_find_from_pane(fs, t->wp, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL) {
|
||||
cmd_find_from_winlink(fs, wl, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s) &&
|
||||
cmd_find_from_session_window(fs, t->s, t->w, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (t->s != NULL && session_alive(t->s)) {
|
||||
cmd_find_from_session(fs, t->s, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cmd_find_from_nothing(fs, flags) == 0)
|
||||
return (1);
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Set a string item. */
|
||||
void
|
||||
event_payload_set_string(struct event_payload *ep, const char *name,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_STRING;
|
||||
xvasprintf(&epi->string, fmt, ap);
|
||||
event_payload_set_item(ep, name, epi);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Set a time item. */
|
||||
void
|
||||
event_payload_set_time(struct event_payload *ep, const char *name,
|
||||
time_t value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_TIME;
|
||||
epi->time = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a number item. */
|
||||
void
|
||||
event_payload_set_int(struct event_payload *ep, const char *name, int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_INT;
|
||||
epi->number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set an unsigned number item. */
|
||||
void
|
||||
event_payload_set_uint(struct event_payload *ep, const char *name, u_int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_UINT;
|
||||
epi->unsigned_number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a client item. */
|
||||
void
|
||||
event_payload_set_client(struct event_payload *ep, const char *name,
|
||||
struct client *c)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
c->references++;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_CLIENT;
|
||||
epi->client = c;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a session item. */
|
||||
void
|
||||
event_payload_set_session(struct event_payload *ep, const char *name,
|
||||
struct session *s)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
session_add_ref(s, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_SESSION;
|
||||
epi->session = s;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a window item. */
|
||||
void
|
||||
event_payload_set_window(struct event_payload *ep, const char *name,
|
||||
struct window *w)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_add_ref(w, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_WINDOW;
|
||||
epi->window = w;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pane item. */
|
||||
void
|
||||
event_payload_set_pane(struct event_payload *ep, const char *name,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_pane_add_ref(wp, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_PANE;
|
||||
epi->pane = wp;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pointer item. */
|
||||
void
|
||||
event_payload_set_pointer(struct event_payload *ep, const char *name,
|
||||
void *ptr, event_payload_free_cb free_cb, event_payload_print_cb print_cb)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_POINTER;
|
||||
epi->pointer.ptr = ptr;
|
||||
epi->pointer.free_cb = free_cb;
|
||||
epi->pointer.print_cb = print_cb;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Get a string item. */
|
||||
const char *
|
||||
event_payload_get_string(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_STRING)
|
||||
return (NULL);
|
||||
return (epi->string);
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
static void
|
||||
event_payload_add_item(struct event_payload_item *epi, struct evbuffer *evb)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
evbuffer_add_printf(evb, "%s", epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
evbuffer_add_printf(evb, "%lld", (long long)epi->time);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
evbuffer_add_printf(evb, "%d", epi->number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
evbuffer_add_printf(evb, "%u", epi->unsigned_number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
evbuffer_add_printf(evb, "%s", epi->client->name);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
evbuffer_add_printf(evb, "$%u", epi->session->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
evbuffer_add_printf(evb, "@%u", epi->window->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
evbuffer_add_printf(evb, "%%%u", epi->pane->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.print_cb != NULL)
|
||||
epi->pointer.print_cb(epi->pointer.ptr, evb);
|
||||
else
|
||||
evbuffer_add_printf(evb, "%p", epi->pointer.ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
char *
|
||||
event_payload_item_print(struct event_payload_item *epi)
|
||||
{
|
||||
struct evbuffer *evb;
|
||||
char *value = NULL;
|
||||
size_t size;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
event_payload_add_item(epi, evb);
|
||||
if ((size = EVBUFFER_LENGTH(evb)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(evb), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(evb);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Print an item value. */
|
||||
char *
|
||||
event_payload_print(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL)
|
||||
return (NULL);
|
||||
return (event_payload_item_print(epi));
|
||||
}
|
||||
|
||||
/* Add payload items as formats. */
|
||||
void
|
||||
event_payload_add_formats(struct event_payload *ep, struct format_tree *ft,
|
||||
const char *prefix)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
char *name, *value;
|
||||
const char *key;
|
||||
|
||||
if (prefix == NULL)
|
||||
prefix = "";
|
||||
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
key = epi->name;
|
||||
if (*key == '_')
|
||||
continue;
|
||||
|
||||
value = event_payload_item_print(epi);
|
||||
xasprintf(&name, "%s%s", prefix, key);
|
||||
format_add(ft, name, "%s", value);
|
||||
free(name);
|
||||
free(value);
|
||||
|
||||
if (epi->type == EVENT_PAYLOAD_SESSION) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->session->name);
|
||||
free(name);
|
||||
} else if (epi->type == EVENT_PAYLOAD_WINDOW) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->window->name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_first(struct event_payload *ep)
|
||||
{
|
||||
return (RB_MIN(event_payload_tree, &ep->items));
|
||||
}
|
||||
|
||||
/* Get the next payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_next(struct event_payload_item *epi)
|
||||
{
|
||||
return (RB_NEXT(event_payload_tree, , epi));
|
||||
}
|
||||
|
||||
/* Get a payload item name. */
|
||||
const char *
|
||||
event_payload_item_name(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->name);
|
||||
}
|
||||
|
||||
/* Get a payload item type. */
|
||||
enum event_payload_type
|
||||
event_payload_item_type(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->type);
|
||||
}
|
||||
|
||||
/* Log a payload. */
|
||||
void
|
||||
event_payload_log(struct event_payload *ep, const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
struct evbuffer *evb;
|
||||
va_list ap;
|
||||
char *prefix;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&prefix, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
if (EVBUFFER_LENGTH(evb) != 0)
|
||||
evbuffer_add_printf(evb, ", ");
|
||||
evbuffer_add_printf(evb, "%s=", epi->name);
|
||||
event_payload_add_item(epi, evb);
|
||||
}
|
||||
}
|
||||
log_debug("%s%.*s", prefix, (int)EVBUFFER_LENGTH(evb),
|
||||
(char *)EVBUFFER_DATA(evb));
|
||||
evbuffer_free(evb);
|
||||
free(prefix);
|
||||
}
|
||||
|
||||
/* Get a time item. */
|
||||
time_t
|
||||
event_payload_get_time(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_TIME)
|
||||
return (0);
|
||||
return (epi->time);
|
||||
}
|
||||
|
||||
/* Get a number item. */
|
||||
int
|
||||
event_payload_get_int(struct event_payload *ep, const char *name, int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_INT)
|
||||
return (-1);
|
||||
*value = epi->number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get an unsigned number item. */
|
||||
int
|
||||
event_payload_get_uint(struct event_payload *ep, const char *name, u_int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_UINT)
|
||||
return (-1);
|
||||
*value = epi->unsigned_number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get a client item. */
|
||||
struct client *
|
||||
event_payload_get_client(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_CLIENT)
|
||||
return (NULL);
|
||||
return (epi->client);
|
||||
}
|
||||
|
||||
/* Get a session item. */
|
||||
struct session *
|
||||
event_payload_get_session(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_SESSION)
|
||||
return (NULL);
|
||||
return (epi->session);
|
||||
}
|
||||
|
||||
/* Get a window item. */
|
||||
struct window *
|
||||
event_payload_get_window(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_WINDOW)
|
||||
return (NULL);
|
||||
return (epi->window);
|
||||
}
|
||||
|
||||
/* Get a pane item. */
|
||||
struct window_pane *
|
||||
event_payload_get_pane(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_PANE)
|
||||
return (NULL);
|
||||
return (epi->pane);
|
||||
}
|
||||
|
||||
/* Get a pointer item. */
|
||||
void *
|
||||
event_payload_get_pointer(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_POINTER)
|
||||
return (NULL);
|
||||
return (epi->pointer.ptr);
|
||||
}
|
||||
199
events.c
Normal file
199
events.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/* $OpenBSD: events.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Event sink. */
|
||||
struct events_sink {
|
||||
char *name;
|
||||
events_cb cb;
|
||||
void *data;
|
||||
int dead;
|
||||
u_int generation;
|
||||
|
||||
TAILQ_ENTRY(events_sink) entry;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(events_sinks, events_sink);
|
||||
static struct events_sinks events_sinks = TAILQ_HEAD_INITIALIZER(events_sinks);
|
||||
|
||||
static u_int events_dispatching;
|
||||
static u_int events_generation;
|
||||
|
||||
/* Free an event sink. */
|
||||
static void
|
||||
events_free_sink(struct events_sink *es)
|
||||
{
|
||||
TAILQ_REMOVE(&events_sinks, es, entry);
|
||||
free(es->name);
|
||||
free(es);
|
||||
}
|
||||
|
||||
/* Free dead event sinks. */
|
||||
static void
|
||||
events_free_dead(void)
|
||||
{
|
||||
struct events_sink *es, *es1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(es, &events_sinks, entry, es1) {
|
||||
if (es->dead)
|
||||
events_free_sink(es);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an event sink. */
|
||||
struct events_sink *
|
||||
events_add_sink(const char *name, events_cb cb, void *data)
|
||||
{
|
||||
struct events_sink *es;
|
||||
|
||||
es = xcalloc(1, sizeof *es);
|
||||
es->name = xstrdup(name);
|
||||
es->cb = cb;
|
||||
es->data = data;
|
||||
es->generation = ++events_generation;
|
||||
|
||||
TAILQ_INSERT_TAIL(&events_sinks, es, entry);
|
||||
return (es);
|
||||
}
|
||||
|
||||
/* Remove an event sink. */
|
||||
void
|
||||
events_remove_sink(struct events_sink *es)
|
||||
{
|
||||
if (es != NULL && !es->dead) {
|
||||
if (events_dispatching != 0)
|
||||
es->dead = 1;
|
||||
else
|
||||
events_free_sink(es);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fire an event. */
|
||||
void
|
||||
events_fire(const char *name, struct event_payload *ep)
|
||||
{
|
||||
struct events_sink *es;
|
||||
u_int generation = events_generation;
|
||||
|
||||
event_payload_set_string(ep, "event", "%s", name);
|
||||
|
||||
if (log_get_level() != 0)
|
||||
event_payload_log(ep, "%s: %s: ", __func__, name);
|
||||
|
||||
events_dispatching++;
|
||||
TAILQ_FOREACH(es, &events_sinks, entry) {
|
||||
if (es->dead || es->generation > generation)
|
||||
continue;
|
||||
if (strcmp(es->name, name) == 0)
|
||||
es->cb(name, ep, es->data);
|
||||
}
|
||||
if (--events_dispatching == 0)
|
||||
events_free_dead();
|
||||
event_payload_free(ep);
|
||||
}
|
||||
|
||||
/* Fire a client event. */
|
||||
void
|
||||
events_fire_client(const char *name, struct client *c)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_client(&fs, c, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_client(ep, "client", c);
|
||||
if (fs.s != NULL)
|
||||
event_payload_set_session(ep, "session", fs.s);
|
||||
if (fs.w != NULL)
|
||||
event_payload_set_window(ep, "window", fs.w);
|
||||
if (fs.wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", fs.wl->idx);
|
||||
else if (fs.idx != -1)
|
||||
event_payload_set_int(ep, "window_index", fs.idx);
|
||||
if (fs.wp != NULL)
|
||||
event_payload_set_pane(ep, "pane", fs.wp);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a session event. */
|
||||
void
|
||||
events_fire_session(const char *name, struct session *s)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
if (session_alive(s)) {
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
}
|
||||
event_payload_set_session(ep, "session", s);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a window event. */
|
||||
void
|
||||
events_fire_window(const char *name, struct window *w)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_window(&fs, w, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_window(ep, "window", w);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a pane event. */
|
||||
void
|
||||
events_fire_pane(const char *name, struct window_pane *wp)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a winlink event. */
|
||||
void
|
||||
events_fire_winlink(const char *name, struct winlink *wl)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_session(ep, "session", wl->session);
|
||||
event_payload_set_window(ep, "window", wl->window);
|
||||
event_payload_set_int(ep, "window_index", wl->idx);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
2
file.c
2
file.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: file.c,v 1.20 2026/05/17 10:54:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: format-draw.c,v 1.33 2026/06/29 17:08:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
634
format.c
634
format.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: format.c,v 1.403 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -42,6 +42,7 @@
|
||||
struct format_expand_state;
|
||||
|
||||
static char *format_job_get(struct format_expand_state *, const char *);
|
||||
static char *format_quote_shell_single(const char *);
|
||||
static char *format_expand1(struct format_expand_state *, const char *);
|
||||
static int format_replace(struct format_expand_state *, const char *,
|
||||
size_t, char **, size_t *, size_t *);
|
||||
@@ -123,6 +124,10 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
#define FORMAT_CLIENT_ENVIRON 0x4000000
|
||||
#define FORMAT_COLOUR_ESC_FG 0x8000000
|
||||
#define FORMAT_COLOUR_ESC_BG 0x10000000
|
||||
#define FORMAT_QUOTE_SHELL_SQ 0x20000000
|
||||
#define FORMAT_OPTIONS 0x40000000
|
||||
#define FORMAT_ENVIRON 0x80000000ULL
|
||||
#define FORMAT_DIFFERENCE 0x100000000ULL
|
||||
|
||||
/* Limit on recursion. */
|
||||
#define FORMAT_LOOP_LIMIT 100
|
||||
@@ -878,6 +883,37 @@ format_cb_start_command(struct format_tree *ft)
|
||||
return (cmd_stringify_argv(wp->argc, wp->argv));
|
||||
}
|
||||
|
||||
/* Callback for pane_start_command_list. */
|
||||
static void *
|
||||
format_cb_start_command_list(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
char *buf = NULL, *s;
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
if (wp->argc == 0)
|
||||
return (xstrdup(""));
|
||||
|
||||
for (i = 0; i < wp->argc; i++) {
|
||||
s = format_quote_shell_single(wp->argv[i]);
|
||||
|
||||
len += strlen(s) + 1;
|
||||
buf = xrealloc(buf, len);
|
||||
|
||||
if (i == 0)
|
||||
*buf = '\0';
|
||||
else
|
||||
strlcat(buf, " ", len);
|
||||
strlcat(buf, s, len);
|
||||
|
||||
free(s);
|
||||
}
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Callback for pane_start_path. */
|
||||
static void *
|
||||
format_cb_start_path(struct format_tree *ft)
|
||||
@@ -2151,6 +2187,106 @@ format_cb_pane_dead_time(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_output_time. */
|
||||
static void *
|
||||
format_cb_pane_last_output_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->last_output_time != 0) {
|
||||
tv.tv_sec = wp->last_output_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_prompt_time. */
|
||||
static void *
|
||||
format_cb_pane_last_prompt_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->last_prompt_time != 0) {
|
||||
tv.tv_sec = wp->last_prompt_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_start_time. */
|
||||
static void *
|
||||
format_cb_pane_command_start_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->cmd_start_time != 0) {
|
||||
tv.tv_sec = wp->cmd_start_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_end_time. */
|
||||
static void *
|
||||
format_cb_pane_command_end_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->cmd_end_time != 0) {
|
||||
tv.tv_sec = wp->cmd_end_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_running. */
|
||||
static void *
|
||||
format_cb_pane_command_running(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%d", !!(wp->flags & PANE_CMDRUNNING)));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_duration. */
|
||||
static void *
|
||||
format_cb_pane_command_duration(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
time_t end;
|
||||
|
||||
if (wp == NULL || wp->cmd_start_time == 0)
|
||||
return (NULL);
|
||||
if (wp->flags & PANE_CMDRUNNING)
|
||||
end = time(NULL);
|
||||
else
|
||||
end = wp->cmd_end_time;
|
||||
if (end < wp->cmd_start_time)
|
||||
end = wp->cmd_start_time;
|
||||
return (format_printf("%lld", (long long)(end - wp->cmd_start_time)));
|
||||
}
|
||||
|
||||
/* Callback for pane_command_status. */
|
||||
static void *
|
||||
format_cb_pane_command_status(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL && wp->cmd_status != -1)
|
||||
return (format_printf("%d", wp->cmd_status));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_format. */
|
||||
static void *
|
||||
format_cb_pane_format(struct format_tree *ft)
|
||||
@@ -2306,7 +2442,7 @@ format_cb_pane_path(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_pane_pid(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL)
|
||||
if (ft->wp != NULL && ft->wp->fd != -1)
|
||||
return (format_printf("%ld", (long)ft->wp->pid));
|
||||
return (NULL);
|
||||
}
|
||||
@@ -2861,6 +2997,19 @@ format_cb_window_height(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for window_manual_height. */
|
||||
static void *
|
||||
format_cb_window_manual_height(struct format_tree *ft)
|
||||
{
|
||||
struct window *w = ft->w;
|
||||
|
||||
if (w == NULL)
|
||||
return (NULL);
|
||||
if (options_get_number(w->options, "window-size") != WINDOW_SIZE_MANUAL)
|
||||
return (xstrdup(""));
|
||||
return (format_printf("%u", w->manual_sy));
|
||||
}
|
||||
|
||||
/* Callback for window_id. */
|
||||
static void *
|
||||
format_cb_window_id(struct format_tree *ft)
|
||||
@@ -3041,6 +3190,19 @@ format_cb_window_width(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for window_manual_width. */
|
||||
static void *
|
||||
format_cb_window_manual_width(struct format_tree *ft)
|
||||
{
|
||||
struct window *w = ft->w;
|
||||
|
||||
if (w == NULL)
|
||||
return (NULL);
|
||||
if (options_get_number(w->options, "window-size") != WINDOW_SIZE_MANUAL)
|
||||
return (xstrdup(""));
|
||||
return (format_printf("%u", w->manual_sx));
|
||||
}
|
||||
|
||||
/* Callback for window_zoomed_flag. */
|
||||
static void *
|
||||
format_cb_window_zoomed_flag(struct format_tree *ft)
|
||||
@@ -3441,6 +3603,21 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_bottom", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_bottom
|
||||
},
|
||||
{ "pane_command_duration", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_duration
|
||||
},
|
||||
{ "pane_command_end_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_command_end_time
|
||||
},
|
||||
{ "pane_command_running", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_running
|
||||
},
|
||||
{ "pane_command_start_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_command_start_time
|
||||
},
|
||||
{ "pane_command_status", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_status
|
||||
},
|
||||
{ "pane_current_command", FORMAT_TABLE_STRING,
|
||||
format_cb_current_command
|
||||
},
|
||||
@@ -3492,6 +3669,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_last", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_last
|
||||
},
|
||||
{ "pane_last_output_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_last_output_time
|
||||
},
|
||||
{ "pane_last_prompt_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_last_prompt_time
|
||||
},
|
||||
{ "pane_left", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_left
|
||||
},
|
||||
@@ -3531,6 +3714,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_start_command", FORMAT_TABLE_STRING,
|
||||
format_cb_start_command
|
||||
},
|
||||
{ "pane_start_command_list", FORMAT_TABLE_STRING,
|
||||
format_cb_start_command_list
|
||||
},
|
||||
{ "pane_start_path", FORMAT_TABLE_STRING,
|
||||
format_cb_start_path
|
||||
},
|
||||
@@ -3747,6 +3933,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "window_linked_sessions_list", FORMAT_TABLE_STRING,
|
||||
format_cb_window_linked_sessions_list
|
||||
},
|
||||
{ "window_manual_height", FORMAT_TABLE_STRING,
|
||||
format_cb_window_manual_height
|
||||
},
|
||||
{ "window_manual_width", FORMAT_TABLE_STRING,
|
||||
format_cb_window_manual_width
|
||||
},
|
||||
{ "window_marked_flag", FORMAT_TABLE_STRING,
|
||||
format_cb_window_marked_flag
|
||||
},
|
||||
@@ -4027,6 +4219,29 @@ format_quote_shell(const char *s)
|
||||
return (out);
|
||||
}
|
||||
|
||||
/* Quote string with POSIX shell single quotes. */
|
||||
static char *
|
||||
format_quote_shell_single(const char *s)
|
||||
{
|
||||
const char *cp;
|
||||
char *out, *at;
|
||||
|
||||
at = out = xmalloc(strlen(s) * 4 + 3);
|
||||
*at++ = '\'';
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (*cp == '\'') {
|
||||
*at++ = '\'';
|
||||
*at++ = '\\';
|
||||
*at++ = '\'';
|
||||
*at++ = '\'';
|
||||
} else
|
||||
*at++ = *cp;
|
||||
}
|
||||
*at++ = '\'';
|
||||
*at = '\0';
|
||||
return (out);
|
||||
}
|
||||
|
||||
/* Quote #s in string. */
|
||||
static char *
|
||||
format_quote_style(const char *s)
|
||||
@@ -4128,9 +4343,20 @@ format_relative_time(time_t t)
|
||||
return (xstrdup(out));
|
||||
}
|
||||
|
||||
/* Make a time difference in seconds. */
|
||||
static char *
|
||||
format_time_difference(time_t t)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
char *out;
|
||||
|
||||
xasprintf(&out, "%ld", (long)now - (long)t);
|
||||
return (out);
|
||||
}
|
||||
|
||||
/* Find a format entry. */
|
||||
static char *
|
||||
format_find(struct format_tree *ft, const char *key, int modifiers,
|
||||
format_find(struct format_tree *ft, const char *key, uint64_t modifiers,
|
||||
const char *time_format)
|
||||
{
|
||||
const struct format_table_entry *fte;
|
||||
@@ -4138,25 +4364,26 @@ format_find(struct format_tree *ft, const char *key, int modifiers,
|
||||
struct format_entry *fe, fe_find;
|
||||
struct environ_entry *envent;
|
||||
struct options_entry *o;
|
||||
int idx;
|
||||
char *found = NULL, *saved, s[512];
|
||||
char *array_key = NULL;
|
||||
const char *errstr;
|
||||
time_t t = 0;
|
||||
struct tm tm;
|
||||
|
||||
o = options_parse_get(global_options, key, &idx, 0);
|
||||
o = options_parse_get(global_options, key, &array_key, 0);
|
||||
if (o == NULL && ft->wp != NULL)
|
||||
o = options_parse_get(ft->wp->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->wp->options, key, &array_key, 0);
|
||||
if (o == NULL && ft->w != NULL)
|
||||
o = options_parse_get(ft->w->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->w->options, key, &array_key, 0);
|
||||
if (o == NULL)
|
||||
o = options_parse_get(global_w_options, key, &idx, 0);
|
||||
o = options_parse_get(global_w_options, key, &array_key, 0);
|
||||
if (o == NULL && ft->s != NULL)
|
||||
o = options_parse_get(ft->s->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->s->options, key, &array_key, 0);
|
||||
if (o == NULL)
|
||||
o = options_parse_get(global_s_options, key, &idx, 0);
|
||||
o = options_parse_get(global_s_options, key, &array_key, 0);
|
||||
if (o != NULL) {
|
||||
found = options_to_string(o, idx, 1);
|
||||
found = options_to_string(o, array_key, 1);
|
||||
free(array_key);
|
||||
goto found;
|
||||
}
|
||||
|
||||
@@ -4211,6 +4438,8 @@ found:
|
||||
return (NULL);
|
||||
if (modifiers & FORMAT_RELATIVE)
|
||||
found = format_relative_time(t);
|
||||
else if (modifiers & FORMAT_DIFFERENCE)
|
||||
found = format_time_difference(t);
|
||||
else if (modifiers & FORMAT_PRETTY)
|
||||
found = format_pretty_time(t, 0);
|
||||
else {
|
||||
@@ -4245,6 +4474,11 @@ found:
|
||||
found = format_quote_shell(saved);
|
||||
free(saved);
|
||||
}
|
||||
if (modifiers & FORMAT_QUOTE_SHELL_SQ) {
|
||||
saved = found;
|
||||
found = format_quote_shell_single(saved);
|
||||
free(saved);
|
||||
}
|
||||
if (modifiers & FORMAT_QUOTE_STYLE) {
|
||||
saved = found;
|
||||
found = format_quote_style(saved);
|
||||
@@ -4455,7 +4689,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
|
||||
/*
|
||||
* Modifiers are a ; separated list of the forms:
|
||||
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,R,<,>
|
||||
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,O,V,R,<,>
|
||||
* =a
|
||||
* =/a
|
||||
* =/a/
|
||||
@@ -4474,7 +4708,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
break;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("labdnwETSWPL!<>", cp[0]) != NULL &&
|
||||
if (strchr("labdnwETSWPOVL!<>", cp[0]) != NULL &&
|
||||
format_is_end(cp[1])) {
|
||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||
cp++;
|
||||
@@ -4496,7 +4730,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
}
|
||||
|
||||
/* Now try single character with arguments. */
|
||||
if (strchr("ImCLNPSst=pReqWc", cp[0]) == NULL)
|
||||
if (strchr("ImCLNPSOVst=pReqWc", cp[0]) == NULL)
|
||||
break;
|
||||
c = cp[0];
|
||||
|
||||
@@ -4773,11 +5007,14 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, ft->c, s, NULL, NULL);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(next.ft);
|
||||
|
||||
@@ -4820,9 +5057,9 @@ format_window_name(struct format_expand_state *es, const char *fmt)
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
|
||||
/* Add neighbor window variables to the format tree. */
|
||||
/* Add neighbour window variables to the format tree. */
|
||||
static void
|
||||
format_add_window_neighbor(struct format_tree *nft, struct winlink *wl,
|
||||
format_add_window_neighbour(struct format_tree *nft, struct winlink *wl,
|
||||
struct session *s, const char *prefix)
|
||||
{
|
||||
struct options_entry *o;
|
||||
@@ -4842,7 +5079,7 @@ format_add_window_neighbor(struct format_tree *nft, struct winlink *wl,
|
||||
oname = options_name(o);
|
||||
if (*oname == '@') {
|
||||
xasprintf(&prefixed, "%s_%s", prefix, oname);
|
||||
oval = options_to_string(o, -1, 1);
|
||||
oval = options_to_string(o, NULL, 1);
|
||||
format_add(nft, prefixed, "%s", oval);
|
||||
free(oval);
|
||||
free(prefixed);
|
||||
@@ -4855,20 +5092,21 @@ format_add_window_neighbor(struct format_tree *nft, struct winlink *wl,
|
||||
static char *
|
||||
format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
{
|
||||
struct sort_criteria *sc = &sort_crit;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
struct winlink *wl, **l;
|
||||
struct window *w;
|
||||
int i, n;
|
||||
struct sort_criteria *sc = &sort_crit;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct client *c = ft->client;
|
||||
struct session *s = ft->s;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
struct winlink *wl, **l;
|
||||
struct window *w;
|
||||
int i, n;
|
||||
|
||||
if (ft->s == NULL) {
|
||||
if (s == NULL) {
|
||||
format_log(es, "window loop but no session");
|
||||
return (NULL);
|
||||
}
|
||||
@@ -4882,33 +5120,38 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
l = sort_get_winlinks_session(ft->s, &n, sc);
|
||||
l = sort_get_winlinks_session(s, &n, sc);
|
||||
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 == ft->s->curw)
|
||||
if (active != NULL && wl == s->curw)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id,
|
||||
ft->flags);
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
format_defaults(nft, ft->c, ft->s, wl, NULL);
|
||||
|
||||
/* Add neighbor window data to the format tree. */
|
||||
format_add(nft, "window_after_active", "%d",
|
||||
i > 0 && l[i - 1] == ft->s->curw);
|
||||
format_add(nft, "window_before_active", "%d",
|
||||
i + 1 < n && l[i + 1] == ft->s->curw);
|
||||
/* Add neighbour window data to the format tree. */
|
||||
if (i > 0 && l[i - 1] == s->curw)
|
||||
format_add(nft, "window_after_active", "1");
|
||||
else
|
||||
format_add(nft, "window_after_active", "0");
|
||||
if (i + 1 < n && l[i + 1] == s->curw)
|
||||
format_add(nft, "window_before_active", "1");
|
||||
else
|
||||
format_add(nft, "window_before_active", "0");
|
||||
if (i + 1 < n)
|
||||
format_add_window_neighbor(nft, l[i + 1], ft->s, "next");
|
||||
format_add_window_neighbour(nft, l[i + 1], s, "next");
|
||||
if (i > 0)
|
||||
format_add_window_neighbor(nft, l[i - 1], ft->s, "prev");
|
||||
format_add_window_neighbour(nft, l[i - 1], s, "prev");
|
||||
|
||||
format_defaults(nft, ft->c, s, wl, NULL);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
@@ -4965,13 +5208,15 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_PANE|wp->id,
|
||||
ft->flags);
|
||||
nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
@@ -4990,6 +5235,271 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Add an option to an options loop. */
|
||||
static void
|
||||
format_loop_add_option(struct format_expand_state *es, const char *fmt,
|
||||
struct evbuffer *buffer, struct options_entry *o, u_int n, u_int i)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct format_expand_state next;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
const char *name = options_name(o);
|
||||
char *expanded, *s;
|
||||
int is_array = options_is_array(o);
|
||||
|
||||
format_log(es, "option loop: %s", name);
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, NULL, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "%d", is_array);
|
||||
format_add(nft, "option_array_key", "%s", "");
|
||||
format_add(nft, "option_array_index", "%s", "");
|
||||
format_add(nft, "option_array_first", "%d", is_array);
|
||||
format_add(nft, "option_array_last", "%d", is_array);
|
||||
format_add(nft, "option_array_count", "%u", n);
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
|
||||
format_add(nft, "option_is_hook", "1");
|
||||
else
|
||||
format_add(nft, "option_is_hook", "0");
|
||||
format_add(nft, "option_is_user", "%d", oe == NULL);
|
||||
|
||||
if (options_next(o) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
/* Add an array option item to an options loop. */
|
||||
static void
|
||||
format_loop_add_array_item(struct format_expand_state *es, const char *fmt,
|
||||
struct evbuffer *buffer, struct options_entry *o,
|
||||
struct options_array_item *a, int n, u_int i)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct format_expand_state next;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
const char *name = options_name(o);
|
||||
const char *array_key;
|
||||
char *expanded, *s;
|
||||
|
||||
array_key = options_array_item_key(a);
|
||||
format_log(es, "option loop: %s[%s]", name, array_key);
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, array_key, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "1");
|
||||
format_add(nft, "option_array_key", "%s", array_key);
|
||||
format_add(nft, "option_array_index", "%s", array_key);
|
||||
if (a == options_array_first(o))
|
||||
format_add(nft, "option_array_first", "1");
|
||||
else
|
||||
format_add(nft, "option_array_first", "0");
|
||||
if (options_array_next(a) == NULL)
|
||||
format_add(nft, "option_array_last", "1");
|
||||
else
|
||||
format_add(nft, "option_array_last", "0");
|
||||
format_add(nft, "option_array_count", "%u", n);
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
|
||||
format_add(nft, "option_is_hook", "1");
|
||||
else
|
||||
format_add(nft, "option_is_hook", "0");
|
||||
format_add(nft, "option_is_user", "%d", oe == NULL);
|
||||
|
||||
if (options_array_next(a) == NULL && options_next(o) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
/* Loop over options. */
|
||||
static char *
|
||||
format_loop_options(struct format_expand_state *es, const char *fmt,
|
||||
const char *flags)
|
||||
{
|
||||
struct format_tree *ft = es->ft;
|
||||
struct options *oo = NULL;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
char *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
u_int i = 0, n;
|
||||
int global = 0;
|
||||
|
||||
if (flags == NULL || *flags == '\0')
|
||||
flags = "s";
|
||||
if (strchr(flags, 'v') != NULL)
|
||||
oo = global_options;
|
||||
else {
|
||||
if (strchr(flags, 'g') != NULL)
|
||||
global = 1;
|
||||
if (strchr(flags, 'w') != NULL) {
|
||||
if (global)
|
||||
oo = global_w_options;
|
||||
else if (ft->w != NULL)
|
||||
oo = ft->w->options;
|
||||
} else if (strchr(flags, 's') != NULL) {
|
||||
if (global)
|
||||
oo = global_s_options;
|
||||
else if (ft->s != NULL)
|
||||
oo = ft->s->options;
|
||||
} else if (strchr(flags, 'p') != NULL) {
|
||||
if (global)
|
||||
/* invalid */;
|
||||
else if (ft->wp != NULL)
|
||||
oo = ft->wp->options;
|
||||
} else if (global)
|
||||
oo = global_s_options;
|
||||
}
|
||||
if (oo == NULL)
|
||||
return (xstrdup(""));
|
||||
|
||||
buffer = evbuffer_new();
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
|
||||
n = 0;
|
||||
if (options_is_array(o)) {
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
n++;
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options_is_array(o) || n == 0) {
|
||||
format_loop_add_option(es, fmt, buffer, o, n, i);
|
||||
i++;
|
||||
o = options_next(o);
|
||||
continue;
|
||||
}
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
format_loop_add_array_item(es, fmt, buffer, o, a, n, i);
|
||||
i++;
|
||||
a = options_array_next(a);
|
||||
}
|
||||
o = options_next(o);
|
||||
}
|
||||
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(buffer);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Loop over an environment. */
|
||||
static char *
|
||||
format_loop_environ(struct format_expand_state *es, const char *fmt,
|
||||
const char *flags)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_expand_state next;
|
||||
struct environ *env = NULL;
|
||||
struct environ_entry *envent;
|
||||
char *expanded, *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
u_int i = 0;
|
||||
|
||||
if (flags == NULL || *flags == '\0' || strcmp(flags, "s") == 0) {
|
||||
if (ft->s != NULL)
|
||||
env = ft->s->environ;
|
||||
} else if (strcmp(flags, "g") == 0)
|
||||
env = global_environ;
|
||||
else if (strcmp(flags, "c") == 0) {
|
||||
if (ft->client != NULL)
|
||||
env = ft->client->environ;
|
||||
}
|
||||
if (env == NULL)
|
||||
return (xstrdup(""));
|
||||
|
||||
buffer = evbuffer_new();
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
envent = environ_first(env);
|
||||
while (envent != NULL) {
|
||||
format_log(es, "environment loop: %s", envent->name);
|
||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "environ_name", "%s", envent->name);
|
||||
if (envent->value == NULL)
|
||||
format_add(nft, "environ_value", "%s", "");
|
||||
else
|
||||
format_add(nft, "environ_value", "%s", envent->value);
|
||||
|
||||
if (envent->flags & ENVIRON_HIDDEN)
|
||||
format_add(nft, "environ_hidden", "1");
|
||||
else
|
||||
format_add(nft, "environ_hidden", "0");
|
||||
format_add(nft, "environ_removed", "%d", envent->value == NULL);
|
||||
|
||||
if (environ_next(envent) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
|
||||
i++;
|
||||
envent = environ_next(envent);
|
||||
}
|
||||
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(buffer);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Loop over clients. */
|
||||
static char *
|
||||
format_loop_clients(struct format_expand_state *es, const char *fmt)
|
||||
@@ -5014,14 +5524,16 @@ format_loop_clients(struct format_expand_state *es, const char *fmt)
|
||||
c = l[i];
|
||||
format_log(es, "client loop: %s", c->name);
|
||||
nft = format_create(c, item, 0, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
@@ -5191,12 +5703,14 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
char *copy0, *condition, *found, *new;
|
||||
char *value, *left, *right;
|
||||
size_t valuelen;
|
||||
int modifiers = 0, limit = 0, width = 0;
|
||||
uint64_t modifiers = 0;
|
||||
int limit = 0, width = 0;
|
||||
int j, c;
|
||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||
struct format_modifier *bool_op_n = NULL;
|
||||
u_int i, count, nsub = 0, nrep, check = 0;
|
||||
const char *loop_flags = "";
|
||||
struct format_expand_state next;
|
||||
struct environ_entry *envent;
|
||||
|
||||
@@ -5305,6 +5819,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
modifiers |= FORMAT_PRETTY;
|
||||
else if (strchr(fm->argv[0], 'r') != NULL)
|
||||
modifiers |= FORMAT_RELATIVE;
|
||||
else if (strchr(fm->argv[0], 'd') != NULL)
|
||||
modifiers |= FORMAT_DIFFERENCE;
|
||||
else if (fm->argc >= 2 &&
|
||||
strchr(fm->argv[0], 'f') != NULL) {
|
||||
free(time_format);
|
||||
@@ -5315,6 +5831,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
case 'q':
|
||||
if (fm->argc < 1)
|
||||
modifiers |= FORMAT_QUOTE_SHELL;
|
||||
else if (strchr(fm->argv[0], 's') != NULL)
|
||||
modifiers |= FORMAT_QUOTE_SHELL_SQ;
|
||||
else if (strchr(fm->argv[0], 'e') != NULL ||
|
||||
strchr(fm->argv[0], 'h') != NULL)
|
||||
modifiers |= FORMAT_QUOTE_STYLE;
|
||||
@@ -5381,11 +5899,27 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
sc->reversed = 0;
|
||||
break;
|
||||
}
|
||||
if (strchr(fm->argv[0], 'i') != NULL)
|
||||
sc->order = SORT_INDEX;
|
||||
else if (strchr(fm->argv[0], 'z') != NULL)
|
||||
sc->order = SORT_Z;
|
||||
else
|
||||
sc->order = SORT_CREATION;
|
||||
if (strchr(fm->argv[0], 'r') != NULL)
|
||||
sc->reversed = 1;
|
||||
else
|
||||
sc->reversed = 0;
|
||||
break;
|
||||
case 'O':
|
||||
modifiers |= FORMAT_OPTIONS;
|
||||
if (fm->argc == 1)
|
||||
loop_flags = fm->argv[0];
|
||||
break;
|
||||
case 'V':
|
||||
modifiers |= FORMAT_ENVIRON;
|
||||
if (fm->argc == 1)
|
||||
loop_flags = fm->argv[0];
|
||||
break;
|
||||
case 'L':
|
||||
modifiers |= FORMAT_CLIENTS;
|
||||
if (fm->argc < 1) {
|
||||
@@ -5521,6 +6055,14 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
value = format_loop_clients(es, copy);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_OPTIONS) {
|
||||
value = format_loop_options(es, copy, loop_flags);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_ENVIRON) {
|
||||
value = format_loop_environ(es, copy, loop_flags);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_WINDOW_NAME) {
|
||||
value = format_window_name(es, copy);
|
||||
if (value == NULL)
|
||||
|
||||
2
fuzzy.c
2
fuzzy.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: fuzzy.c,v 1.1 2026/06/26 14:40:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid-reader.c,v 1.10 2026/05/17 13:12:21 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid-view.c,v 1.38 2026/01/22 08:55:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
35
grid.c
35
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid.c,v 1.153 2026/07/02 08:51:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -60,21 +60,6 @@ static const struct grid_cell_entry grid_cleared_entry = {
|
||||
};
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void
|
||||
grid_check_lines(struct grid *gd)
|
||||
{
|
||||
u_int i, j;
|
||||
|
||||
for (i = 0; i < gd->hsize + gd->sy; i++) {
|
||||
for (j = i + 1; j < gd->hsize + gd->sy; j++) {
|
||||
if (gd->linedata[i].celldata != NULL)
|
||||
assert(gd->linedata[i].celldata != gd->linedata[j].celldata);
|
||||
if (gd->linedata[i].extddata != NULL)
|
||||
assert(gd->linedata[i].extddata != gd->linedata[j].extddata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grid_check_is_clear(struct grid *gd)
|
||||
{
|
||||
@@ -104,11 +89,6 @@ grid_check_is_clear(struct grid *gd)
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
grid_check_lines(__unused struct grid *gd)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
grid_check_is_clear(__unused struct grid *gd)
|
||||
{
|
||||
@@ -386,6 +366,9 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
|
||||
if (gd->sy != 0)
|
||||
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
|
||||
|
||||
#ifdef __APPLE__
|
||||
assert(gd->hsize == 0);
|
||||
#endif
|
||||
grid_check_is_clear(gd);
|
||||
return (gd);
|
||||
}
|
||||
@@ -506,8 +489,6 @@ grid_scroll_history(struct grid *gd, u_int bg)
|
||||
gd->linedata[gd->hsize].time = current_time;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Clear the history. */
|
||||
@@ -557,8 +538,6 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
|
||||
gd->hscrolled++;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Expand line to fit to cell. */
|
||||
@@ -820,8 +799,6 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
|
||||
}
|
||||
if (py != 0 && (py < dy || py >= dy + ny))
|
||||
gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Move a group of cells. */
|
||||
@@ -1311,8 +1288,6 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
||||
sy++;
|
||||
dy++;
|
||||
}
|
||||
|
||||
grid_check_lines(dst);
|
||||
}
|
||||
|
||||
/* Mark line as dead. */
|
||||
@@ -1609,8 +1584,6 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
gd->linedata = target->linedata;
|
||||
free(target);
|
||||
gd->scroll_generation++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Convert to position based on wrapped lines. */
|
||||
|
||||
458
hooks.c
Normal file
458
hooks.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/* $OpenBSD: hooks.c,v 1.13 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
* Copyright (c) 2012 George Nachman <tmux@georgester.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 MIND, 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 <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Hook monitor state owned by an option entry. */
|
||||
struct hook_monitor {
|
||||
struct options *oo;
|
||||
|
||||
struct monitor_set *set;
|
||||
struct events_sink *sink;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
char *format;
|
||||
};
|
||||
|
||||
/* Hook command data built from an event payload. */
|
||||
struct hooks_data {
|
||||
const char *name;
|
||||
struct cmd_find_state fs;
|
||||
struct format_tree *formats;
|
||||
struct options *oo;
|
||||
struct client *client;
|
||||
int expand;
|
||||
};
|
||||
|
||||
/* Hook event sink registered for a notify event name. */
|
||||
struct hooks_event {
|
||||
char *name;
|
||||
struct events_sink *sink;
|
||||
TAILQ_ENTRY(hooks_event) entry;
|
||||
};
|
||||
TAILQ_HEAD(hooks_events, hooks_event);
|
||||
static struct hooks_events hooks_events = TAILQ_HEAD_INITIALIZER(hooks_events);
|
||||
|
||||
/* Insert one hook command list. */
|
||||
static struct cmdq_item *
|
||||
hooks_insert_one(struct cmdq_item *item, struct hooks_data *hd,
|
||||
struct cmd_parse_tree *tree, struct cmdq_state *state)
|
||||
{
|
||||
struct cmdq_item *new_item;
|
||||
char *s;
|
||||
|
||||
if (tree == NULL)
|
||||
return (item);
|
||||
if (log_get_level() != 0) {
|
||||
s = cmd_parse_print(tree, 0);
|
||||
log_debug("%s: hook %s is: %s", __func__, hd->name, s);
|
||||
free(s);
|
||||
}
|
||||
new_item = cmd_invoke_get(tree, state, NULL);
|
||||
if (item != NULL)
|
||||
return (cmdq_insert_after(item, new_item));
|
||||
return (cmdq_append(NULL, new_item));
|
||||
}
|
||||
|
||||
/* Parse a hook command. */
|
||||
static struct cmd_parse_tree *
|
||||
hooks_parse(struct hooks_data *hd, struct cmd_find_state *fs,
|
||||
const char *value, char **cause)
|
||||
{
|
||||
struct cmd_parse_tree *tree;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
|
||||
if (!hd->expand)
|
||||
return (cmd_parse_from_string(value, NULL, cause));
|
||||
|
||||
ft = format_create_defaults(NULL, hd->client, fs->s, fs->wl, fs->wp);
|
||||
if (hd->formats != NULL)
|
||||
format_merge(ft, hd->formats);
|
||||
expanded = format_expand(ft, value);
|
||||
format_free(ft);
|
||||
|
||||
tree = cmd_parse_from_string(expanded, NULL, cause);
|
||||
free(expanded);
|
||||
return (tree);
|
||||
}
|
||||
|
||||
/* Insert commands for a hook. */
|
||||
static void
|
||||
hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
|
||||
{
|
||||
struct cmd_find_state fs;
|
||||
struct options *oo;
|
||||
struct cmdq_state *state;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_parse_tree *tree;
|
||||
const char *value;
|
||||
char *cause = NULL;
|
||||
|
||||
log_debug("%s: inserting hook %s", __func__, hd->name);
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (cmd_find_empty_state(&hd->fs) || !cmd_find_valid_state(&hd->fs))
|
||||
cmd_find_from_nothing(&fs, 0);
|
||||
else
|
||||
cmd_find_copy_state(&fs, &hd->fs);
|
||||
|
||||
if (hd->oo != NULL) {
|
||||
oo = hd->oo;
|
||||
o = options_get_only(oo, hd->name);
|
||||
} else {
|
||||
if (fs.s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = fs.s->options;
|
||||
o = options_get(oo, hd->name);
|
||||
if (o == NULL && fs.wp != NULL) {
|
||||
oo = fs.wp->options;
|
||||
o = options_get(oo, hd->name);
|
||||
}
|
||||
if (o == NULL && fs.wl != NULL) {
|
||||
oo = fs.wl->window->options;
|
||||
o = options_get(oo, hd->name);
|
||||
}
|
||||
}
|
||||
if (o == NULL) {
|
||||
log_debug("%s: hook %s not found", __func__, hd->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item == NULL)
|
||||
state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
|
||||
else {
|
||||
state = cmdq_new_state(&fs, cmdq_get_event(item),
|
||||
CMDQ_STATE_NOHOOKS);
|
||||
}
|
||||
cmdq_add_formats(state, hd->formats);
|
||||
|
||||
if (*hd->name == '@') {
|
||||
value = options_get_string(oo, hd->name);
|
||||
cause = NULL;
|
||||
tree = hooks_parse(hd, &fs, value, &cause);
|
||||
if (tree == NULL) {
|
||||
log_debug("%s: can't parse hook %s: %s", __func__,
|
||||
hd->name, cause);
|
||||
free(cause);
|
||||
} else {
|
||||
hooks_insert_one(item, hd, tree, state);
|
||||
cmd_parse_free(tree);
|
||||
}
|
||||
} else {
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
if (hd->expand) {
|
||||
value = options_array_item_value(a)->string;
|
||||
cause = NULL;
|
||||
tree = hooks_parse(hd, &fs, value, &cause);
|
||||
if (tree == NULL) {
|
||||
if (cause != NULL)
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
} else {
|
||||
item = hooks_insert_one(item, hd, tree,
|
||||
state);
|
||||
cmd_parse_free(tree);
|
||||
}
|
||||
} else {
|
||||
tree = options_array_item_value(a)->cmd;
|
||||
item = hooks_insert_one(item, hd, tree,
|
||||
state);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
cmdq_free_state(state);
|
||||
}
|
||||
|
||||
/* Insert commands for a hook event. */
|
||||
static void
|
||||
hooks_insert_event(struct cmdq_item *item, const char *name,
|
||||
struct event_payload *ep, struct options *oo, int expand)
|
||||
{
|
||||
struct hooks_data hd;
|
||||
struct format_tree *ft;
|
||||
struct client *c;
|
||||
|
||||
if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
return;
|
||||
|
||||
c = event_payload_get_client(ep, "client");
|
||||
ft = format_create(c, item, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, "hook_");
|
||||
format_add(ft, "hook", "%s", name);
|
||||
format_log_debug(ft, __func__);
|
||||
|
||||
memset(&hd, 0, sizeof hd);
|
||||
hd.name = name;
|
||||
cmd_find_clear_state(&hd.fs, 0);
|
||||
event_payload_get_target(ep, &hd.fs);
|
||||
hd.formats = ft;
|
||||
hd.oo = oo;
|
||||
hd.client = c;
|
||||
hd.expand = expand;
|
||||
|
||||
hooks_insert(item, &hd);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
/* Handle an event for hooks. */
|
||||
static void
|
||||
hooks_event_cb(const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct cmdq_item *item;
|
||||
|
||||
if (event_payload_get_pointer(ep, "_hook_monitor") != NULL)
|
||||
return;
|
||||
|
||||
item = event_payload_get_pointer(ep, "_cmdq_item");
|
||||
if (item != NULL) {
|
||||
hooks_insert_event(item, name, ep, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
item = cmdq_running(NULL);
|
||||
if (item == NULL || (~cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
hooks_insert_event(NULL, name, ep, NULL, 0);
|
||||
}
|
||||
|
||||
/* Add a hook event sink. */
|
||||
void
|
||||
hooks_add_event(const char *name)
|
||||
{
|
||||
struct hooks_event *he;
|
||||
|
||||
TAILQ_FOREACH(he, &hooks_events, entry) {
|
||||
if (strcmp(he->name, name) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
he = xcalloc(1, sizeof *he);
|
||||
he->name = xstrdup(name);
|
||||
he->sink = events_add_sink(name, hooks_event_cb, NULL);
|
||||
TAILQ_INSERT_TAIL(&hooks_events, he, entry);
|
||||
}
|
||||
|
||||
/* Return if an event name can be fired through the hooks path. */
|
||||
int
|
||||
hooks_valid_event_name(const char *name)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
if (*name == '@')
|
||||
return (1);
|
||||
oe = options_search(name);
|
||||
return (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK));
|
||||
}
|
||||
|
||||
/* Add hook event sinks for all built-in hooks. */
|
||||
void
|
||||
hooks_build_events(void)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (oe->flags & OPTIONS_TABLE_IS_HOOK)
|
||||
hooks_add_event(oe->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a hook immediately. */
|
||||
void
|
||||
hooks_run(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct hooks_data hd = { 0 };
|
||||
|
||||
hd.name = name;
|
||||
cmd_find_copy_state(&hd.fs, target);
|
||||
hd.client = cmdq_get_client(item);
|
||||
|
||||
hd.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||
format_add(hd.formats, "hook", "%s", name);
|
||||
format_log_debug(hd.formats, __func__);
|
||||
|
||||
hooks_insert(item, &hd);
|
||||
format_free(hd.formats);
|
||||
}
|
||||
|
||||
/* Free a hook monitor. */
|
||||
void
|
||||
hooks_monitor_free(void *data)
|
||||
{
|
||||
struct hook_monitor *hm = data;
|
||||
|
||||
events_remove_sink(hm->sink);
|
||||
monitor_destroy(hm->set);
|
||||
free(hm->format);
|
||||
free(hm);
|
||||
}
|
||||
|
||||
/* Remove a hook monitor. */
|
||||
void
|
||||
hooks_monitor_remove(struct options *oo, const char *name)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct hook_monitor *hm;
|
||||
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
return;
|
||||
|
||||
hm = options_get_monitor_data(o);
|
||||
if (hm != NULL) {
|
||||
options_set_monitor_data(o, NULL);
|
||||
hooks_monitor_free(hm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle a hook monitor event. */
|
||||
static void
|
||||
hooks_monitor_hook_cb(const char *name, struct event_payload *ep,
|
||||
void *sink_data)
|
||||
{
|
||||
struct hook_monitor *hm = sink_data;
|
||||
|
||||
if (event_payload_get_pointer(ep, "_hook_monitor") == hm)
|
||||
hooks_insert_event(cmdq_running(NULL), name, ep, hm->oo, 1);
|
||||
}
|
||||
|
||||
/* Fire a hook monitor event. */
|
||||
static void
|
||||
hooks_monitor_cb(struct monitor_change *change, void *data)
|
||||
{
|
||||
struct hook_monitor *hm = data;
|
||||
struct event_payload *ep;
|
||||
struct winlink *wl = change->wl;
|
||||
struct window_pane *wp = change->wp;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
event_payload_set_pointer(ep, "_hook_monitor", data, NULL, NULL);
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (wl != NULL && wp != NULL && wp->window == wl->window)
|
||||
cmd_find_from_winlink_pane(&fs, wl, wp, 0);
|
||||
else if (wl != NULL)
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
else if (wp != NULL)
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
else if (change->s != NULL)
|
||||
cmd_find_from_session(&fs, change->s, 0);
|
||||
else
|
||||
cmd_find_copy_state(&fs, &hm->fs);
|
||||
event_payload_set_target(ep, &fs);
|
||||
|
||||
if (change->value != NULL)
|
||||
event_payload_set_string(ep, "value", "%s", change->value);
|
||||
else
|
||||
event_payload_set_string(ep, "value", "%s", "");
|
||||
if (change->last != NULL)
|
||||
event_payload_set_string(ep, "last", "%s", change->last);
|
||||
else
|
||||
event_payload_set_string(ep, "last", "%s", "");
|
||||
|
||||
if (change->c != NULL)
|
||||
event_payload_set_client(ep, "client", change->c);
|
||||
if (change->s != NULL)
|
||||
event_payload_set_session(ep, "session", change->s);
|
||||
if (wl != NULL) {
|
||||
if (change->s == NULL)
|
||||
event_payload_set_session(ep, "session",
|
||||
wl->session);
|
||||
event_payload_set_window(ep, "window", wl->window);
|
||||
event_payload_set_int(ep, "window_index", wl->idx);
|
||||
}
|
||||
if (wp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
if (wl == NULL)
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
}
|
||||
|
||||
events_fire(change->name, ep);
|
||||
}
|
||||
|
||||
/* Add a hook monitor. */
|
||||
void
|
||||
hooks_monitor_add(__unused struct cmdq_item *item, struct options *oo,
|
||||
const char *name, enum monitor_type type, int id, const char *format,
|
||||
int flags, struct cmd_find_state *fs, struct session *s)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct hook_monitor *hm;
|
||||
|
||||
hooks_monitor_remove(oo, name);
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
o = options_set_string(oo, name, 0, "%s", "");
|
||||
|
||||
hm = xcalloc(1, sizeof *hm);
|
||||
hm->oo = oo;
|
||||
cmd_find_copy_state(&hm->fs, fs);
|
||||
hm->type = type;
|
||||
hm->id = id;
|
||||
hm->format = xstrdup(format);
|
||||
hm->set = monitor_create_session(s, hooks_monitor_cb, hm);
|
||||
hm->sink = events_add_sink(name, hooks_monitor_hook_cb, hm);
|
||||
options_set_monitor_data(o, hm);
|
||||
monitor_add(hm->set, name, type, id, format, flags);
|
||||
}
|
||||
|
||||
/* Convert a hook monitor to its value. */
|
||||
char *
|
||||
hooks_monitor_to_string(struct options_entry *o)
|
||||
{
|
||||
struct hook_monitor *hm = options_get_monitor_data(o);
|
||||
const char *name = options_name(o);
|
||||
char *s;
|
||||
|
||||
if (hm == NULL)
|
||||
return (NULL);
|
||||
|
||||
switch (hm->type) {
|
||||
case MONITOR_SESSION:
|
||||
xasprintf(&s, "%s::%s", name, hm->format);
|
||||
break;
|
||||
case MONITOR_PANE:
|
||||
xasprintf(&s, "%s:%%%d:%s", name, hm->id, hm->format);
|
||||
break;
|
||||
case MONITOR_ALL_PANES:
|
||||
xasprintf(&s, "%s:%%*:%s", name, hm->format);
|
||||
break;
|
||||
case MONITOR_WINDOW:
|
||||
xasprintf(&s, "%s:@%d:%s", name, hm->id, hm->format);
|
||||
break;
|
||||
case MONITOR_ALL_WINDOWS:
|
||||
xasprintf(&s, "%s:@*:%s", name, hm->format);
|
||||
break;
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: hyperlinks.c,v 1.5 2026/06/29 16:44:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Will <author@will.party>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: input-keys.c,v 1.114 2026/06/15 21:47:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
114
input.c
114
input.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: input.c,v 1.266 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -174,6 +174,8 @@ static void input_osc_110(struct input_ctx *, const char *);
|
||||
static void input_osc_111(struct input_ctx *, const char *);
|
||||
static void input_osc_112(struct input_ctx *, const char *);
|
||||
static void input_osc_133(struct input_ctx *, const char *);
|
||||
static void input_fire_pane_title_changed(struct window_pane *,
|
||||
const char *);
|
||||
|
||||
/* Transition entry/exit handlers. */
|
||||
static void input_clear(struct input_ctx *);
|
||||
@@ -210,6 +212,21 @@ static int input_end_bel(struct input_ctx *);
|
||||
/* Command table comparison function. */
|
||||
static int input_table_compare(const void *, const void *);
|
||||
|
||||
static void
|
||||
input_fire_pane_title_changed(struct window_pane *wp, const char *title)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
}
|
||||
|
||||
/* Command table entry. */
|
||||
struct input_table_entry {
|
||||
int ch;
|
||||
@@ -1017,6 +1034,8 @@ input_parse_pane(struct window_pane *wp)
|
||||
size_t new_size;
|
||||
|
||||
new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
|
||||
if (new_size != 0)
|
||||
wp->last_output_time = time(NULL);
|
||||
input_parse_buffer(wp, new_data, new_size);
|
||||
window_pane_update_used_data(wp, &wp->offset, new_size);
|
||||
}
|
||||
@@ -2180,7 +2199,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
|
||||
screen_pop_title(sctx->s);
|
||||
if (wp == NULL)
|
||||
break;
|
||||
notify_pane("pane-title-changed", wp);
|
||||
events_fire_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(w);
|
||||
server_status_window(w);
|
||||
break;
|
||||
@@ -2700,7 +2719,7 @@ input_exit_osc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, p, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, p);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -2778,7 +2797,7 @@ input_exit_apc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, ictx->input_buf, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, ictx->input_buf);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -2818,7 +2837,7 @@ input_exit_rename(struct input_ctx *ictx)
|
||||
if (ictx->input_len == 0) {
|
||||
o = options_get_only(w->options, "automatic-rename");
|
||||
if (o != NULL)
|
||||
options_remove_or_default(o, -1, NULL);
|
||||
options_remove_or_default(o, NULL, NULL);
|
||||
if (!options_get_number(w->options, "automatic-rename"))
|
||||
window_set_name(w, "", 1);
|
||||
} else {
|
||||
@@ -3146,7 +3165,8 @@ input_osc_12(struct input_ctx *ictx, const char *p)
|
||||
c = ictx->ctx.s->ccolour;
|
||||
if (c == -1)
|
||||
c = ictx->ctx.s->default_ccolour;
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c,
|
||||
ictx->input_end);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3166,24 +3186,92 @@ input_osc_112(struct input_ctx *ictx, const char *p)
|
||||
screen_set_cursor_colour(ictx->ctx.s, -1);
|
||||
}
|
||||
|
||||
/* Fire an OSC 133 command event. */
|
||||
static void
|
||||
input_fire_command_event(struct window_pane *wp, const char *name)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
time_t tstart = wp->cmd_start_time, end;
|
||||
time_t tend = wp->cmd_end_time;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
if (fs.s != NULL)
|
||||
event_payload_set_session(ep, "session", fs.s);
|
||||
if (fs.wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", fs.wl->idx);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
|
||||
if (wp->cmd_status != -1)
|
||||
event_payload_set_int(ep, "command_status", wp->cmd_status);
|
||||
if (tstart != 0)
|
||||
event_payload_set_time(ep, "command_start_time", tstart);
|
||||
if (tend != 0)
|
||||
event_payload_set_time(ep, "command_end_time", tend);
|
||||
|
||||
if (tstart != 0) {
|
||||
if (wp->flags & PANE_CMDRUNNING)
|
||||
end = time(NULL);
|
||||
else
|
||||
end = tend;
|
||||
if (end < tstart)
|
||||
end = tstart;
|
||||
end -= tstart;
|
||||
event_payload_set_uint(ep, "command_duration", end);
|
||||
}
|
||||
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Handle the OSC 133 sequence. */
|
||||
static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid *gd = ictx->ctx.s->grid;
|
||||
u_int line = ictx->ctx.s->cy + gd->hsize;
|
||||
struct grid_line *gl;
|
||||
struct grid_line *gl = NULL;
|
||||
const char *errstr;
|
||||
int status;
|
||||
|
||||
if (line > gd->hsize + gd->sy - 1)
|
||||
return;
|
||||
gl = grid_get_line(gd, line);
|
||||
if (line <= gd->hsize + gd->sy - 1)
|
||||
gl = grid_get_line(gd, line);
|
||||
|
||||
switch (*p) {
|
||||
case 'A':
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (gl != NULL)
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
events_fire_pane("pane-shell-prompt", wp);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
if (gl != NULL)
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
if (wp != NULL) {
|
||||
wp->cmd_start_time = time(NULL);
|
||||
wp->cmd_end_time = 0;
|
||||
wp->flags |= PANE_CMDRUNNING;
|
||||
wp->cmd_status = -1;
|
||||
input_fire_command_event(wp, "pane-command-started");
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if (wp != NULL) {
|
||||
wp->cmd_end_time = time(NULL);
|
||||
wp->flags &= ~PANE_CMDRUNNING;
|
||||
wp->cmd_status = -1;
|
||||
if (p[1] == ';' && p[2] != '\0') {
|
||||
status = strtonum(p + 2, 0, INT_MAX, &errstr);
|
||||
if (errstr == NULL)
|
||||
wp->cmd_status = status;
|
||||
}
|
||||
input_fire_command_event(wp, "pane-command-finished");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3289,7 +3377,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, clip, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
events_fire_pane("pane-set-clipboard", wp);
|
||||
paste_add(NULL, out, outlen);
|
||||
}
|
||||
}
|
||||
|
||||
18
job.c
18
job.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: job.c,v 1.75 2026/07/12 20:35:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -147,7 +147,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
else if (chdir("/") == 0)
|
||||
environ_set(env, "PWD", 0, "/");
|
||||
else
|
||||
fatal("chdir failed");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
environ_push(env);
|
||||
@@ -155,21 +155,21 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
|
||||
if (~flags & JOB_PTY) {
|
||||
if (dup2(out[1], STDIN_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDIN_FILENO;
|
||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDOUT_FILENO;
|
||||
if (flags & JOB_SHOWSTDERR) {
|
||||
if (dup2(out[1], STDERR_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDERR_FILENO;
|
||||
} else {
|
||||
nullfd = open(_PATH_DEVNULL, O_RDWR);
|
||||
if (nullfd == -1)
|
||||
fatal("open failed");
|
||||
_exit(1);
|
||||
if (dup2(nullfd, STDERR_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
if (nullfd != STDERR_FILENO)
|
||||
close(nullfd);
|
||||
}
|
||||
@@ -183,11 +183,11 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
if (flags & JOB_DEFAULTSHELL)
|
||||
setenv("SHELL", shell, 1);
|
||||
execl(shell, argv0, "-c", cmd, (char *)NULL);
|
||||
fatal("execl failed");
|
||||
_exit(1);
|
||||
} else {
|
||||
argvp = cmd_copy_argv(argc, argv);
|
||||
execvp(argvp[0], argvp);
|
||||
fatal("execvp failed");
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: key-bindings.c,v 1.186 2026/07/07 12:30:36 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -59,17 +59,45 @@
|
||||
" '#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}' 'C-h' {copy-mode -q; send-keys -l -- \"#{q:mouse_hyperlink}\"}" \
|
||||
" '#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}' 'h' {copy-mode -q; set-buffer -- \"#{q:mouse_hyperlink}\"}" \
|
||||
" ''" \
|
||||
" '#{?#{#{pane_floating_flag}},Move,}' '' {display-menu -xL -yL -T '#[align=centre]Move' " DEFAULT_MOVE_MENU " }" \
|
||||
" '#{?#{#{pane_floating_flag}},Move & Resize,}' '' {display-menu -xL -yL -T '#[align=centre]Move & Resize' " DEFAULT_MOVE_RESIZE_MENU " }" \
|
||||
" '#{?#{#{pane_floating_flag}},Tile,}' 't' { join-pane }" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Float,}' 'f' { break-pane -W }" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Horizontal Split,}' 'h' {split-window -h}" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Vertical Split,}' 'v' {split-window -v}" \
|
||||
" ''" \
|
||||
" '#{?#{&&:#{!:#{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_floating_flag}},#{?pane_marked_set,,-}Swap Marked,}' 's' {swap-pane}" \
|
||||
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \
|
||||
" ''" \
|
||||
" 'Kill' 'X' {kill-pane}" \
|
||||
" 'Respawn' 'R' {respawn-pane -k}" \
|
||||
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
|
||||
" '#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
|
||||
#define DEFAULT_MOVE_MENU \
|
||||
" 'Centre' 'c' {move-pane -P centre}" \
|
||||
" ''" \
|
||||
" 'Top Left' '1' {move-pane -P top-left}" \
|
||||
" 'Top Right' '2' {move-pane -P top-right}" \
|
||||
" 'Bottom Left' '3' {move-pane -P bottom-left}" \
|
||||
" 'Bottom Right' '4' {move-pane -P bottom-right}" \
|
||||
" ''" \
|
||||
" 'Top' 't' {move-pane -P top-centre}" \
|
||||
" 'Bottom' 'b' {move-pane -P bottom-centre}" \
|
||||
" 'Left' 'l' {move-pane -P centre-left}" \
|
||||
" 'Right' 'r' {move-pane -P centre-right}"
|
||||
#define DEFAULT_MOVE_RESIZE_MENU \
|
||||
" 'Fill' '0' {resize-pane -x100% -y100%; move-pane -P top-left}" \
|
||||
" ''" \
|
||||
" 'Top Left' '1' {resize-pane -x50% -y50%; move-pane -P top-left}" \
|
||||
" 'Top Right' '2' {resize-pane -x50% -y50%; move-pane -P top-right}" \
|
||||
" 'Bottom Left' '3' {resize-pane -x50% -y50%; move-pane -P bottom-left}" \
|
||||
" 'Bottom Right' '4' {resize-pane -x50% -y50%; move-pane -P bottom-right}" \
|
||||
" ''" \
|
||||
" 'Top' 't' {resize-pane -x100% -y50%; move-pane -P top-centre}" \
|
||||
" 'Bottom' 'b' {resize-pane -x100% -y50%; move-pane -P bottom-centre}" \
|
||||
" 'Left' 'l' {resize-pane -x50% -y100%; move-pane -P centre-left}" \
|
||||
" 'Right' 'r' {resize-pane -x50% -y100%; move-pane -P centre-right}"
|
||||
|
||||
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
||||
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
@@ -358,13 +386,14 @@ key_bindings_init(void)
|
||||
"bind -N 'Rename current session' '$' { command-prompt -I'#S' { rename-session -- '%%' } }",
|
||||
"bind -N 'Split window horizontally' % { split-window -h }",
|
||||
"bind -N 'Kill current window' & { confirm-before -p\"kill-window #W? (y/n)\" kill-window }",
|
||||
"bind -N 'Prompt for window index to select' \"'\" { command-prompt -T window-target -pindex { select-window -t ':%%' } }",
|
||||
"bind -N 'Prompt for window index to select' \"'\" { command-prompt -pindex { select-window -t ':%%' } }",
|
||||
"bind -N 'New floating pane' * { new-pane }",
|
||||
"bind -N 'Toggle pane between floating and tiled' @ { if -F '#{pane_floating_flag}' { join-pane } { break-pane -W } }",
|
||||
"bind -N 'Switch to previous client' ( { switch-client -p }",
|
||||
"bind -N 'Switch to next client' ) { switch-client -n }",
|
||||
"bind -N 'Rename current window' , { command-prompt -I'#W' { rename-window -- '%%' } }",
|
||||
"bind -N 'Delete the most recent paste buffer' - { delete-buffer }",
|
||||
"bind -N 'Move the current window' . { command-prompt -T target { move-window -t '%%' } }",
|
||||
"bind -N 'Move the current window' . { command-prompt { move-window -t '%%' } }",
|
||||
"bind -N 'Describe key binding' '/' { command-prompt -kpkey { list-keys -1N '%%' } }",
|
||||
"bind -N 'Select window 0' 0 { select-window -t:=0 }",
|
||||
"bind -N 'Select window 1' 1 { select-window -t:=1 }",
|
||||
@@ -405,10 +434,8 @@ key_bindings_init(void)
|
||||
"bind -N 'Choose a window from a list' w { choose-tree -Zw }",
|
||||
"bind -N 'Kill the active pane' x { confirm-before -p\"kill-pane #P? (y/n)\" kill-pane }",
|
||||
"bind -N 'Zoom the active pane' z { resize-pane -Z }",
|
||||
"bind -N 'Move pane to top-left corner' '{' { resize-pane -x50% -y50%; move-pane -P top-left }",
|
||||
"bind -N 'Move pane to top-right corner' '}' { resize-pane -x50% -y50%; move-pane -P top-right }",
|
||||
"bind -N 'Move pane to bottom-left corner' 'M-{' { resize-pane -x50% -y50%; move-pane -P bottom-left }",
|
||||
"bind -N 'Move pane to bottom-right corner' 'M-}' { resize-pane -x50% -y50%; move-pane -P bottom-right }",
|
||||
"bind -N 'Swap the active pane with the pane above' '{' { swap-pane -U }",
|
||||
"bind -N 'Swap the active pane with the pane below' '}' { swap-pane -D }",
|
||||
"bind -N 'Show messages' '~' { show-messages }",
|
||||
"bind -N 'Enter copy mode and scroll up' PPage { copy-mode -u }",
|
||||
"bind -N 'Select the pane above the active pane' -r Up { select-pane -U }",
|
||||
@@ -439,6 +466,28 @@ key_bindings_init(void)
|
||||
"bind -N 'Resize the pane left' -r C-Left if -F '#{?floating_pane_flag}' { resizep -R-1 } { resize-pane -L }",
|
||||
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
|
||||
|
||||
/* Floating pane movement. */
|
||||
"bind -N 'Move a floating pane' g { switch-client -Tmove }",
|
||||
"bind -Tmove -N 'Move pane to top-left corner' 1 { move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Move pane to top-right corner' 2 { move-pane -P top-right }",
|
||||
"bind -Tmove -N 'Move pane to bottom-left corner' 3 { move-pane -P bottom-left }",
|
||||
"bind -Tmove -N 'Move pane to bottom-right corner' 4 { move-pane -P bottom-right }",
|
||||
"bind -Tmove -N 'Move pane to top-left corner and resize' M-1 { resize-pane -x50% -y50%; move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Move pane to top-right corner and resize' M-2 { resize-pane -x50% -y50%; move-pane -P top-right }",
|
||||
"bind -Tmove -N 'Move pane to bottom-left corner and resize' M-3 { resize-pane -x50% -y50%; move-pane -P bottom-left }",
|
||||
"bind -Tmove -N 'Move pane to bottom-right corner and resize' M-4 { resize-pane -x50% -y50%; move-pane -P bottom-right }",
|
||||
"bind -Tmove -N 'Move pane to top' 'Up' { move-pane -P top-centre }",
|
||||
"bind -Tmove -N 'Move pane to bottom' 'Down' { move-pane -P bottom-centre }",
|
||||
"bind -Tmove -N 'Move pane to left' 'Left' { move-pane -P centre-left }",
|
||||
"bind -Tmove -N 'Move pane to right' 'Right' { move-pane -P centre-right }",
|
||||
"bind -Tmove -N 'Move pane to top and resize' 'M-Up' { resizep -x100% -y50%; move-pane -P top-centre }",
|
||||
"bind -Tmove -N 'Move pane to bottom and resize' 'M-Down' { resizep -x100% -y50%; move-pane -P bottom-centre }",
|
||||
"bind -Tmove -N 'Move pane to left and resize' 'M-Left' { resizep -x50% -y100%; move-pane -P centre-left }",
|
||||
"bind -Tmove -N 'Move pane to right and resize' 'M-Right' { resizep -x50% -y100%; move-pane -P centre-right }",
|
||||
"bind -Tmove -N 'Move pane to fill the window' 0 { resize-pane -x100% -y100%; move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Display move menu' , { if -F '#{pane_floating_flag}' { display-menu -xP -yP -T '#[align=centre]Move' " DEFAULT_MOVE_MENU " } }",
|
||||
"bind -Tmove -N 'Display move and resize menu' . { if -F '#{pane_floating_flag}' { display-menu -xP -yP -T '#[align=centre]Move & Resize' " DEFAULT_MOVE_RESIZE_MENU " } }",
|
||||
|
||||
/* Menu keys */
|
||||
"bind -N 'Display window menu' < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }",
|
||||
"bind -N 'Display pane menu' > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
||||
@@ -477,6 +526,7 @@ key_bindings_init(void)
|
||||
/* Mouse button 1 down on default pane-border-format */
|
||||
"bind -n MouseDown1Control9 { display-menu -t= -xM -yM -O -T 'Kill pane #{pane_index}?' 'Yes' 'y' { kill-pane -t= } 'No' 'n' {}}",
|
||||
"bind -n MouseDown1Control8 { resize-pane -Z }",
|
||||
"bind -n MouseDown1Control7 { if -Ft= '#{pane_floating_flag}' { join-pane } { break-pane -W } }",
|
||||
|
||||
/* Mouse wheel down on status line. */
|
||||
"bind -n WheelDownStatus { next-window }",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: key-string.c,v 1.77 2026/03/31 11:46:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: layout-custom.c,v 1.37 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -101,10 +101,10 @@ layout_append(struct layout_cell *lc, char *buf, size_t len)
|
||||
return (0);
|
||||
if (lc->wp != NULL) {
|
||||
tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%d,%d,%u",
|
||||
lc->sx, lc->sy, lc->xoff, lc->yoff, lc->wp->id);
|
||||
lc->g.sx, lc->g.sy, lc->g.xoff, lc->g.yoff, lc->wp->id);
|
||||
} else {
|
||||
tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%d,%d",
|
||||
lc->sx, lc->sy, lc->xoff, lc->yoff);
|
||||
lc->g.sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
}
|
||||
if (tmplen > (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
@@ -145,24 +145,24 @@ layout_check(struct layout_cell *lc)
|
||||
break;
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (lcchild->sy != lc->sy)
|
||||
if (lcchild->g.sy != lc->g.sy)
|
||||
return (0);
|
||||
if (!layout_check(lcchild))
|
||||
return (0);
|
||||
n += lcchild->sx + 1;
|
||||
n += lcchild->g.sx + 1;
|
||||
}
|
||||
if (n - 1 != lc->sx)
|
||||
if (n - 1 != lc->g.sx)
|
||||
return (0);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (lcchild->sx != lc->sx)
|
||||
if (lcchild->g.sx != lc->g.sx)
|
||||
return (0);
|
||||
if (!layout_check(lcchild))
|
||||
return (0);
|
||||
n += lcchild->sy + 1;
|
||||
n += lcchild->g.sy + 1;
|
||||
}
|
||||
if (n - 1 != lc->sy)
|
||||
if (n - 1 != lc->g.sy)
|
||||
return (0);
|
||||
break;
|
||||
}
|
||||
@@ -237,21 +237,21 @@ layout_parse(struct window *w, const char *layout, char **cause)
|
||||
break;
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
TAILQ_FOREACH(lcchild, &tiled_lc->cells, entry) {
|
||||
sy = lcchild->sy + 1;
|
||||
sx += lcchild->sx + 1;
|
||||
sy = lcchild->g.sy + 1;
|
||||
sx += lcchild->g.sx + 1;
|
||||
}
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
TAILQ_FOREACH(lcchild, &tiled_lc->cells, entry) {
|
||||
sx = lcchild->sx + 1;
|
||||
sy += lcchild->sy + 1;
|
||||
sx = lcchild->g.sx + 1;
|
||||
sy += lcchild->g.sy + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (tiled_lc->type != LAYOUT_WINDOWPANE &&
|
||||
(tiled_lc->sx != sx || tiled_lc->sy != sy)) {
|
||||
(tiled_lc->g.sx != sx || tiled_lc->g.sy != sy)) {
|
||||
layout_print_cell(tiled_lc, __func__, 0);
|
||||
tiled_lc->sx = sx - 1; tiled_lc->sy = sy - 1;
|
||||
tiled_lc->g.sx = sx - 1; tiled_lc->g.sy = sy - 1;
|
||||
}
|
||||
|
||||
/* Check the new layout. */
|
||||
@@ -262,7 +262,7 @@ layout_parse(struct window *w, const char *layout, char **cause)
|
||||
|
||||
/* Resize window to the layout size. */
|
||||
if (sx != 0 && sy != 0)
|
||||
window_resize(w, tiled_lc->sx, tiled_lc->sy, -1, -1);
|
||||
window_resize(w, tiled_lc->g.sx, tiled_lc->g.sy, -1, -1);
|
||||
|
||||
/* Destroy the old layout and swap to the new. */
|
||||
layout_free_cell(w->layout_root, 0);
|
||||
@@ -286,7 +286,7 @@ layout_parse(struct window *w, const char *layout, char **cause)
|
||||
recalculate_sizes();
|
||||
layout_print_cell(tiled_lc, __func__, 0);
|
||||
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -358,10 +358,10 @@ layout_construct_cell(struct layout_cell *lcparent, const char **layout)
|
||||
}
|
||||
|
||||
lc = layout_create_cell(lcparent);
|
||||
lc->sx = sx;
|
||||
lc->sy = sy;
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
lc->g.sx = sx;
|
||||
lc->g.sy = sy;
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
|
||||
return (lc);
|
||||
}
|
||||
|
||||
30
layout-set.c
30
layout-set.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: layout-set.c,v 1.39 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -170,8 +170,8 @@ layout_set_even(struct window *w, enum layout_type type)
|
||||
TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry);
|
||||
lcchild->parent = lcroot;
|
||||
if (layout_cell_is_tiled(lcchild)) {
|
||||
lcchild->sx = w->sx;
|
||||
lcchild->sy = w->sy;
|
||||
lcchild->g.sx = w->sx;
|
||||
lcchild->g.sy = w->sy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +182,8 @@ layout_set_even(struct window *w, enum layout_type type)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -291,8 +291,8 @@ layout_set_main_h(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -388,8 +388,8 @@ layout_set_main_h_mirrored(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -485,8 +485,8 @@ layout_set_main_v(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -583,8 +583,8 @@ layout_set_main_v_mirrored(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ layout_set_tiled(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
318
layout.c
318
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: layout.c,v 1.93 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -56,32 +56,29 @@ static int layout_set_size_check(struct window *, struct layout_cell *,
|
||||
static void layout_resize_child_cells(struct window *,
|
||||
struct layout_cell *);
|
||||
|
||||
/* Initializes cell geometry to sentinel values. */
|
||||
static void
|
||||
layout_geometry_init(struct layout_geometry *lg)
|
||||
{
|
||||
lg->sx = UINT_MAX;
|
||||
lg->sy = UINT_MAX;
|
||||
lg->xoff = INT_MAX;
|
||||
lg->yoff = INT_MAX;
|
||||
}
|
||||
|
||||
/* Create a new layout cell. */
|
||||
struct layout_cell *
|
||||
layout_create_cell(struct layout_cell *lcparent)
|
||||
{
|
||||
struct layout_cell *lc;
|
||||
|
||||
lc = xmalloc(sizeof *lc);
|
||||
lc = xcalloc(1, sizeof *lc);
|
||||
lc->type = LAYOUT_WINDOWPANE;
|
||||
lc->flags = 0;
|
||||
lc->parent = lcparent;
|
||||
|
||||
TAILQ_INIT(&lc->cells);
|
||||
|
||||
lc->sx = UINT_MAX;
|
||||
lc->sy = UINT_MAX;
|
||||
|
||||
lc->xoff = INT_MAX;
|
||||
lc->yoff = INT_MAX;
|
||||
|
||||
lc->saved_sx = UINT_MAX;
|
||||
lc->saved_sy = UINT_MAX;
|
||||
|
||||
lc->saved_xoff = INT_MAX;
|
||||
lc->saved_yoff = INT_MAX;
|
||||
|
||||
lc->wp = NULL;
|
||||
layout_geometry_init(&lc->g);
|
||||
layout_geometry_init(&lc->fg);
|
||||
|
||||
return (lc);
|
||||
}
|
||||
@@ -144,8 +141,8 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
|
||||
break;
|
||||
}
|
||||
log_debug("%s:%*s%p type %s [parent %p] wp=%p [%d,%d %ux%u]", hdr, n,
|
||||
" ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
|
||||
lc->sy);
|
||||
" ", lc, type, lc->parent, lc->wp, lc->g.xoff, lc->g.yoff, lc->g.sx,
|
||||
lc->g.sy);
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
@@ -164,10 +161,10 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
struct layout_cell *lcchild, *last = NULL;
|
||||
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if ((int)x >= lcchild->xoff &&
|
||||
(int)x < lcchild->xoff + (int)lcchild->sx &&
|
||||
(int)y >= lcchild->yoff &&
|
||||
(int)y < lcchild->yoff + (int)lcchild->sy) {
|
||||
if ((int)x >= lcchild->g.xoff &&
|
||||
(int)x < lcchild->g.xoff + (int)lcchild->g.sx &&
|
||||
(int)y >= lcchild->g.yoff &&
|
||||
(int)y < lcchild->g.yoff + (int)lcchild->g.sy) {
|
||||
/* Inside the cell - recurse. */
|
||||
return (layout_search_by_border(lcchild, x, y));
|
||||
}
|
||||
@@ -179,13 +176,13 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
if ((int)x < lcchild->xoff &&
|
||||
(int)x >= last->xoff + (int)last->sx)
|
||||
if ((int)x < lcchild->g.xoff &&
|
||||
(int)x >= last->g.xoff + (int)last->g.sx)
|
||||
return (last);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if ((int)y < lcchild->yoff &&
|
||||
(int)y >= last->yoff + (int)last->sy)
|
||||
if ((int)y < lcchild->g.yoff &&
|
||||
(int)y >= last->g.yoff + (int)last->g.sy)
|
||||
return (last);
|
||||
break;
|
||||
case LAYOUT_WINDOWPANE:
|
||||
@@ -202,11 +199,11 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
void
|
||||
layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff)
|
||||
{
|
||||
lc->sx = sx;
|
||||
lc->sy = sy;
|
||||
lc->g.sx = sx;
|
||||
lc->g.sy = sy;
|
||||
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
}
|
||||
|
||||
/* Make a cell a leaf cell. */
|
||||
@@ -331,28 +328,28 @@ layout_fix_offsets1(struct layout_cell *lc)
|
||||
int xoff, yoff;
|
||||
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
xoff = lc->xoff;
|
||||
xoff = lc->g.xoff;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_cell_is_tiled(lcchild) &&
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
lcchild->xoff = xoff;
|
||||
lcchild->yoff = lc->yoff;
|
||||
lcchild->g.xoff = xoff;
|
||||
lcchild->g.yoff = lc->g.yoff;
|
||||
if (lcchild->type != LAYOUT_WINDOWPANE)
|
||||
layout_fix_offsets1(lcchild);
|
||||
xoff += lcchild->sx + 1;
|
||||
xoff += lcchild->g.sx + 1;
|
||||
}
|
||||
} else {
|
||||
yoff = lc->yoff;
|
||||
yoff = lc->g.yoff;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_cell_is_tiled(lcchild) &&
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
lcchild->xoff = lc->xoff;
|
||||
lcchild->yoff = yoff;
|
||||
lcchild->g.xoff = lc->g.xoff;
|
||||
lcchild->g.yoff = yoff;
|
||||
if (lcchild->type != LAYOUT_WINDOWPANE)
|
||||
layout_fix_offsets1(lcchild);
|
||||
yoff += lcchild->sy + 1;
|
||||
yoff += lcchild->g.sy + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,8 +364,8 @@ layout_fix_offsets(struct window *w)
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return;
|
||||
|
||||
lc->xoff = 0;
|
||||
lc->yoff = 0;
|
||||
lc->g.xoff = 0;
|
||||
lc->g.yoff = 0;
|
||||
|
||||
layout_fix_offsets1(lc);
|
||||
}
|
||||
@@ -452,16 +449,17 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
old_sx = wp->sx;
|
||||
old_sy = wp->sy;
|
||||
|
||||
wp->xoff = lc->xoff;
|
||||
wp->yoff = lc->yoff;
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
wp->xoff = lc->g.xoff;
|
||||
wp->yoff = lc->g.yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
|
||||
if (!window_pane_is_floating(wp) &&
|
||||
layout_add_horizontal_border(w, lc, status)) {
|
||||
if (status == PANE_STATUS_TOP)
|
||||
wp->yoff++;
|
||||
sy--;
|
||||
if (sy > 1)
|
||||
sy--;
|
||||
}
|
||||
|
||||
if (window_pane_scrollbar_reserve(wp)) {
|
||||
@@ -535,14 +533,14 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||
/* Space available in this cell only. */
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
available = lc->sx;
|
||||
available = lc->g.sx;
|
||||
if (w->sb == PANE_SCROLLBARS_ALWAYS)
|
||||
minimum = PANE_MINIMUM + sb_style->width +
|
||||
sb_style->pad;
|
||||
else
|
||||
minimum = PANE_MINIMUM;
|
||||
} else {
|
||||
available = lc->sy;
|
||||
available = lc->g.sy;
|
||||
if (layout_add_horizontal_border(w, lc, status))
|
||||
minimum = PANE_MINIMUM + 1;
|
||||
else
|
||||
@@ -580,12 +578,13 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
enum layout_type type, int change)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
int changed;
|
||||
|
||||
/* Adjust the cell size. */
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
lc->sx += change;
|
||||
lc->g.sx += change;
|
||||
else
|
||||
lc->sy += change;
|
||||
lc->g.sy += change;
|
||||
|
||||
/* If this is a leaf cell, that is all that is necessary. */
|
||||
if (type == LAYOUT_WINDOWPANE)
|
||||
@@ -613,6 +612,7 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
* until no further change is possible.
|
||||
*/
|
||||
while (change != 0) {
|
||||
changed = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (change == 0)
|
||||
break;
|
||||
@@ -622,13 +622,17 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
if (change > 0) {
|
||||
layout_resize_adjust(w, lcchild, type, 1);
|
||||
change--;
|
||||
changed = 1;
|
||||
continue;
|
||||
}
|
||||
if (layout_resize_check(w, lcchild, type) > 0) {
|
||||
layout_resize_adjust(w, lcchild, type, -1);
|
||||
change++;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
if (!changed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,9 +644,9 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
|
||||
int change;
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
change = size - lc->sx;
|
||||
change = size - lc->g.sx;
|
||||
else
|
||||
change = size - lc->sy;
|
||||
change = size - lc->g.sy;
|
||||
layout_resize_adjust(w, lc, type, change);
|
||||
}
|
||||
|
||||
@@ -716,9 +720,9 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
||||
lcother = layout_cell_get_neighbour(lc);
|
||||
if (lcother != NULL) {
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
change = lc->sx + 1;
|
||||
change = lc->g.sx + 1;
|
||||
else
|
||||
change = lc->sy + 1;
|
||||
change = lc->g.sy + 1;
|
||||
layout_resize_adjust(w, lcother, lcparent->type, change);
|
||||
} else
|
||||
layout_remove_tile(w, lcparent);
|
||||
@@ -739,8 +743,8 @@ out:
|
||||
lc->parent = lcparent->parent;
|
||||
if (lc->parent == NULL) {
|
||||
if (layout_cell_is_tiled(lc)) {
|
||||
lc->xoff = 0;
|
||||
lc->yoff = 0;
|
||||
lc->g.xoff = 0;
|
||||
lc->g.yoff = 0;
|
||||
}
|
||||
*lcroot = lc;
|
||||
} else
|
||||
@@ -791,29 +795,29 @@ layout_resize(struct window *w, u_int sx, u_int sy)
|
||||
*/
|
||||
if (lc->type == LAYOUT_WINDOWPANE && (lc->flags & LAYOUT_CELL_FLOATING))
|
||||
return;
|
||||
xchange = sx - lc->sx;
|
||||
xchange = sx - lc->g.sx;
|
||||
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
|
||||
if (xchange < 0 && xchange < -xlimit)
|
||||
xchange = -xlimit;
|
||||
if (xlimit == 0) {
|
||||
if (sx <= lc->sx) /* lc->sx is minimum possible */
|
||||
if (sx <= lc->g.sx) /* lc->g.sx is minimum possible */
|
||||
xchange = 0;
|
||||
else
|
||||
xchange = sx - lc->sx;
|
||||
xchange = sx - lc->g.sx;
|
||||
}
|
||||
if (xchange != 0)
|
||||
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
|
||||
|
||||
/* Adjust vertically in a similar fashion. */
|
||||
ychange = sy - lc->sy;
|
||||
ychange = sy - lc->g.sy;
|
||||
ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
|
||||
if (ychange < 0 && ychange < -ylimit)
|
||||
ychange = -ylimit;
|
||||
if (ylimit == 0) {
|
||||
if (sy <= lc->sy) /* lc->sy is minimum possible */
|
||||
if (sy <= lc->g.sy) /* lc->g.sy is minimum possible */
|
||||
ychange = 0;
|
||||
else
|
||||
ychange = sy - lc->sy;
|
||||
ychange = sy - lc->g.sy;
|
||||
}
|
||||
if (ychange != 0)
|
||||
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
|
||||
@@ -844,9 +848,9 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
|
||||
/* Work out the size adjustment. */
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
size = lc->sx;
|
||||
size = lc->g.sx;
|
||||
else
|
||||
size = lc->sy;
|
||||
size = lc->g.sy;
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
change = size - new_size;
|
||||
else
|
||||
@@ -877,13 +881,13 @@ layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
}
|
||||
|
||||
if (type == LAYOUT_TOPBOTTOM) {
|
||||
if (lc->sy == size)
|
||||
if (lc->g.sy == size)
|
||||
return (0);
|
||||
lc->sy = size;
|
||||
lc->g.sy = size;
|
||||
} else {
|
||||
if (lc->sx == size)
|
||||
if (lc->g.sx == size)
|
||||
return (0);
|
||||
lc->sx = size;
|
||||
lc->g.sx = size;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
@@ -905,23 +909,23 @@ layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||
return (0);
|
||||
|
||||
if (type == LAYOUT_TOPBOTTOM) {
|
||||
size = lc->sy + change;
|
||||
size = lc->g.sy + change;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("change is too big or too small");
|
||||
return (-1);
|
||||
}
|
||||
lc->sy = size;
|
||||
lc->g.sy = size;
|
||||
if (opposite)
|
||||
lc->yoff -= change;
|
||||
lc->g.yoff -= change;
|
||||
} else {
|
||||
size = lc->sx + change;
|
||||
size = lc->g.sx + change;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("change is too big or too small");
|
||||
return (-1);
|
||||
}
|
||||
lc->sx = size;
|
||||
lc->g.sx = size;
|
||||
if (opposite)
|
||||
lc->xoff -= change;
|
||||
lc->g.xoff -= change;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
@@ -953,7 +957,7 @@ layout_resize_layout(struct window *w, struct layout_cell *lc,
|
||||
/* Fix cell offsets. */
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
}
|
||||
|
||||
/* Resize a single pane within the layout. */
|
||||
@@ -1087,13 +1091,13 @@ layout_new_pane_size(struct window *w, u_int previous, struct layout_cell *lc,
|
||||
*/
|
||||
min = (PANE_MINIMUM + 1) * (count_left - 1);
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
if (lc->sx - available > min)
|
||||
min = lc->sx - available;
|
||||
new_size = (lc->sx * size) / previous;
|
||||
if (lc->g.sx - available > min)
|
||||
min = lc->g.sx - available;
|
||||
new_size = (lc->g.sx * size) / previous;
|
||||
} else {
|
||||
if (lc->sy - available > min)
|
||||
min = lc->sy - available;
|
||||
new_size = (lc->sy * size) / previous;
|
||||
if (lc->g.sy - available > min)
|
||||
min = lc->g.sy - available;
|
||||
new_size = (lc->g.sy * size) / previous;
|
||||
}
|
||||
|
||||
/* Check against the maximum and minimum size. */
|
||||
@@ -1129,9 +1133,9 @@ layout_set_size_check(struct window *w, struct layout_cell *lc,
|
||||
return (0);
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
previous = lc->sx;
|
||||
previous = lc->g.sx;
|
||||
else
|
||||
previous = lc->sy;
|
||||
previous = lc->g.sy;
|
||||
|
||||
idx = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
@@ -1167,32 +1171,32 @@ static void
|
||||
layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int previous, available, count, idx;
|
||||
u_int prev, available, count, idx;
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE)
|
||||
return;
|
||||
|
||||
/* What is the current size used? */
|
||||
count = 0;
|
||||
previous = 0;
|
||||
prev = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_cell_is_tiled(lcchild) &&
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
count++;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
previous += lcchild->sx;
|
||||
prev += lcchild->g.sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
previous += lcchild->sy;
|
||||
prev += lcchild->g.sy;
|
||||
}
|
||||
previous += (count - 1);
|
||||
prev += (count - 1);
|
||||
|
||||
/* And how much is available? */
|
||||
available = 0;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
available = lc->sx;
|
||||
available = lc->g.sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
available = lc->sy;
|
||||
available = lc->g.sy;
|
||||
|
||||
/* Resize children into the new size. */
|
||||
idx = 0;
|
||||
@@ -1201,20 +1205,20 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lcchild->sx = lc->sx;
|
||||
lcchild->xoff = lc->xoff;
|
||||
lcchild->g.sx = lc->g.sx;
|
||||
lcchild->g.xoff = lc->g.xoff;
|
||||
} else {
|
||||
lcchild->sx = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sx, count - idx, available);
|
||||
available -= (lcchild->sx + 1);
|
||||
lcchild->g.sx = layout_new_pane_size(w, prev, lcchild,
|
||||
lc->type, lc->g.sx, count - idx, available);
|
||||
available -= (lcchild->g.sx + 1);
|
||||
}
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
lcchild->sy = lc->sy;
|
||||
lcchild->yoff = lc->yoff;
|
||||
lcchild->g.sy = lc->g.sy;
|
||||
lcchild->g.yoff = lc->g.yoff;
|
||||
} else {
|
||||
lcchild->sy = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sy, count - idx, available);
|
||||
available -= (lcchild->sy + 1);
|
||||
lcchild->g.sy = layout_new_pane_size(w, prev, lcchild,
|
||||
lc->type, lc->g.sy, count - idx, available);
|
||||
available -= (lcchild->g.sy + 1);
|
||||
}
|
||||
layout_resize_child_cells(w, lcchild);
|
||||
idx++;
|
||||
@@ -1234,7 +1238,7 @@ layout_replace_with_node(struct window *w, struct layout_cell *lc,
|
||||
|
||||
lcparent = layout_create_cell(lc->parent);
|
||||
layout_make_node(lcparent, type);
|
||||
layout_set_size(lcparent, lc->sx, lc->sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lcparent, lc->g.sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
if (lc->parent == NULL)
|
||||
w->layout_root = lcparent;
|
||||
else
|
||||
@@ -1253,7 +1257,7 @@ layout_split_check_space(struct window_pane *wp, struct layout_cell *lc,
|
||||
enum layout_type type)
|
||||
{
|
||||
struct style *sb_style = &wp->scrollbar_style;
|
||||
u_int minimum, sx = lc->sx, sy = lc->sy;
|
||||
u_int minimum, sx = lc->g.sx, sy = lc->g.sy;
|
||||
int status;
|
||||
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
@@ -1292,7 +1296,7 @@ layout_split_sizes(struct layout_cell *lc, int size, int before,
|
||||
enum layout_type type, u_int *size1, u_int *size2, u_int *saved_size)
|
||||
{
|
||||
u_int s1, s2, ss;
|
||||
u_int sx = lc->sx, sy = lc->sy;
|
||||
u_int sx = lc->g.sx, sy = lc->g.sy;
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
ss = sx;
|
||||
@@ -1306,7 +1310,7 @@ layout_split_sizes(struct layout_cell *lc, int size, int before,
|
||||
s2 = size;
|
||||
if (s2 < PANE_MINIMUM)
|
||||
s2 = PANE_MINIMUM;
|
||||
else if (s2 > sx - 2)
|
||||
else if (s2 > ss - 2)
|
||||
s2 = ss - 2;
|
||||
s1 = ss - 1 - s2;
|
||||
|
||||
@@ -1339,10 +1343,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
lc = wp->layout_cell;
|
||||
|
||||
/* Copy the old cell size. */
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
xoff = lc->xoff;
|
||||
yoff = lc->yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
xoff = lc->g.xoff;
|
||||
yoff = lc->g.yoff;
|
||||
|
||||
/* Check there is enough space for the two new panes. */
|
||||
if (!layout_split_check_space(wp, lc, type))
|
||||
@@ -1383,13 +1387,13 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
* must be resized before inserting the new cell.
|
||||
*/
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
lc->sx = new_size;
|
||||
lc->g.sx = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sx = saved_size;
|
||||
lc->g.sx = saved_size;
|
||||
} else if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lc->sy = new_size;
|
||||
lc->g.sy = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sy = saved_size;
|
||||
lc->g.sy = saved_size;
|
||||
}
|
||||
resize_first = 1;
|
||||
|
||||
@@ -1433,10 +1437,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
*/
|
||||
if (!resize_first && type == LAYOUT_LEFTRIGHT) {
|
||||
layout_set_size(lc1, size1, sy, xoff, yoff);
|
||||
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
|
||||
layout_set_size(lc2, size2, sy, xoff + lc1->g.sx + 1, yoff);
|
||||
} else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
|
||||
layout_set_size(lc1, sx, size1, xoff, yoff);
|
||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
|
||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->g.sy + 1);
|
||||
}
|
||||
if (full_size) {
|
||||
if (!resize_first)
|
||||
@@ -1453,8 +1457,8 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
* layout_assign_pane before much else happens!
|
||||
*/
|
||||
struct layout_cell *
|
||||
layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||
u_int sy, int ox, int oy)
|
||||
layout_floating_pane(struct window *w, struct window_pane *wp,
|
||||
struct layout_geometry *lg)
|
||||
{
|
||||
struct layout_cell *lc, *lcnew, *lcparent;
|
||||
|
||||
@@ -1466,16 +1470,16 @@ layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||
|
||||
if (lcparent == NULL) {
|
||||
/*
|
||||
* Adding a pane to a root that isn't node. Must create and
|
||||
* insert a new root.
|
||||
*/
|
||||
* Adding a pane to a root that isn't a node. Must create and
|
||||
* insert a new root.
|
||||
*/
|
||||
lcparent = layout_replace_with_node(w, lc, LAYOUT_TOPBOTTOM);
|
||||
}
|
||||
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
||||
lcnew->flags |= LAYOUT_CELL_FLOATING;
|
||||
layout_set_size(lcnew, sx, sy, ox, oy);
|
||||
layout_set_size(lcnew, lg->sx, lg->sy, lg->xoff, lg->yoff);
|
||||
|
||||
return (lcnew);
|
||||
}
|
||||
@@ -1498,7 +1502,7 @@ layout_close_pane(struct window_pane *wp)
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
}
|
||||
|
||||
/* Spread out cells inside a parent cell. */
|
||||
@@ -1518,12 +1522,12 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
status = window_get_pane_status(w);
|
||||
|
||||
if (parent->type == LAYOUT_LEFTRIGHT)
|
||||
size = parent->sx;
|
||||
size = parent->g.sx;
|
||||
else if (parent->type == LAYOUT_TOPBOTTOM) {
|
||||
if (layout_add_horizontal_border(w, parent, status))
|
||||
size = parent->sy - 1;
|
||||
size = parent->g.sy - 1;
|
||||
else
|
||||
size = parent->sy;
|
||||
size = parent->g.sy;
|
||||
} else
|
||||
return (0);
|
||||
if (size < number - 1)
|
||||
@@ -1544,7 +1548,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
continue;
|
||||
change = 0;
|
||||
if (parent->type == LAYOUT_LEFTRIGHT) {
|
||||
change = each - (int)lc->sx;
|
||||
change = each - (int)lc->g.sx;
|
||||
if (remainder > 0) {
|
||||
change++;
|
||||
remainder--;
|
||||
@@ -1559,7 +1563,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
this++;
|
||||
remainder--;
|
||||
}
|
||||
change = this - (int)lc->sy;
|
||||
change = this - (int)lc->g.sy;
|
||||
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
|
||||
}
|
||||
if (change != 0)
|
||||
@@ -1656,29 +1660,29 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||
char **cause)
|
||||
{
|
||||
struct layout_cell *lcnew;
|
||||
u_int sx = UINT_MAX, sy = UINT_MAX;
|
||||
int ox = INT_MAX, oy = INT_MAX;
|
||||
struct layout_geometry fg;
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
cause) != 0)
|
||||
layout_geometry_init(&fg);
|
||||
if (layout_floating_args_parse(item, args, lines, w, &fg, cause) != 0)
|
||||
return (NULL);
|
||||
|
||||
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
||||
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
|
||||
lcnew = layout_floating_pane(w, wp, &fg);
|
||||
return (lcnew);
|
||||
}
|
||||
|
||||
int
|
||||
layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
enum pane_lines lines, struct window *w, u_int *sxp, u_int *syp, int *oxp,
|
||||
int *oyp, char **cause)
|
||||
enum pane_lines lines, struct window *w, struct layout_geometry *lg,
|
||||
char **cause)
|
||||
{
|
||||
int sx, sy, ox, oy;
|
||||
char *error = NULL;
|
||||
|
||||
sx = *sxp == UINT_MAX ? w->sx / 2 : *sxp;
|
||||
sy = *syp == UINT_MAX ? w->sy / 4 : *syp;
|
||||
ox = *oxp == INT_MAX ? INT_MAX : *oxp;
|
||||
oy = *oyp == INT_MAX ? INT_MAX : *oyp;
|
||||
sx = lg->sx == UINT_MAX ? w->sx / 2 : lg->sx;
|
||||
sy = lg->sy == UINT_MAX ? w->sy / 4 : lg->sy;
|
||||
ox = lg->xoff;
|
||||
oy = lg->yoff;
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
sx = args_percentage_and_expand(args, 'x', 0, PANE_MAXIMUM,
|
||||
@@ -1730,7 +1734,7 @@ layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
ox = 4;
|
||||
}
|
||||
w->last_new_pane_x = ox;
|
||||
} else
|
||||
} else if (args_has(args, 'X'))
|
||||
if (lines != PANE_LINES_NONE)
|
||||
ox += 1;
|
||||
if (oy == INT_MAX) {
|
||||
@@ -1742,7 +1746,7 @@ layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
oy = 2;
|
||||
}
|
||||
w->last_new_pane_y = oy;
|
||||
} else
|
||||
} else if (args_has(args, 'Y'))
|
||||
if (lines != PANE_LINES_NONE)
|
||||
oy += 1;
|
||||
|
||||
@@ -1755,10 +1759,10 @@ layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*sxp = sx;
|
||||
*syp = sy;
|
||||
*oxp = ox;
|
||||
*oyp = oy;
|
||||
lg->sx = sx;
|
||||
lg->sy = sy;
|
||||
lg->xoff = ox;
|
||||
lg->yoff = oy;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1774,7 +1778,7 @@ layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||
int change;
|
||||
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
lcneighbour = layout_cell_get_neighbour(lc);
|
||||
if (lcneighbour == NULL) {
|
||||
@@ -1787,9 +1791,9 @@ layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||
* neighbour.
|
||||
*/
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
change = lc->sy + 1;
|
||||
change = lc->g.sy + 1;
|
||||
else
|
||||
change = lc->sx + 1;
|
||||
change = lc->g.sx + 1;
|
||||
layout_resize_adjust(w, lcneighbour, type, change);
|
||||
}
|
||||
|
||||
@@ -1799,7 +1803,7 @@ layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||
*/
|
||||
if (lc->parent != NULL)
|
||||
layout_set_size(lc, 0, 0, 0, 0);
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1816,14 +1820,14 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
if (lc == NULL)
|
||||
fatalx("layout cell cannot be null when tiling");
|
||||
|
||||
lcparent = lc->parent;
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return (1);
|
||||
if (layout_cell_is_tiled(lc))
|
||||
return (-1);
|
||||
|
||||
lcparent = lc->parent;
|
||||
if (lcparent == NULL) {
|
||||
/* Only pane in the layout. */
|
||||
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
type = lcparent->type;
|
||||
@@ -1835,9 +1839,9 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
*/
|
||||
layout_insert_tile(w, lcparent);
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
size1 = lcparent->sx;
|
||||
size1 = lcparent->g.sx;
|
||||
else
|
||||
size1 = lcparent->sy;
|
||||
size1 = lcparent->g.sy;
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
} else {
|
||||
/*
|
||||
@@ -1846,7 +1850,7 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
*/
|
||||
lctiled = layout_cell_get_first_tiled(lcneighbour);
|
||||
if (!layout_split_check_space(lctiled->wp, lcneighbour, type))
|
||||
return (0);
|
||||
return (-1);
|
||||
layout_split_sizes(lcneighbour, -1, 0, type, &size1, &size2,
|
||||
&saved_size);
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
@@ -1855,13 +1859,13 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
|
||||
/* Setting opposite of the 'split' size to that of the parent. */
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT) {
|
||||
size1 = lcparent->sy;
|
||||
size1 = lcparent->g.sy;
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
} else {
|
||||
size1 = lcparent->sx;
|
||||
size1 = lcparent->g.sx;
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
}
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user