Merge branch 'master' into feature-floating-window-panes

This commit is contained in:
Michael Grant
2025-12-18 23:14:59 +01:00
committed by GitHub
15 changed files with 243 additions and 63 deletions

View File

@@ -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;

View File

@@ -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
View File

@@ -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
View File

@@ -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;

View File

@@ -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 }",

View File

@@ -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."
}, },

View File

@@ -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 ||

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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);

View File

@@ -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

View File

@@ -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,23 +151,20 @@ 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 *
@@ -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);

View File

@@ -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,

View File

@@ -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;