mirror of
https://github.com/tmux/tmux.git
synced 2026-03-07 08:15:36 +00:00
Merge branch 'master' into feature-floating-window-panes
This commit is contained in:
@@ -758,7 +758,7 @@ static int
|
|||||||
cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||||
struct cmd_parse_input *pi, struct cmd_parse_result *pr)
|
struct cmd_parse_input *pi, struct cmd_parse_result *pr)
|
||||||
{
|
{
|
||||||
struct cmd_parse_argument *arg, *arg1, *first;
|
struct cmd_parse_argument *first;
|
||||||
struct cmd_parse_commands *cmds;
|
struct cmd_parse_commands *cmds;
|
||||||
struct cmd_parse_command *last;
|
struct cmd_parse_command *last;
|
||||||
char *alias, *name, *cause;
|
char *alias, *name, *cause;
|
||||||
@@ -798,10 +798,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
|||||||
TAILQ_REMOVE(&cmd->arguments, first, entry);
|
TAILQ_REMOVE(&cmd->arguments, first, entry);
|
||||||
cmd_parse_free_argument(first);
|
cmd_parse_free_argument(first);
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) {
|
TAILQ_CONCAT(&last->arguments, &cmd->arguments, entry);
|
||||||
TAILQ_REMOVE(&cmd->arguments, arg, entry);
|
|
||||||
TAILQ_INSERT_TAIL(&last->arguments, arg, entry);
|
|
||||||
}
|
|
||||||
cmd_parse_log_commands(cmds, __func__);
|
cmd_parse_log_commands(cmds, __func__);
|
||||||
|
|
||||||
pi->flags |= CMD_PARSE_NOALIAS;
|
pi->flags |= CMD_PARSE_NOALIAS;
|
||||||
|
|||||||
15
format.c
15
format.c
@@ -1947,6 +1947,18 @@ format_cb_origin_flag(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for synchronized_output_flag. */
|
||||||
|
static void *
|
||||||
|
format_cb_synchronized_output_flag(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->wp != NULL) {
|
||||||
|
if (ft->wp->base.mode & MODE_SYNC)
|
||||||
|
return (xstrdup("1"));
|
||||||
|
return (xstrdup("0"));
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for pane_active. */
|
/* Callback for pane_active. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_pane_active(struct format_tree *ft)
|
format_cb_pane_active(struct format_tree *ft)
|
||||||
@@ -3443,6 +3455,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "start_time", FORMAT_TABLE_TIME,
|
{ "start_time", FORMAT_TABLE_TIME,
|
||||||
format_cb_start_time
|
format_cb_start_time
|
||||||
},
|
},
|
||||||
|
{ "synchronized_output_flag", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_synchronized_output_flag
|
||||||
|
},
|
||||||
{ "tree_mode_format", FORMAT_TABLE_STRING,
|
{ "tree_mode_format", FORMAT_TABLE_STRING,
|
||||||
format_cb_tree_mode_format
|
format_cb_tree_mode_format
|
||||||
},
|
},
|
||||||
|
|||||||
50
image.c
50
image.c
@@ -27,11 +27,36 @@ static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images);
|
|||||||
static u_int all_images_count;
|
static u_int all_images_count;
|
||||||
#define MAX_IMAGE_COUNT 20
|
#define MAX_IMAGE_COUNT 20
|
||||||
|
|
||||||
|
static void printflike(3, 4)
|
||||||
|
image_log(struct image *im, const char* from, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char s[128];
|
||||||
|
|
||||||
|
if (log_get_level() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fmt == NULL) {
|
||||||
|
log_debug("%s: %p (%ux%u %u,%u)", from, im, im->sx, im->sy,
|
||||||
|
im->px, im->py);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(s, sizeof s, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
log_debug("%s: %p (%ux%u %u,%u): %s", from, im, im->sx, im->sy,
|
||||||
|
im->px, im->py, s);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
image_free(struct image *im)
|
image_free(struct image *im)
|
||||||
{
|
{
|
||||||
struct screen *s = im->s;
|
struct screen *s = im->s;
|
||||||
|
|
||||||
|
image_log(im, __func__, NULL);
|
||||||
|
|
||||||
TAILQ_REMOVE(&all_images, im, all_entry);
|
TAILQ_REMOVE(&all_images, im, all_entry);
|
||||||
all_images_count--;
|
all_images_count--;
|
||||||
|
|
||||||
@@ -47,6 +72,8 @@ image_free_all(struct screen *s)
|
|||||||
struct image *im, *im1;
|
struct image *im, *im1;
|
||||||
int redraw = !TAILQ_EMPTY(&s->images);
|
int redraw = !TAILQ_EMPTY(&s->images);
|
||||||
|
|
||||||
|
if (redraw)
|
||||||
|
log_debug ("%s", __func__);
|
||||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1)
|
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1)
|
||||||
image_free(im);
|
image_free(im);
|
||||||
return (redraw);
|
return (redraw);
|
||||||
@@ -109,6 +136,7 @@ image_store(struct screen *s, struct sixel_image *si)
|
|||||||
|
|
||||||
image_fallback(&im->fallback, im->sx, im->sy);
|
image_fallback(&im->fallback, im->sx, im->sy);
|
||||||
|
|
||||||
|
image_log(im, __func__, NULL);
|
||||||
TAILQ_INSERT_TAIL(&s->images, im, entry);
|
TAILQ_INSERT_TAIL(&s->images, im, entry);
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&all_images, im, all_entry);
|
TAILQ_INSERT_TAIL(&all_images, im, all_entry);
|
||||||
@@ -122,10 +150,12 @@ int
|
|||||||
image_check_line(struct screen *s, u_int py, u_int ny)
|
image_check_line(struct screen *s, u_int py, u_int ny)
|
||||||
{
|
{
|
||||||
struct image *im, *im1;
|
struct image *im, *im1;
|
||||||
int redraw = 0;
|
int redraw = 0, in;
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||||
if (py + ny > im->py && py < im->py + im->sy) {
|
in = (py + ny > im->py && py < im->py + im->sy);
|
||||||
|
image_log(im, __func__, "py=%u, ny=%u, in=%d", py, ny, in);
|
||||||
|
if (in) {
|
||||||
image_free(im);
|
image_free(im);
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
}
|
}
|
||||||
@@ -137,16 +167,19 @@ int
|
|||||||
image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny)
|
image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny)
|
||||||
{
|
{
|
||||||
struct image *im, *im1;
|
struct image *im, *im1;
|
||||||
int redraw = 0;
|
int redraw = 0, in;
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||||
if (py + ny <= im->py || py >= im->py + im->sy)
|
in = (py < im->py + im->sy &&
|
||||||
continue;
|
py + ny > im->py &&
|
||||||
if (px + nx <= im->px || px >= im->px + im->sx)
|
px < im->px + im->sx &&
|
||||||
continue;
|
px + nx > im->px);
|
||||||
|
image_log(im, __func__, "py=%u, ny=%u, in=%d", py, ny, in);
|
||||||
|
if (in) {
|
||||||
image_free(im);
|
image_free(im);
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return (redraw);
|
return (redraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,17 +193,20 @@ image_scroll_up(struct screen *s, u_int lines)
|
|||||||
|
|
||||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||||
if (im->py >= lines) {
|
if (im->py >= lines) {
|
||||||
|
image_log(im, __func__, "1, lines=%u", lines);
|
||||||
im->py -= lines;
|
im->py -= lines;
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (im->py + im->sy <= lines) {
|
if (im->py + im->sy <= lines) {
|
||||||
|
image_log(im, __func__, "2, lines=%u", lines);
|
||||||
image_free(im);
|
image_free(im);
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sx = im->sx;
|
sx = im->sx;
|
||||||
sy = (im->py + im->sy) - lines;
|
sy = (im->py + im->sy) - lines;
|
||||||
|
image_log(im, __func__, "3, lines=%u, sy=%u", lines, sy);
|
||||||
|
|
||||||
new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1);
|
new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1);
|
||||||
sixel_free(im->data);
|
sixel_free(im->data);
|
||||||
|
|||||||
10
input.c
10
input.c
@@ -898,6 +898,8 @@ input_free(struct input_ctx *ictx)
|
|||||||
evbuffer_free(ictx->since_ground);
|
evbuffer_free(ictx->since_ground);
|
||||||
event_del(&ictx->ground_timer);
|
event_del(&ictx->ground_timer);
|
||||||
|
|
||||||
|
screen_write_stop_sync(ictx->wp);
|
||||||
|
|
||||||
free(ictx);
|
free(ictx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1901,6 +1903,11 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
|
|||||||
case 2031:
|
case 2031:
|
||||||
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
|
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
|
||||||
break;
|
break;
|
||||||
|
case 2026: /* synchronized output */
|
||||||
|
screen_write_stop_sync(ictx->wp);
|
||||||
|
if (ictx->wp != NULL)
|
||||||
|
ictx->wp->flags |= PANE_REDRAW;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@@ -1999,6 +2006,9 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
|||||||
case 2031:
|
case 2031:
|
||||||
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
||||||
break;
|
break;
|
||||||
|
case 2026: /* synchronized output */
|
||||||
|
screen_write_start_sync(ictx->wp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -488,9 +488,9 @@ key_bindings_init(void)
|
|||||||
"bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
"bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
||||||
|
|
||||||
/* Mouse on scrollbar. */
|
/* Mouse on scrollbar. */
|
||||||
"bind -n MouseDown1ScrollbarUp { copy-mode -u }",
|
"bind -n MouseDown1ScrollbarUp { if -Ft= '#{pane_in_mode}' { send -X page-up } {copy-mode -u } }",
|
||||||
"bind -n MouseDown1ScrollbarDown { copy-mode -d }",
|
"bind -n MouseDown1ScrollbarDown { if -Ft= '#{pane_in_mode}' { send -X page-down } {copy-mode -d } }",
|
||||||
"bind -n MouseDrag1ScrollbarSlider { copy-mode -S }",
|
"bind -n MouseDrag1ScrollbarSlider { if -Ft= '#{pane_in_mode}' { send -X scroll-to-mouse } { copy-mode -S } }",
|
||||||
|
|
||||||
/* Copy mode (emacs) keys. */
|
/* Copy mode (emacs) keys. */
|
||||||
"bind -Tcopy-mode C-Space { send -X begin-selection }",
|
"bind -Tcopy-mode C-Space { send -X begin-selection }",
|
||||||
|
|||||||
@@ -958,7 +958,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
{ .name = "prompt-cursor-colour",
|
{ .name = "prompt-cursor-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_COLOUR,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.default_num = 6,
|
.default_num = -1,
|
||||||
.text = "Colour of the cursor when in the command prompt."
|
.text = "Colour of the cursor when in the command prompt."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -224,9 +224,10 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
|
|||||||
if ((wp->xoff == 0 || (int)px >= wp->xoff) &&
|
if ((wp->xoff == 0 || (int)px >= wp->xoff) &&
|
||||||
((int)px <= ex ||
|
((int)px <= ex ||
|
||||||
(sb_w != 0 && (int)px < ex + sb_w))) {
|
(sb_w != 0 && (int)px < ex + sb_w))) {
|
||||||
if (wp->yoff != 0 && (int)py == wp->yoff - 1)
|
if (pane_status != PANE_STATUS_BOTTOM &&
|
||||||
|
wp->yoff != 0 && (int)py == wp->yoff - 1)
|
||||||
return (SCREEN_REDRAW_BORDER_TOP);
|
return (SCREEN_REDRAW_BORDER_TOP);
|
||||||
if ((int)py == ey)
|
if (pane_status != PANE_STATUS_TOP && (int)py == ey)
|
||||||
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1164,6 +1165,9 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
|||||||
struct visible_ranges *vr;
|
struct visible_ranges *vr;
|
||||||
u_int i, j, top, x, y, width, r;
|
u_int i, j, top, x, y, width, r;
|
||||||
|
|
||||||
|
if (wp->base.mode & MODE_SYNC)
|
||||||
|
screen_write_stop_sync(wp);
|
||||||
|
|
||||||
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
|
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
|
||||||
|
|
||||||
if (wp->xoff + (int)wp->sx <= ctx->ox ||
|
if (wp->xoff + (int)wp->sx <= ctx->ox ||
|
||||||
|
|||||||
@@ -894,6 +894,52 @@ screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
|
|||||||
log_debug("%s: %s", __func__, screen_mode_to_string(mode));
|
log_debug("%s: %s", __func__, screen_mode_to_string(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sync timeout callback. */
|
||||||
|
static void
|
||||||
|
screen_write_sync_callback(__unused int fd, __unused short events, void *arg)
|
||||||
|
{
|
||||||
|
struct window_pane *wp = arg;
|
||||||
|
|
||||||
|
log_debug("%s: %%%u sync timer expired", __func__, wp->id);
|
||||||
|
evtimer_del(&wp->sync_timer);
|
||||||
|
|
||||||
|
if (wp->base.mode & MODE_SYNC) {
|
||||||
|
wp->base.mode &= ~MODE_SYNC;
|
||||||
|
wp->flags |= PANE_REDRAW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start sync mode. */
|
||||||
|
void
|
||||||
|
screen_write_start_sync(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
|
||||||
|
|
||||||
|
if (wp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wp->base.mode |= MODE_SYNC;
|
||||||
|
if (!event_initialized(&wp->sync_timer))
|
||||||
|
evtimer_set(&wp->sync_timer, screen_write_sync_callback, wp);
|
||||||
|
evtimer_add(&wp->sync_timer, &tv);
|
||||||
|
|
||||||
|
log_debug("%s: %%%u started sync mode", __func__, wp->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop sync mode. */
|
||||||
|
void
|
||||||
|
screen_write_stop_sync(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
if (wp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event_initialized(&wp->sync_timer))
|
||||||
|
evtimer_del(&wp->sync_timer);
|
||||||
|
wp->base.mode &= ~MODE_SYNC;
|
||||||
|
|
||||||
|
log_debug("%s: %%%u stopped sync mode", __func__, wp->id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Cursor up by ny. */
|
/* Cursor up by ny. */
|
||||||
void
|
void
|
||||||
screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
|
screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
|
||||||
@@ -1787,6 +1833,9 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
|
|||||||
struct visible_ranges *vr;
|
struct visible_ranges *vr;
|
||||||
struct window_pane *wp = ctx->wp;
|
struct window_pane *wp = ctx->wp;
|
||||||
|
|
||||||
|
if (s->mode & MODE_SYNC)
|
||||||
|
return;
|
||||||
|
|
||||||
if (ctx->scrolled != 0) {
|
if (ctx->scrolled != 0) {
|
||||||
log_debug("%s: scrolled %u (region %u-%u)", __func__,
|
log_debug("%s: scrolled %u (region %u-%u)", __func__,
|
||||||
ctx->scrolled, s->rupper, s->rlower);
|
ctx->scrolled, s->rupper, s->rlower);
|
||||||
@@ -2134,7 +2183,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write to the screen. */
|
/* Write to the screen. */
|
||||||
if (!skip) {
|
if (!skip && !(s->mode & MODE_SYNC)) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
screen_select_cell(s, &tmp_gc, gc);
|
screen_select_cell(s, &tmp_gc, gc);
|
||||||
ttyctx.cell = &tmp_gc;
|
ttyctx.cell = &tmp_gc;
|
||||||
@@ -2372,8 +2421,11 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
|||||||
u_int x, y, sx, sy, cx = s->cx, cy = s->cy, i, lines;
|
u_int x, y, sx, sy, cx = s->cx, cy = s->cy, i, lines;
|
||||||
struct sixel_image *new;
|
struct sixel_image *new;
|
||||||
|
|
||||||
|
if (screen_size_y(s) == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
sixel_size_in_cells(si, &x, &y);
|
sixel_size_in_cells(si, &x, &y);
|
||||||
if (x > screen_size_x(s) || y > screen_size_y(s)) {
|
if (x > screen_size_x(s) || y > screen_size_y(s) - 1) {
|
||||||
if (x > screen_size_x(s) - cx)
|
if (x > screen_size_x(s) - cx)
|
||||||
sx = screen_size_x(s) - cx;
|
sx = screen_size_x(s) - cx;
|
||||||
else
|
else
|
||||||
@@ -2384,16 +2436,14 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
|||||||
sy = y;
|
sy = y;
|
||||||
new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1);
|
new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1);
|
||||||
sixel_free(si);
|
sixel_free(si);
|
||||||
si = new;
|
if (new == NULL)
|
||||||
|
|
||||||
/* Bail out if the image cannot be scaled. */
|
|
||||||
if (si == NULL)
|
|
||||||
return;
|
return;
|
||||||
sixel_size_in_cells(si, &x, &y);
|
sixel_size_in_cells(new, &x, &y);
|
||||||
|
si = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
sy = screen_size_y(s) - cy;
|
sy = screen_size_y(s) - cy;
|
||||||
if (sy < y) {
|
if (sy <= y) {
|
||||||
lines = y - sy + 1;
|
lines = y - sy + 1;
|
||||||
if (image_scroll_up(s, lines) && ctx->wp != NULL)
|
if (image_scroll_up(s, lines) && ctx->wp != NULL)
|
||||||
ctx->wp->flags |= PANE_REDRAW;
|
ctx->wp->flags |= PANE_REDRAW;
|
||||||
|
|||||||
36
spawn.c
36
spawn.c
@@ -211,7 +211,9 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
struct environ *child;
|
struct environ *child;
|
||||||
struct environ_entry *ee;
|
struct environ_entry *ee;
|
||||||
char **argv, *cp, **argvp, *argv0, *cwd, *new_cwd;
|
char **argv, *cp, **argvp, *argv0, *cwd, *new_cwd;
|
||||||
const char *cmd, *tmp;
|
char path[PATH_MAX];
|
||||||
|
const char *cmd, *tmp, *home = find_home();
|
||||||
|
const char *actual_cwd = NULL;
|
||||||
int argc;
|
int argc;
|
||||||
u_int idx;
|
u_int idx;
|
||||||
struct termios now;
|
struct termios now;
|
||||||
@@ -373,6 +375,16 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
goto complete;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store current working directory and change to new one. */
|
||||||
|
if (getcwd(path, sizeof path) != NULL) {
|
||||||
|
if (chdir(new_wp->cwd) == 0)
|
||||||
|
actual_cwd = new_wp->cwd;
|
||||||
|
else if (home != NULL && chdir(home) == 0)
|
||||||
|
actual_cwd = home;
|
||||||
|
else if (chdir("/") == 0)
|
||||||
|
actual_cwd = "/";
|
||||||
|
}
|
||||||
|
|
||||||
/* Fork the new process. */
|
/* Fork the new process. */
|
||||||
new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws);
|
new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws);
|
||||||
if (new_wp->pid == -1) {
|
if (new_wp->pid == -1) {
|
||||||
@@ -388,8 +400,15 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In the parent process, everything is done now. */
|
/*
|
||||||
|
* In the parent process, everything is done now. Change the working
|
||||||
|
* directory back.
|
||||||
|
*/
|
||||||
if (new_wp->pid != 0) {
|
if (new_wp->pid != 0) {
|
||||||
|
if (actual_cwd != NULL &&
|
||||||
|
chdir(path) != 0 &&
|
||||||
|
(home == NULL || chdir(home) != 0))
|
||||||
|
chdir("/");
|
||||||
goto complete;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,17 +423,10 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* Child process. Change to the working directory or home if that
|
* Child process. Set PWD to the working directory.
|
||||||
* fails.
|
|
||||||
*/
|
*/
|
||||||
if (chdir(new_wp->cwd) == 0)
|
if (actual_cwd != NULL)
|
||||||
environ_set(child, "PWD", 0, "%s", new_wp->cwd);
|
environ_set(child, "PWD", 0, "%s", actual_cwd);
|
||||||
else if ((tmp = find_home()) != NULL && chdir(tmp) == 0)
|
|
||||||
environ_set(child, "PWD", 0, "%s", tmp);
|
|
||||||
else if (chdir("/") == 0)
|
|
||||||
environ_set(child, "PWD", 0, "/");
|
|
||||||
else
|
|
||||||
fatal("chdir failed");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update terminal escape characters from the session if available and
|
* Update terminal escape characters from the session if available and
|
||||||
|
|||||||
21
tmux.1
21
tmux.1
@@ -1663,9 +1663,10 @@ is used,
|
|||||||
option will not be applied.
|
option will not be applied.
|
||||||
.Pp
|
.Pp
|
||||||
.Fl T
|
.Fl T
|
||||||
sets the client's key table; the next key from the client will be interpreted
|
sets the client's key table; the next key will be looked up using
|
||||||
from
|
|
||||||
.Ar key-table .
|
.Ar key-table .
|
||||||
|
After that key, the client is returned to its default key table (normally
|
||||||
|
.Em root ) .
|
||||||
This may be used to configure multiple prefix keys, or to bind commands to
|
This may be used to configure multiple prefix keys, or to bind commands to
|
||||||
sequences of keys.
|
sequences of keys.
|
||||||
For example, to make typing
|
For example, to make typing
|
||||||
@@ -2213,6 +2214,13 @@ but also exit copy mode if the cursor reaches the bottom.
|
|||||||
Scroll so that the current line becomes the middle one while keeping the
|
Scroll so that the current line becomes the middle one while keeping the
|
||||||
cursor on that line.
|
cursor on that line.
|
||||||
.It Xo
|
.It Xo
|
||||||
|
.Ic scroll-to-mouse
|
||||||
|
.Xc
|
||||||
|
Scroll pane in copy-mode when bound to a mouse drag event.
|
||||||
|
.Fl e
|
||||||
|
causes copy mode to exit when at the bottom.
|
||||||
|
.Pp
|
||||||
|
.It Xo
|
||||||
.Ic scroll-top
|
.Ic scroll-top
|
||||||
.Xc
|
.Xc
|
||||||
Scroll down until the current line is at the top while keeping the cursor on
|
Scroll down until the current line is at the top while keeping the cursor on
|
||||||
@@ -2449,12 +2457,10 @@ cancels copy mode and any other modes.
|
|||||||
.Fl M
|
.Fl M
|
||||||
begins a mouse drag (only valid if bound to a mouse key binding, see
|
begins a mouse drag (only valid if bound to a mouse key binding, see
|
||||||
.Sx MOUSE SUPPORT ) .
|
.Sx MOUSE SUPPORT ) .
|
||||||
|
.Pp
|
||||||
.Fl S
|
.Fl S
|
||||||
scrolls when bound to a mouse drag event; for example,
|
enters copy-mode and scrolls when bound to a mouse drag event; See
|
||||||
.Ic copy-mode -Se
|
.Ic scroll-to-mouse .
|
||||||
is bound to
|
|
||||||
.Ar MouseDrag1ScrollbarSlider
|
|
||||||
by default.
|
|
||||||
.Pp
|
.Pp
|
||||||
.Fl s
|
.Fl s
|
||||||
copies from
|
copies from
|
||||||
@@ -6258,6 +6264,7 @@ The following variables are available, where appropriate:
|
|||||||
.It Li "socket_path" Ta "" Ta "Server socket path"
|
.It Li "socket_path" Ta "" Ta "Server socket path"
|
||||||
.It Li "sixel_support" Ta "" Ta "1 if server has support for SIXEL"
|
.It Li "sixel_support" Ta "" Ta "1 if server has support for SIXEL"
|
||||||
.It Li "start_time" Ta "" Ta "Server start time"
|
.It Li "start_time" Ta "" Ta "Server start time"
|
||||||
|
.It Li "synchronized_output_flag" Ta "" Ta "1 if pane has synchronized output enabled"
|
||||||
.It Li "uid" Ta "" Ta "Server UID"
|
.It Li "uid" Ta "" Ta "Server UID"
|
||||||
.It Li "user" Ta "" Ta "Server user"
|
.It Li "user" Ta "" Ta "Server user"
|
||||||
.It Li "version" Ta "" Ta "Server version"
|
.It Li "version" Ta "" Ta "Server version"
|
||||||
|
|||||||
4
tmux.h
4
tmux.h
@@ -652,6 +652,7 @@ enum tty_code_code {
|
|||||||
#define MODE_CURSOR_BLINKING_SET 0x20000
|
#define MODE_CURSOR_BLINKING_SET 0x20000
|
||||||
#define MODE_KEYS_EXTENDED_2 0x40000
|
#define MODE_KEYS_EXTENDED_2 0x40000
|
||||||
#define MODE_THEME_UPDATES 0x80000
|
#define MODE_THEME_UPDATES 0x80000
|
||||||
|
#define MODE_SYNC 0x100000
|
||||||
|
|
||||||
#define ALL_MODES 0xffffff
|
#define ALL_MODES 0xffffff
|
||||||
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
|
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
|
||||||
@@ -1225,6 +1226,7 @@ struct window_pane {
|
|||||||
|
|
||||||
struct window_pane_resizes resize_queue;
|
struct window_pane_resizes resize_queue;
|
||||||
struct event resize_timer;
|
struct event resize_timer;
|
||||||
|
struct event sync_timer;
|
||||||
|
|
||||||
struct input_ctx *ictx;
|
struct input_ctx *ictx;
|
||||||
|
|
||||||
@@ -3160,6 +3162,8 @@ void screen_write_preview(struct screen_write_ctx *, struct screen *, u_int,
|
|||||||
void screen_write_backspace(struct screen_write_ctx *);
|
void screen_write_backspace(struct screen_write_ctx *);
|
||||||
void screen_write_mode_set(struct screen_write_ctx *, int);
|
void screen_write_mode_set(struct screen_write_ctx *, int);
|
||||||
void screen_write_mode_clear(struct screen_write_ctx *, int);
|
void screen_write_mode_clear(struct screen_write_ctx *, int);
|
||||||
|
void screen_write_start_sync(struct window_pane *);
|
||||||
|
void screen_write_stop_sync(struct window_pane *);
|
||||||
void screen_write_cursorup(struct screen_write_ctx *, u_int);
|
void screen_write_cursorup(struct screen_write_ctx *, u_int);
|
||||||
void screen_write_cursordown(struct screen_write_ctx *, u_int);
|
void screen_write_cursordown(struct screen_write_ctx *, u_int);
|
||||||
void screen_write_cursorright(struct screen_write_ctx *, u_int);
|
void screen_write_cursorright(struct screen_write_ctx *, u_int);
|
||||||
|
|||||||
10
tty-keys.c
10
tty-keys.c
@@ -909,10 +909,16 @@ first_key:
|
|||||||
* used. termios should have a better idea.
|
* used. termios should have a better idea.
|
||||||
*/
|
*/
|
||||||
bspace = tty->tio.c_cc[VERASE];
|
bspace = tty->tio.c_cc[VERASE];
|
||||||
if (bspace != _POSIX_VDISABLE && key == bspace) {
|
if (bspace != _POSIX_VDISABLE) {
|
||||||
log_debug("%s: key %#llx is backspace", c->name, key);
|
if (key == bspace) {
|
||||||
|
log_debug("%s: key %#llx is BSpace", c->name, key);
|
||||||
key = KEYC_BSPACE;
|
key = KEYC_BSPACE;
|
||||||
}
|
}
|
||||||
|
if (key == (bspace|KEYC_META)) {
|
||||||
|
log_debug("%s: key %#llx is M-BSpace", c->name, key);
|
||||||
|
key = KEYC_BSPACE|KEYC_META;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up all C0 control codes that don't have a dedicated key into
|
* Fix up all C0 control codes that don't have a dedicated key into
|
||||||
|
|||||||
@@ -123,6 +123,26 @@ const char window_clock_table[14][5][5] = {
|
|||||||
{ 1,0,0,0,1 } },
|
{ 1,0,0,0,1 } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_clock_start_timer(struct window_mode_entry *wme)
|
||||||
|
{
|
||||||
|
struct window_clock_mode_data *data = wme->data;
|
||||||
|
struct timeval tv;
|
||||||
|
struct timespec ts;
|
||||||
|
long delay;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
delay = 1000000 - (ts.tv_nsec / 1000);
|
||||||
|
|
||||||
|
tv.tv_sec = delay / 1000000;
|
||||||
|
tv.tv_usec = delay % 1000000;
|
||||||
|
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
}
|
||||||
|
evtimer_add(&data->timer, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
|
window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
|
||||||
{
|
{
|
||||||
@@ -131,25 +151,22 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
|
|||||||
struct window_clock_mode_data *data = wme->data;
|
struct window_clock_mode_data *data = wme->data;
|
||||||
struct tm now, then;
|
struct tm now, then;
|
||||||
time_t t;
|
time_t t;
|
||||||
struct timeval tv = { .tv_sec = 1 };
|
|
||||||
|
|
||||||
evtimer_del(&data->timer);
|
evtimer_del(&data->timer);
|
||||||
evtimer_add(&data->timer, &tv);
|
|
||||||
|
|
||||||
if (TAILQ_FIRST(&wp->modes) != wme)
|
|
||||||
return;
|
|
||||||
|
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
gmtime_r(&t, &now);
|
gmtime_r(&t, &now);
|
||||||
gmtime_r(&data->tim, &then);
|
gmtime_r(&data->tim, &then);
|
||||||
if (now.tm_sec == then.tm_sec)
|
|
||||||
return;
|
|
||||||
data->tim = t;
|
|
||||||
|
|
||||||
|
if (now.tm_sec != then.tm_sec) {
|
||||||
|
data->tim = t;
|
||||||
window_clock_draw_screen(wme);
|
window_clock_draw_screen(wme);
|
||||||
wp->flags |= PANE_REDRAW;
|
wp->flags |= PANE_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window_clock_start_timer(wme);
|
||||||
|
}
|
||||||
|
|
||||||
static struct screen *
|
static struct screen *
|
||||||
window_clock_init(struct window_mode_entry *wme,
|
window_clock_init(struct window_mode_entry *wme,
|
||||||
__unused struct cmd_find_state *fs, __unused struct args *args)
|
__unused struct cmd_find_state *fs, __unused struct args *args)
|
||||||
@@ -157,13 +174,12 @@ window_clock_init(struct window_mode_entry *wme,
|
|||||||
struct window_pane *wp = wme->wp;
|
struct window_pane *wp = wme->wp;
|
||||||
struct window_clock_mode_data *data;
|
struct window_clock_mode_data *data;
|
||||||
struct screen *s;
|
struct screen *s;
|
||||||
struct timeval tv = { .tv_sec = 1 };
|
|
||||||
|
|
||||||
wme->data = data = xmalloc(sizeof *data);
|
wme->data = data = xmalloc(sizeof *data);
|
||||||
data->tim = time(NULL);
|
data->tim = time(NULL);
|
||||||
|
|
||||||
evtimer_set(&data->timer, window_clock_timer_callback, wme);
|
evtimer_set(&data->timer, window_clock_timer_callback, wme);
|
||||||
evtimer_add(&data->timer, &tv);
|
window_clock_start_timer(wme);
|
||||||
|
|
||||||
s = &data->screen;
|
s = &data->screen;
|
||||||
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
|
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
|
||||||
|
|||||||
@@ -1479,6 +1479,20 @@ window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs)
|
|||||||
return (window_copy_cmd_scroll_to(cs, mid_value));
|
return (window_copy_cmd_scroll_to(cs, mid_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Scroll the pane to the mouse in the scrollbar. */
|
||||||
|
static enum window_copy_cmd_action
|
||||||
|
window_copy_cmd_scroll_to_mouse(struct window_copy_cmd_state *cs)
|
||||||
|
{
|
||||||
|
struct window_mode_entry *wme = cs->wme;
|
||||||
|
struct window_pane *wp = wme->wp;
|
||||||
|
struct client *c = cs->c;
|
||||||
|
struct mouse_event *m = cs->m;
|
||||||
|
int scroll_exit = args_has(cs->wargs, 'e');
|
||||||
|
|
||||||
|
window_copy_scroll(wp, c->tty.mouse_slider_mpos, m->y, scroll_exit);
|
||||||
|
return (WINDOW_COPY_CMD_NOTHING);
|
||||||
|
}
|
||||||
|
|
||||||
/* Scroll line containing the cursor to the top. */
|
/* Scroll line containing the cursor to the top. */
|
||||||
static enum window_copy_cmd_action
|
static enum window_copy_cmd_action
|
||||||
window_copy_cmd_scroll_top(struct window_copy_cmd_state *cs)
|
window_copy_cmd_scroll_top(struct window_copy_cmd_state *cs)
|
||||||
@@ -3044,6 +3058,11 @@ static const struct {
|
|||||||
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
||||||
.f = window_copy_cmd_scroll_middle
|
.f = window_copy_cmd_scroll_middle
|
||||||
},
|
},
|
||||||
|
{ .command = "scroll-to-mouse",
|
||||||
|
.args = { "e", 0, 0, NULL },
|
||||||
|
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
|
||||||
|
.f = window_copy_cmd_scroll_to_mouse
|
||||||
|
},
|
||||||
{ .command = "scroll-top",
|
{ .command = "scroll-top",
|
||||||
.args = { "", 0, 0, NULL },
|
.args = { "", 0, 0, NULL },
|
||||||
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
||||||
|
|||||||
4
window.c
4
window.c
@@ -1104,6 +1104,8 @@ window_pane_destroy(struct window_pane *wp)
|
|||||||
|
|
||||||
if (event_initialized(&wp->resize_timer))
|
if (event_initialized(&wp->resize_timer))
|
||||||
event_del(&wp->resize_timer);
|
event_del(&wp->resize_timer);
|
||||||
|
if (event_initialized(&wp->sync_timer))
|
||||||
|
event_del(&wp->sync_timer);
|
||||||
TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
|
TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
|
||||||
TAILQ_REMOVE(&wp->resize_queue, r, entry);
|
TAILQ_REMOVE(&wp->resize_queue, r, entry);
|
||||||
free(r);
|
free(r);
|
||||||
@@ -1183,6 +1185,8 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
|
|||||||
if (sx == wp->sx && sy == wp->sy)
|
if (sx == wp->sx && sy == wp->sy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
screen_write_stop_sync(wp);
|
||||||
|
|
||||||
r = xmalloc(sizeof *r);
|
r = xmalloc(sizeof *r);
|
||||||
r->sx = sx;
|
r->sx = sx;
|
||||||
r->sy = sy;
|
r->sy = sy;
|
||||||
|
|||||||
Reference in New Issue
Block a user