Merge branch 'obsd-master' into master

pull/2824/head
Thomas Adam 2021-08-14 01:34:54 +01:00
commit 54773d23b5
23 changed files with 682 additions and 341 deletions

View File

@ -124,17 +124,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
c->session = s;
server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
@ -156,25 +148,14 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
c->session = s;
server_client_set_session(c, s);
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED;
}
recalculate_sizes();
alerts_check_session(s);
server_update_socket();
return (CMD_RETURN_NORMAL);
}

View File

@ -40,8 +40,8 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,
.args = { "1FkiI:Np:t:T:", 0, 1 },
.usage = "[-1FkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
.args = { "1bFkiI:Np:t:T:", 0, 1 },
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
" [-T type] [template]",
.flags = CMD_CLIENT_TFLAG,
@ -49,17 +49,20 @@ const struct cmd_entry cmd_command_prompt_entry = {
};
struct cmd_command_prompt_cdata {
int flags;
enum prompt_type prompt_type;
struct cmdq_item *item;
struct cmd_parse_input pi;
char *inputs;
char *next_input;
int flags;
enum prompt_type prompt_type;
char *prompts;
char *next_prompt;
char *inputs;
char *next_input;
char *template;
int idx;
char *prompts;
char *next_prompt;
char *template;
int idx;
};
static enum cmd_retval
@ -72,21 +75,23 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_command_prompt_cdata *cdata;
char *prompt, *ptr, *input = NULL;
size_t n;
int wait = !args_has(args, 'b');
if (tc->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
cdata->inputs = NULL;
cdata->next_input = NULL;
cdata->prompts = NULL;
cdata->next_prompt = NULL;
cdata->template = NULL;
cdata->idx = 1;
cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
if (wait)
cdata->pi.item = item;
cdata->pi.c = tc;
cmd_find_copy_state(&cdata->pi.fs, target);
if (wait)
cdata->item = item;
if (args->argc != 0 && args_has(args, 'F'))
cdata->template = format_single_from_target(item, args->argv[0]);
else if (args->argc != 0)
@ -140,7 +145,9 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags, cdata->prompt_type);
free(prompt);
return (CMD_RETURN_NORMAL);
if (!wait)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static int
@ -150,12 +157,13 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
struct cmd_command_prompt_cdata *cdata = data;
char *new_template, *prompt, *ptr, *error;
char *input = NULL;
struct cmdq_item *item = cdata->item;
enum cmd_parse_status status;
if (s == NULL)
return (0);
goto out;
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
goto out;
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
if (done) {
@ -177,7 +185,13 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
return (1);
}
status = cmd_parse_and_append(new_template, NULL, c, NULL, &error);
if (item != NULL) {
status = cmd_parse_and_insert(new_template, &cdata->pi, item,
cmdq_get_state(item), &error);
} else {
status = cmd_parse_and_append(new_template, &cdata->pi, c, NULL,
&error);
}
if (status == CMD_PARSE_ERROR) {
cmdq_append(c, cmdq_get_error(error));
free(error);
@ -187,6 +201,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
free(new_template);
if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1);
out:
if (item != NULL)
cmdq_continue(item);
return (0);
}

View File

@ -75,7 +75,6 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
memset(&cdata->pi, 0, sizeof cdata->pi);
cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
if (wait)
cdata->pi.item = item;
@ -88,8 +87,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
status_prompt_set(tc, target, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE, PROMPT_TYPE_COMMAND);
free(new_prompt);
if (!wait)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
@ -104,14 +103,16 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
char *error;
struct cmdq_item *item = cdata->item;
enum cmd_parse_status status;
int retcode = 1;
if (c->flags & CLIENT_DEAD)
return (0);
goto out;
if (s == NULL || *s == '\0')
goto out;
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
goto out;
retcode = 0;
if (item != NULL) {
status = cmd_parse_and_insert(cmd, &cdata->pi, item,
@ -124,8 +125,12 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
}
out:
if (item != NULL)
cmdq_continue(item);
if (item != NULL) {
if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
return (0);
}

View File

@ -50,8 +50,8 @@ const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Cc:d:Eh:t:w:x:y:", 0, -1 },
.usage = "[-CE] [-c target-client] [-d start-directory] [-h height] "
.args = { "BCc:d:Eh:t:w:x:y:", 0, -1 },
.usage = "[-BCE] [-c target-client] [-d start-directory] [-h height] "
CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [command]",
@ -390,6 +390,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
flags |= POPUP_CLOSEEXITZERO;
else if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (args_has(args, 'B'))
flags |= POPUP_NOBORDER;
if (popup_display(flags, item, px, py, w, h, shellcmd, argc, argv, cwd,
tc, s, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);

View File

@ -186,7 +186,8 @@ out:
}
static void
cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
cmd_display_panes_draw(struct client *c, __unused void *data,
struct screen_redraw_ctx *ctx)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
@ -200,9 +201,9 @@ cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
}
static void
cmd_display_panes_free(struct client *c)
cmd_display_panes_free(__unused struct client *c, void *data)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
struct cmd_display_panes_data *cdata = data;
if (cdata->item != NULL)
cmdq_continue(cdata->item);
@ -211,9 +212,9 @@ cmd_display_panes_free(struct client *c)
}
static int
cmd_display_panes_key(struct client *c, struct key_event *event)
cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
struct cmd_display_panes_data *cdata = data;
char *cmd, *expanded, *error;
struct window *w = c->session->curw->window;
struct window_pane *wp;

View File

@ -104,8 +104,6 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
if (!args_has(args, 'b'))
cdata->client = cmdq_get_client(item);
@ -116,10 +114,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
else
cdata->item = NULL;
memset(&cdata->input, 0, sizeof cdata->input);
cmd_get_source(self, &file, &cdata->input.line);
if (file != NULL)
cdata->input.file = xstrdup(file);

View File

@ -329,18 +329,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
}
recalculate_sizes();
server_update_socket();
/*
* If there are still configuration file errors to display, put the new

View File

@ -121,7 +121,6 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->shell = !args_has(args, 'C');
if (!cdata->shell) {
memset(&cdata->pi, 0, sizeof cdata->pi);
cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
if (wait)
cdata->pi.item = item;

View File

@ -134,23 +134,9 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'E'))
environ_update(s->options, tc->environ, s->environ);
if (tc->session != NULL && tc->session != s)
tc->last_session = tc->session;
tc->session = s;
server_client_set_session(tc, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(tc, NULL);
tty_update_client_offset(tc);
status_timer_start(tc);
notify_client("client-session-changed", tc);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_check_unattached();
server_redraw_client(tc);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = tc;
recalculate_sizes();
alerts_check_session(s);
return (CMD_RETURN_NORMAL);
}

View File

@ -1792,8 +1792,12 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
if (sctx->s->mode & MODE_FOCUSON)
break;
screen_write_mode_set(sctx, MODE_FOCUSON);
if (wp != NULL)
wp->flags |= PANE_FOCUSPUSH; /* force update */
if (wp == NULL)
break;
if (wp->flags & PANE_FOCUSED)
bufferevent_write(wp->event, "\033[I", 3);
else
bufferevent_write(wp->event, "\033[O", 3);
break;
case 1005:
screen_write_mode_set(sctx, MODE_MOUSE_UTF8);

32
job.c
View File

@ -50,6 +50,7 @@ struct job {
char *cmd;
pid_t pid;
char tty[TTY_NAME_MAX];
int status;
int fd;
@ -79,7 +80,7 @@ job_run(const char *cmd, int argc, char **argv, struct session *s,
const char *home;
sigset_t set, oldset;
struct winsize ws;
char **argvp;
char **argvp, tty[TTY_NAME_MAX];
/*
* Do not set TERM during .tmux.conf, it is nice to be able to use
@ -94,7 +95,7 @@ job_run(const char *cmd, int argc, char **argv, struct session *s,
memset(&ws, 0, sizeof ws);
ws.ws_col = sx;
ws.ws_row = sy;
pid = fdforkpty(ptm_fd, &master, NULL, NULL, &ws);
pid = fdforkpty(ptm_fd, &master, tty, NULL, &ws);
} else {
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
goto fail;
@ -168,6 +169,7 @@ job_run(const char *cmd, int argc, char **argv, struct session *s,
else
job->cmd = cmd_stringify_argv(argc, argv);
job->pid = pid;
strlcpy(job->tty, tty, sizeof job->tty);
job->status = 0;
LIST_INSERT_HEAD(&all_jobs, job, entry);
@ -199,6 +201,32 @@ fail:
return (NULL);
}
/* Take job's file descriptor and free the job. */
int
job_transfer(struct job *job, pid_t *pid, char *tty, size_t ttylen)
{
int fd = job->fd;
log_debug("transfer job %p: %s", job, job->cmd);
if (pid != NULL)
*pid = job->pid;
if (tty != NULL)
strlcpy(tty, job->tty, ttylen);
LIST_REMOVE(job, entry);
free(job->cmd);
if (job->freecb != NULL && job->data != NULL)
job->freecb(job->data);
if (job->event != NULL)
bufferevent_free(job->event);
free(job);
return (fd);
}
/* Kill and free an individual job. */
void
job_free(struct job *job)

57
menu.c
View File

@ -131,18 +131,33 @@ menu_free(struct menu *menu)
free(menu);
}
static struct screen *
menu_mode_cb(struct client *c, __unused u_int *cx, __unused u_int *cy)
struct screen *
menu_mode_cb(__unused struct client *c, void *data, __unused u_int *cx,
__unused u_int *cy)
{
struct menu_data *md = c->overlay_data;
struct menu_data *md = data;
return (&md->s);
}
static void
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
int
menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py)
{
struct menu_data *md = c->overlay_data;
struct menu_data *md = data;
struct menu *menu = md->menu;
if (px < md->px || px > md->px + menu->width + 3)
return (1);
if (py < md->py || py > md->py + menu->count + 1)
return (1);
return (0);
}
void
menu_draw_cb(struct client *c, void *data,
__unused struct screen_redraw_ctx *rctx)
{
struct menu_data *md = data;
struct tty *tty = &c->tty;
struct screen *s = &md->s;
struct menu *menu = md->menu;
@ -163,10 +178,10 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
}
}
static void
menu_free_cb(struct client *c)
void
menu_free_cb(__unused struct client *c, void *data)
{
struct menu_data *md = c->overlay_data;
struct menu_data *md = data;
if (md->item != NULL)
cmdq_continue(md->item);
@ -179,10 +194,10 @@ menu_free_cb(struct client *c)
free(md);
}
static int
menu_key_cb(struct client *c, struct key_event *event)
int
menu_key_cb(struct client *c, void *data, struct key_event *event)
{
struct menu_data *md = c->overlay_data;
struct menu_data *md = data;
struct menu *menu = md->menu;
struct mouse_event *m = &event->m;
u_int i;
@ -342,8 +357,8 @@ chosen:
return (1);
}
int
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
struct menu_data *
menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
void *data)
{
@ -352,7 +367,7 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
const char *name;
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
return (-1);
return (NULL);
if (px + menu->width + 4 > c->tty.sx)
px = c->tty.sx - menu->width - 4;
if (py + menu->count + 2 > c->tty.sy)
@ -388,7 +403,19 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
md->cb = cb;
md->data = data;
return (md);
}
int
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
void *data)
{
struct menu_data *md;
md = menu_prepare(menu, flags, item, px, py, c, fs, cb, data);
if (md == NULL)
return (-1);
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
menu_key_cb, menu_free_cb, NULL, md);
return (0);

305
popup.c
View File

@ -39,6 +39,10 @@ struct popup_data {
popup_close_cb cb;
void *arg;
struct menu *menu;
struct menu_data *md;
int close;
/* Current position and size. */
u_int px;
u_int py;
@ -66,6 +70,28 @@ struct popup_editor {
void *arg;
};
static const struct menu_item popup_menu_items[] = {
{ "Close", 'q', NULL },
{ "#{?buffer_name,Paste #[underscore]#{buffer_name},}", 'p', NULL },
{ "", KEYC_NONE, NULL },
{ "Fill Space", 'F', NULL },
{ "Centre", 'C', NULL },
{ "", KEYC_NONE, NULL },
{ "To Horizontal Pane", 'h', NULL },
{ "To Vertical Pane", 'v', NULL },
{ NULL, KEYC_NONE, NULL }
};
static const struct menu_item popup_internal_menu_items[] = {
{ "Close", 'q', NULL },
{ "", KEYC_NONE, NULL },
{ "Fill Space", 'F', NULL },
{ "Centre", 'C', NULL },
{ NULL, KEYC_NONE, NULL }
};
static void
popup_redraw_cb(const struct tty_ctx *ttyctx)
{
@ -90,8 +116,13 @@ popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
ttyctx->wsx = c->tty.sx;
ttyctx->wsy = c->tty.sy;
ttyctx->xoff = ttyctx->rxoff = pd->px + 1;
ttyctx->yoff = ttyctx->ryoff = pd->py + 1;
if (pd->flags & POPUP_NOBORDER) {
ttyctx->xoff = ttyctx->rxoff = pd->px;
ttyctx->yoff = ttyctx->ryoff = pd->py;
} else {
ttyctx->xoff = ttyctx->rxoff = pd->px + 1;
ttyctx->yoff = ttyctx->ryoff = pd->py + 1;
}
return (1);
}
@ -108,20 +139,30 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
}
static struct screen *
popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
*cx = pd->px + 1 + pd->s.cx;
*cy = pd->py + 1 + pd->s.cy;
if (pd->md != NULL)
return (menu_mode_cb(c, pd->md, cx, cy));
if (pd->flags & POPUP_NOBORDER) {
*cx = pd->px + pd->s.cx;
*cy = pd->py + pd->s.cy;
} else {
*cx = pd->px + 1 + pd->s.cx;
*cy = pd->py + 1 + pd->s.cy;
}
return (&pd->s);
}
static int
popup_check_cb(struct client *c, u_int px, u_int py)
popup_check_cb(struct client *c, void *data, u_int px, u_int py)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
if (pd->md != NULL && menu_check_cb(c, pd->md, px, py) == 0)
return (0);
if (px < pd->px || px > pd->px + pd->sx - 1)
return (1);
if (py < pd->py || py > pd->py + pd->sy - 1)
@ -130,9 +171,9 @@ popup_check_cb(struct client *c, u_int px, u_int py)
}
static void
popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
struct tty *tty = &c->tty;
struct screen s;
struct screen_write_ctx ctx;
@ -144,8 +185,10 @@ popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
screen_write_start(&ctx, &s);
screen_write_clearscreen(&ctx, 8);
/* Skip drawing popup if the terminal is too small. */
if (pd->sx > 2 && pd->sy > 2) {
if (pd->flags & POPUP_NOBORDER) {
screen_write_cursormove(&ctx, 0, 0, 0);
screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx, pd->sy);
} else if (pd->sx > 2 && pd->sy > 2) {
screen_write_box(&ctx, pd->sx, pd->sy);
screen_write_cursormove(&ctx, 1, 1, 0);
screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2,
@ -157,18 +200,33 @@ popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
gc.fg = pd->palette.fg;
gc.bg = pd->palette.bg;
c->overlay_check = NULL;
if (pd->md != NULL) {
c->overlay_check = menu_check_cb;
c->overlay_data = pd->md;
} else {
c->overlay_check = NULL;
c->overlay_data = NULL;
}
for (i = 0; i < pd->sy; i++)
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette);
if (pd->md != NULL) {
c->overlay_check = NULL;
c->overlay_data = NULL;
menu_draw_cb(c, pd->md, rctx);
}
c->overlay_check = popup_check_cb;
c->overlay_data = pd;
}
static void
popup_free_cb(struct client *c)
popup_free_cb(struct client *c, void *data)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
struct cmdq_item *item = pd->item;
if (pd->md != NULL)
menu_free_cb(c, pd->md);
if (pd->cb != NULL)
pd->cb(pd->status, pd->arg);
@ -186,17 +244,20 @@ popup_free_cb(struct client *c)
screen_free(&pd->s);
colour_palette_free(&pd->palette);
free(pd);
}
static void
popup_resize_cb(struct client *c)
popup_resize_cb(__unused struct client *c, void *data)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
struct tty *tty = &c->tty;
if (pd == NULL)
return;
if (pd->md != NULL)
menu_free_cb(c, pd->md);
/* Adjust position and size. */
if (pd->psy > tty->sy)
@ -217,13 +278,103 @@ popup_resize_cb(struct client *c)
pd->px = pd->ppx;
/* Avoid zero size screens. */
if (pd->sx > 2 && pd->sy > 2) {
if (pd->flags & POPUP_NOBORDER) {
screen_resize(&pd->s, pd->sx, pd->sy, 0);
if (pd->job != NULL)
job_resize(pd->job, pd->sx, pd->sy );
} else if (pd->sx > 2 && pd->sy > 2) {
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
if (pd->job != NULL)
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
}
}
static void
popup_make_pane(struct popup_data *pd, enum layout_type type)
{
struct client *c = pd->c;
struct session *s = c->session;
struct window *w = s->curw->window;
struct layout_cell *lc;
struct window_pane *wp = w->active, *new_wp;
u_int hlimit;
const char *shell;
window_unzoom(w);
lc = layout_split_pane(wp, type, -1, 0);
hlimit = options_get_number(s->options, "history-limit");
new_wp = window_add_pane(wp->window, NULL, hlimit, 0);
layout_assign_pane(lc, new_wp, 0);
new_wp->fd = job_transfer(pd->job, &new_wp->pid, new_wp->tty,
sizeof new_wp->tty);
pd->job = NULL;
screen_set_title(&pd->s, new_wp->base.title);
screen_free(&new_wp->base);
memcpy(&new_wp->base, &pd->s, sizeof wp->base);
screen_resize(&new_wp->base, new_wp->sx, new_wp->sy, 1);
screen_init(&pd->s, 1, 1, 0);
shell = options_get_string(s->options, "default-shell");
if (!checkshell(shell))
shell = _PATH_BSHELL;
new_wp->shell = xstrdup(shell);
window_pane_set_event(new_wp);
window_set_active_pane(w, new_wp, 1);
new_wp->flags |= PANE_CHANGED;
pd->close = 1;
}
static void
popup_menu_done(__unused struct menu *menu, __unused u_int choice,
key_code key, void *data)
{
struct popup_data *pd = data;
struct client *c = pd->c;
struct paste_buffer *pb;
const char *buf;
size_t len;
pd->md = NULL;
pd->menu = NULL;
server_redraw_client(pd->c);
switch (key) {
case 'p':
pb = paste_get_top(NULL);
if (pb != NULL) {
buf = paste_buffer_data(pb, &len);
bufferevent_write(job_get_event(pd->job), buf, len);
}
break;
case 'F':
pd->sx = c->tty.sx;
pd->sy = c->tty.sy;
pd->px = 0;
pd->py = 0;
server_redraw_client(c);
break;
case 'C':
pd->px = c->tty.sx / 2 - pd->sx / 2;
pd->py = c->tty.sy / 2 - pd->sy / 2;
server_redraw_client(c);
break;
case 'h':
popup_make_pane(pd, LAYOUT_LEFTRIGHT);
break;
case 'v':
popup_make_pane(pd, LAYOUT_TOPBOTTOM);
break;
case 'q':
pd->close = 1;
break;
}
}
static void
popup_handle_drag(struct client *c, struct popup_data *pd,
struct mouse_event *m)
@ -253,29 +404,55 @@ popup_handle_drag(struct client *c, struct popup_data *pd,
pd->ppy = py;
server_redraw_client(c);
} else if (pd->dragging == SIZE) {
if (m->x < pd->px + 3)
return;
if (m->y < pd->py + 3)
return;
if (pd->flags & POPUP_NOBORDER) {
if (m->x < pd->px + 1)
return;
if (m->y < pd->py + 1)
return;
} else {
if (m->x < pd->px + 3)
return;
if (m->y < pd->py + 3)
return;
}
pd->sx = m->x - pd->px;
pd->sy = m->y - pd->py;
pd->psx = pd->sx;
pd->psy = pd->sy;
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
if (pd->job != NULL)
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
if (pd->flags & POPUP_NOBORDER) {
screen_resize(&pd->s, pd->sx, pd->sy, 0);
if (pd->job != NULL)
job_resize(pd->job, pd->sx, pd->sy);
} else {
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
if (pd->job != NULL)
job_resize(pd->job, pd->sx - 2, pd->sy - 2);
}
server_redraw_client(c);
}
}
static int
popup_key_cb(struct client *c, struct key_event *event)
popup_key_cb(struct client *c, void *data, struct key_event *event)
{
struct popup_data *pd = c->overlay_data;
struct popup_data *pd = data;
struct mouse_event *m = &event->m;
const char *buf;
size_t len;
u_int px, py, x;
if (pd->md != NULL) {
if (menu_key_cb(c, pd->md, event) == 1) {
pd->md = NULL;
pd->menu = NULL;
if (pd->close)
server_client_clear_overlay(c);
else
server_redraw_client(c);
}
return (0);
}
if (KEYC_IS_MOUSE(event->key)) {
if (pd->dragging != OFF) {
@ -286,15 +463,24 @@ popup_key_cb(struct client *c, struct key_event *event)
m->x > pd->px + pd->sx - 1 ||
m->y < pd->py ||
m->y > pd->py + pd->sy - 1) {
if (MOUSE_BUTTONS (m->b) == 1)
return (1);
if (MOUSE_BUTTONS(m->b) == 2)
goto menu;
return (0);
}
if ((m->b & MOUSE_MASK_META) ||
m->x == pd->px ||
if ((~pd->flags & POPUP_NOBORDER) &&
(~m->b & MOUSE_MASK_META) &&
MOUSE_BUTTONS(m->b) == 2 &&
(m->x == pd->px ||
m->x == pd->px + pd->sx - 1 ||
m->y == pd->py ||
m->y == pd->py + pd->sy - 1) {
m->y == pd->py + pd->sy - 1))
goto menu;
if ((m->b & MOUSE_MASK_META) ||
((~pd->flags & POPUP_NOBORDER) &&
(m->x == pd->px ||
m->x == pd->px + pd->sx - 1 ||
m->y == pd->py ||
m->y == pd->py + pd->sy - 1))) {
if (!MOUSE_DRAG(m->b))
goto out;
if (MOUSE_BUTTONS(m->lb) == 0)
@ -306,7 +492,6 @@ popup_key_cb(struct client *c, struct key_event *event)
goto out;
}
}
if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
pd->job == NULL) &&
(event->key == '\033' || event->key == '\003'))
@ -314,8 +499,14 @@ popup_key_cb(struct client *c, struct key_event *event)
if (pd->job != NULL) {
if (KEYC_IS_MOUSE(event->key)) {
/* Must be inside, checked already. */
if (!input_key_get_mouse(&pd->s, m, m->x - pd->px - 1,
m->y - pd->py - 1, &buf, &len))
if (pd->flags & POPUP_NOBORDER) {
px = m->x - pd->px;
py = m->y - pd->py;
} else {
px = m->x - pd->px - 1;
py = m->y - pd->py - 1;
}
if (!input_key_get_mouse(&pd->s, m, px, py, &buf, &len))
return (0);
bufferevent_write(job_get_event(pd->job), buf, len);
return (0);
@ -324,6 +515,21 @@ popup_key_cb(struct client *c, struct key_event *event)
}
return (0);
menu:
pd->menu = menu_create("");
if (pd->flags & POPUP_INTERNAL) {
menu_add_items(pd->menu, popup_internal_menu_items, NULL, NULL,
NULL);
} else
menu_add_items(pd->menu, popup_menu_items, NULL, NULL, NULL);
if (m->x >= (pd->menu->width + 4) / 2)
x = m->x - (pd->menu->width + 4) / 2;
else
x = 0;
pd->md = menu_prepare(pd->menu, 0, NULL, x, m->y, c, NULL,
popup_menu_done, pd);
c->flags |= CLIENT_REDRAWOVERLAY;
out:
pd->lx = m->x;
pd->ly = m->y;
@ -344,9 +550,16 @@ popup_job_update_cb(struct job *job)
if (size == 0)
return;
c->overlay_check = NULL;
if (pd->md != NULL) {
c->overlay_check = menu_check_cb;
c->overlay_data = pd->md;
} else {
c->overlay_check = NULL;
c->overlay_data = NULL;
}
input_parse_screen(pd->ictx, s, popup_init_ctx_cb, pd, data, size);
c->overlay_check = popup_check_cb;
c->overlay_data = pd;
evbuffer_drain(evb, size);
}
@ -377,9 +590,19 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
struct client *c, struct session *s, popup_close_cb cb, void *arg)
{
struct popup_data *pd;
u_int jx, jy;
if (sx < 3 || sy < 3)
return (-1);
if (flags & POPUP_NOBORDER) {
if (sx < 1 || sy < 1)
return (-1);
jx = sx;
jy = sy;
} else {
if (sx < 3 || sy < 3)
return (-1);
jx = sx - 2;
jy = sy - 2;
}
if (c->tty.sx < sx || c->tty.sy < sy)
return (-1);
@ -410,7 +633,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
pd->job = job_run(shellcmd, argc, argv, s, cwd,
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, pd->sx - 2, pd->sy - 2);
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, jx, jy);
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
@ -497,8 +720,8 @@ popup_editor(struct client *c, const char *buf, size_t len,
py = (c->tty.sy / 2) - (sy / 2);
xasprintf(&cmd, "%s %s", editor, path);
if (popup_display(POPUP_CLOSEEXIT, NULL, px, py, sx, sy, cmd, 0, NULL,
_PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) {
if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, NULL, px, py, sx, sy,
cmd, 0, NULL, _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) {
popup_editor_free(pe);
free(cmd);
return (-1);

View File

@ -624,7 +624,7 @@ screen_redraw_screen(struct client *c)
}
if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
log_debug("%s: redrawing overlay", c->name);
c->overlay_draw(c, &ctx);
c->overlay_draw(c, c->overlay_data, &ctx);
}
tty_reset(&c->tty);
@ -690,7 +690,8 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
struct grid_cell gc;
const struct grid_cell *tmp;
if (c->overlay_check != NULL && !c->overlay_check(c, x, y))
if (c->overlay_check != NULL &&
!c->overlay_check(c, c->overlay_data, x, y))
return;
cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);

View File

@ -30,7 +30,6 @@
#include "tmux.h"
static void server_client_free(int, short, void *);
static void server_client_check_pane_focus(struct window_pane *);
static void server_client_check_pane_resize(struct window_pane *);
static void server_client_check_pane_buffer(struct window_pane *);
static void server_client_check_window_resize(struct window *);
@ -132,7 +131,7 @@ server_client_clear_overlay(struct client *c)
evtimer_del(&c->overlay_timer);
if (c->overlay_free != NULL)
c->overlay_free(c);
c->overlay_free(c, c->overlay_data);
c->overlay_check = NULL;
c->overlay_mode = NULL;
@ -298,9 +297,8 @@ server_client_attached_lost(struct client *c)
s = loop->session;
if (loop == c || s == NULL || s->curw->window != w)
continue;
if (found == NULL ||
timercmp(&loop->activity_time, &found->activity_time,
>))
if (found == NULL || timercmp(&loop->activity_time,
&found->activity_time, >))
found = loop;
}
if (found != NULL)
@ -308,6 +306,40 @@ server_client_attached_lost(struct client *c)
}
}
/* Set client session. */
void
server_client_set_session(struct client *c, struct session *s)
{
struct session *old = c->session;
if (s != NULL && c->session != NULL && c->session != s)
c->last_session = c->session;
else if (s == NULL)
c->last_session = NULL;
c->session = s;
c->flags |= CLIENT_FOCUSED;
recalculate_sizes();
if (old != NULL && old->curw != NULL)
window_update_focus(old->curw->window);
if (s != NULL) {
window_update_focus(s->curw->window);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
alerts_check_session(s);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
server_redraw_client(c);
}
server_check_unattached();
server_update_socket();
}
/* Lost a client. */
void
server_client_lost(struct client *c)
@ -1355,7 +1387,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
status_message_clear(c);
}
if (c->overlay_key != NULL) {
switch (c->overlay_key(c, event)) {
switch (c->overlay_key(c, c->overlay_data, event)) {
case 0:
return (0);
case 1:
@ -1386,7 +1418,6 @@ server_client_loop(void)
struct client *c;
struct window *w;
struct window_pane *wp;
int focus;
/* Check for window resize. This is done before redrawing. */
RB_FOREACH(w, windows, &windows)
@ -1404,14 +1435,11 @@ server_client_loop(void)
/*
* Any windows will have been redrawn as part of clients, so clear
* their flags now. Also check pane focus and resize.
* their flags now.
*/
focus = options_get_number(global_options, "focus-events");
RB_FOREACH(w, windows, &windows) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) {
if (focus)
server_client_check_pane_focus(wp);
server_client_check_pane_resize(wp);
server_client_check_pane_buffer(wp);
}
@ -1612,54 +1640,6 @@ out:
bufferevent_enable(wp->event, EV_READ);
}
/* Check whether pane should be focused. */
static void
server_client_check_pane_focus(struct window_pane *wp)
{
struct client *c;
int push;
/* Do we need to push the focus state? */
push = wp->flags & PANE_FOCUSPUSH;
wp->flags &= ~PANE_FOCUSPUSH;
/* If we're not the active pane in our window, we're not focused. */
if (wp->window->active != wp)
goto not_focused;
/*
* If our window is the current window in any focused clients with an
* attached session, we're focused.
*/
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || !(c->flags & CLIENT_FOCUSED))
continue;
if (c->session->attached == 0)
continue;
if (c->session->curw->window == wp->window)
goto focused;
}
not_focused:
if (push || (wp->flags & PANE_FOCUSED)) {
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[O", 3);
notify_pane("pane-focus-out", wp);
}
wp->flags &= ~PANE_FOCUSED;
return;
focused:
if (push || !(wp->flags & PANE_FOCUSED)) {
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3);
notify_pane("pane-focus-in", wp);
session_update_activity(c->session, NULL);
}
wp->flags |= PANE_FOCUSED;
}
/*
* Update cursor position and mode settings. The scroll region and attributes
* are cleared when idle (waiting for an event) as this is the most likely time
@ -1690,7 +1670,7 @@ server_client_reset_state(struct client *c)
/* Get mode from overlay if any, else from screen. */
if (c->overlay_draw != NULL) {
if (c->overlay_mode != NULL)
s = c->overlay_mode(c, &cx, &cy);
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
} else
s = wp->screen;
if (s != NULL)
@ -2067,7 +2047,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
if (c->overlay_resize == NULL)
server_client_clear_overlay(c);
else
c->overlay_resize(c);
c->overlay_resize(c, c->overlay_data);
server_redraw_client(c);
if (c->session != NULL)
notify_client("client-resized", c);
@ -2075,7 +2055,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
c->session = NULL;
server_client_set_session(c, NULL);
tty_close(&c->tty);
proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
break;

View File

@ -446,21 +446,9 @@ server_destroy_session(struct session *s)
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
if (s_new == NULL) {
c->session = NULL;
server_client_set_session(c, NULL);
if (s_new == NULL)
c->flags |= CLIENT_EXIT;
} else {
c->last_session = NULL;
c->session = s_new;
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s_new, NULL);
gettimeofday(&s_new->last_attached_time, NULL);
server_redraw_client(c);
alerts_check_session(s_new);
}
}
recalculate_sizes();
}

View File

@ -487,6 +487,8 @@ session_last(struct session *s)
int
session_set_current(struct session *s, struct winlink *wl)
{
struct winlink *old = s->curw;
if (wl == NULL)
return (-1);
if (wl == s->curw)
@ -495,6 +497,10 @@ session_set_current(struct session *s, struct winlink *wl)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
if (options_get_number(global_options, "focus-events")) {
window_update_focus(old->window);
window_update_focus(wl->window);
}
winlink_clear_flags(wl);
window_update_activity(wl->window);
tty_update_window_offset(wl->window);

114
tmux-protocol.h Normal file
View File

@ -0,0 +1,114 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 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 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.
*/
#ifndef TMUX_PROTOCOL_H
#define TMUX_PROTOCOL_H
/* Protocol version. */
#define PROTOCOL_VERSION 8
/* Message types. */
enum msgtype {
MSG_VERSION = 12,
MSG_IDENTIFY_FLAGS = 100,
MSG_IDENTIFY_TERM,
MSG_IDENTIFY_TTYNAME,
MSG_IDENTIFY_OLDCWD, /* unused */
MSG_IDENTIFY_STDIN,
MSG_IDENTIFY_ENVIRON,
MSG_IDENTIFY_DONE,
MSG_IDENTIFY_CLIENTPID,
MSG_IDENTIFY_CWD,
MSG_IDENTIFY_FEATURES,
MSG_IDENTIFY_STDOUT,
MSG_IDENTIFY_LONGFLAGS,
MSG_IDENTIFY_TERMINFO,
MSG_COMMAND = 200,
MSG_DETACH,
MSG_DETACHKILL,
MSG_EXIT,
MSG_EXITED,
MSG_EXITING,
MSG_LOCK,
MSG_READY,
MSG_RESIZE,
MSG_SHELL,
MSG_SHUTDOWN,
MSG_OLDSTDERR, /* unused */
MSG_OLDSTDIN, /* unused */
MSG_OLDSTDOUT, /* unused */
MSG_SUSPEND,
MSG_UNLOCK,
MSG_WAKEUP,
MSG_EXEC,
MSG_FLAGS,
MSG_READ_OPEN = 300,
MSG_READ,
MSG_READ_DONE,
MSG_WRITE_OPEN,
MSG_WRITE,
MSG_WRITE_READY,
MSG_WRITE_CLOSE
};
/*
* Message data.
*
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_command {
int argc;
}; /* followed by packed argv */
struct msg_read_open {
int stream;
int fd;
}; /* followed by path */
struct msg_read_data {
int stream;
};
struct msg_read_done {
int stream;
int error;
};
struct msg_write_open {
int stream;
int fd;
int flags;
}; /* followed by path */
struct msg_write_data {
int stream;
}; /* followed by data */
struct msg_write_ready {
int stream;
int error;
};
struct msg_write_close {
int stream;
};
#endif /* TMUX_PROTOCOL_H */

14
tmux.1
View File

@ -5414,7 +5414,7 @@ See
for possible values for
.Ar prompt-type .
.It Xo Ic command-prompt
.Op Fl 1FikN
.Op Fl 1bFikN
.Op Fl I Ar inputs
.Op Fl p Ar prompts
.Op Fl t Ar target-client
@ -5517,6 +5517,11 @@ option:
.It Li "Move cursor to start" Ta "0" Ta "C-a"
.It Li "Transpose characters" Ta "" Ta "C-t"
.El
.Pp
With
.Fl b ,
the prompt is shown in the background and the invoking client does not exit
until it is dismissed.
.It Xo Ic confirm-before
.Op Fl b
.Op Fl p Ar prompt
@ -5537,7 +5542,8 @@ It may contain the special character sequences supported by the
option.
With
.Fl b ,
the prompt is shown in the background and the client.
the prompt is shown in the background and the invoking client does not exit
until it is dismissed.
.It Xo Ic display-menu
.Op Fl O
.Op Fl c Ar target-client
@ -5671,7 +5677,7 @@ lists the format variables and their values.
forwards any input read from stdin to the empty pane given by
.Ar target-pane .
.It Xo Ic display-popup
.Op Fl CE
.Op Fl BCE
.Op Fl c Ar target-client
.Op Fl d Ar start-directory
.Op Fl h Ar height
@ -5711,6 +5717,8 @@ and
give the width and height - both may be a percentage (followed by
.Ql % ) .
If omitted, half of the terminal size is used.
.Fl B
does not surround the popup by a border.
.Pp
The
.Fl C

143
tmux.h
View File

@ -32,6 +32,7 @@
#endif
#include "compat.h"
#include "tmux-protocol.h"
#include "xmalloc.h"
extern char **environ;
@ -51,6 +52,7 @@ struct format_job_tree;
struct format_tree;
struct input_ctx;
struct job;
struct menu_data;
struct mode_tree_data;
struct mouse_event;
struct options;
@ -61,13 +63,12 @@ struct screen_write_cline;
struct screen_write_ctx;
struct session;
struct tty_ctx;
struct tty_code;
struct tty_key;
struct tmuxpeer;
struct tmuxproc;
struct winlink;
/* Client-server protocol version. */
#define PROTOCOL_VERSION 8
/* Default configuration files and socket paths. */
#ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf:~/.tmux.conf"
@ -505,95 +506,6 @@ enum tty_code_code {
TTYC_XT
};
/* Message codes. */
enum msgtype {
MSG_VERSION = 12,
MSG_IDENTIFY_FLAGS = 100,
MSG_IDENTIFY_TERM,
MSG_IDENTIFY_TTYNAME,
MSG_IDENTIFY_OLDCWD, /* unused */
MSG_IDENTIFY_STDIN,
MSG_IDENTIFY_ENVIRON,
MSG_IDENTIFY_DONE,
MSG_IDENTIFY_CLIENTPID,
MSG_IDENTIFY_CWD,
MSG_IDENTIFY_FEATURES,
MSG_IDENTIFY_STDOUT,
MSG_IDENTIFY_LONGFLAGS,
MSG_IDENTIFY_TERMINFO,
MSG_COMMAND = 200,
MSG_DETACH,
MSG_DETACHKILL,
MSG_EXIT,
MSG_EXITED,
MSG_EXITING,
MSG_LOCK,
MSG_READY,
MSG_RESIZE,
MSG_SHELL,
MSG_SHUTDOWN,
MSG_OLDSTDERR, /* unused */
MSG_OLDSTDIN, /* unused */
MSG_OLDSTDOUT, /* unused */
MSG_SUSPEND,
MSG_UNLOCK,
MSG_WAKEUP,
MSG_EXEC,
MSG_FLAGS,
MSG_READ_OPEN = 300,
MSG_READ,
MSG_READ_DONE,
MSG_WRITE_OPEN,
MSG_WRITE,
MSG_WRITE_READY,
MSG_WRITE_CLOSE
};
/*
* Message data.
*
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_command {
int argc;
}; /* followed by packed argv */
struct msg_read_open {
int stream;
int fd;
}; /* followed by path */
struct msg_read_data {
int stream;
};
struct msg_read_done {
int stream;
int error;
};
struct msg_write_open {
int stream;
int fd;
int flags;
}; /* followed by path */
struct msg_write_data {
int stream;
}; /* followed by data */
struct msg_write_ready {
int stream;
int error;
};
struct msg_write_close {
int stream;
};
/* Character classes. */
#define WHITESPACE " "
@ -1005,7 +917,7 @@ struct window_pane {
#define PANE_FOCUSED 0x4
/* 0x8 unused */
/* 0x10 unused */
#define PANE_FOCUSPUSH 0x20
/* 0x20 unused */
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
#define PANE_EXITED 0x100
@ -1293,18 +1205,7 @@ struct key_event {
struct mouse_event m;
};
/* TTY information. */
struct tty_key {
char ch;
key_code key;
struct tty_key *left;
struct tty_key *right;
struct tty_key *next;
};
struct tty_code;
/* Terminal definition. */
struct tty_term {
char *name;
struct tty *tty;
@ -1326,6 +1227,7 @@ struct tty_term {
};
LIST_HEAD(tty_terms, tty_term);
/* Client terminal. */
struct tty {
struct client *client;
struct event start_timer;
@ -1394,7 +1296,7 @@ struct tty {
struct tty_key *key_tree;
};
/* TTY command context. */
/* Terminal command context. */
typedef void (*tty_ctx_redraw_cb)(const struct tty_ctx *);
typedef int (*tty_ctx_set_client_cb)(struct tty_ctx *, struct client *);
struct tty_ctx {
@ -1635,12 +1537,14 @@ RB_HEAD(client_windows, client_window);
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
typedef int (*overlay_check_cb)(struct client *, u_int, u_int);
typedef struct screen *(*overlay_mode_cb)(struct client *, u_int *, u_int *);
typedef void (*overlay_draw_cb)(struct client *, struct screen_redraw_ctx *);
typedef int (*overlay_key_cb)(struct client *, struct key_event *);
typedef void (*overlay_free_cb)(struct client *);
typedef void (*overlay_resize_cb)(struct client *);
typedef int (*overlay_check_cb)(struct client *, void *, u_int, u_int);
typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
u_int *);
typedef void (*overlay_draw_cb)(struct client *, void *,
struct screen_redraw_ctx *);
typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *);
typedef void (*overlay_free_cb)(struct client *, void *);
typedef void (*overlay_resize_cb)(struct client *, void *);
struct client {
const char *name;
struct tmuxpeer *peer;
@ -2139,6 +2043,7 @@ struct job *job_run(const char *, int, char **, struct session *,
const char *, job_update_cb, job_complete_cb, job_free_cb,
void *, int, int, int);
void job_free(struct job *);
int job_transfer(struct job *, pid_t *, char *, size_t);
void job_resize(struct job *, u_int, u_int);
void job_check_died(pid_t, int);
int job_get_status(struct job *);
@ -2507,6 +2412,7 @@ int server_client_handle_key(struct client *, struct key_event *);
struct client *server_client_create(int);
int server_client_open(struct client *, char **);
void server_client_unref(struct client *);
void server_client_set_session(struct client *, struct session *);
void server_client_lost(struct client *);
void server_client_suspend(struct client *);
void server_client_detach(struct client *, enum msgtype);
@ -2827,6 +2733,8 @@ struct window_pane *window_find_string(struct window *, const char *);
int window_has_pane(struct window *, struct window_pane *);
int window_set_active_pane(struct window *, struct window_pane *,
int);
void window_update_focus(struct window *);
void window_pane_update_focus(struct window_pane *);
void window_redraw_active_switch(struct window *,
struct window_pane *);
struct window_pane *window_add_pane(struct window *, struct window_pane *,
@ -3116,13 +3024,24 @@ void menu_add_item(struct menu *, const struct menu_item *,
struct cmdq_item *, struct client *,
struct cmd_find_state *);
void menu_free(struct menu *);
struct menu_data *menu_prepare(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *);
int menu_display(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *);
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
int menu_check_cb(struct client *, void *, u_int, u_int);
void menu_draw_cb(struct client *, void *,
struct screen_redraw_ctx *);
void menu_free_cb(struct client *, void *);
int menu_key_cb(struct client *, void *, struct key_event *);
/* popup.c */
#define POPUP_CLOSEEXIT 0x1
#define POPUP_CLOSEEXITZERO 0x2
#define POPUP_NOBORDER 0x4
#define POPUP_INTERNAL 0x8
typedef void (*popup_close_cb)(int, void *);
typedef void (*popup_finish_edit_cb)(char *, size_t, void *);
int popup_display(int, struct cmdq_item *, u_int, u_int, u_int,

View File

@ -58,6 +58,17 @@ static int tty_keys_device_attributes(struct tty *, const char *, size_t,
static int tty_keys_extended_device_attributes(struct tty *, const char *,
size_t, size_t *);
/* A key tree entry. */
struct tty_key {
char ch;
key_code key;
struct tty_key *left;
struct tty_key *right;
struct tty_key *next;
};
/* Default raw keys. */
struct tty_default_key_raw {
const char *string;
@ -821,11 +832,13 @@ complete_key:
/* Check for focus events. */
if (key == KEYC_FOCUS_OUT) {
tty->client->flags &= ~CLIENT_FOCUSED;
c->flags &= ~CLIENT_FOCUSED;
window_update_focus(c->session->curw->window);
notify_client("client-focus-out", c);
} else if (key == KEYC_FOCUS_IN) {
tty->client->flags |= CLIENT_FOCUSED;
c->flags |= CLIENT_FOCUSED;
notify_client("client-focus-in", c);
window_update_focus(c->session->curw->window);
}
/* Fire the key. */

2
tty.c
View File

@ -1318,7 +1318,7 @@ tty_check_overlay(struct tty *tty, u_int px, u_int py)
if (c->overlay_check == NULL)
return (1);
return (c->overlay_check(c, px, py));
return (c->overlay_check(c, c->overlay_data, px, py));
}
void

View File

@ -465,6 +465,52 @@ window_has_pane(struct window *w, struct window_pane *wp)
return (0);
}
void
window_update_focus(struct window *w)
{
if (w != NULL) {
log_debug("%s: @%u", __func__, w->id);
window_pane_update_focus(w->active);
}
}
void
window_pane_update_focus(struct window_pane *wp)
{
struct client *c;
int focused = 0;
if (wp != NULL) {
if (wp != wp->window->active)
focused = 0;
else {
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL &&
c->session->attached != 0 &&
(c->flags & CLIENT_FOCUSED) &&
c->session->curw->window == wp->window) {
focused = 1;
break;
}
}
}
if (!focused && (wp->flags & PANE_FOCUSED)) {
log_debug("%s: %%%u focus out", __func__, wp->id);
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[O", 3);
notify_pane("pane-focus-out", wp);
wp->flags &= ~PANE_FOCUSED;
} else if (focused && (~wp->flags & PANE_FOCUSED)) {
log_debug("%s: %%%u focus in", __func__, wp->id);
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3);
notify_pane("pane-focus-in", wp);
wp->flags |= PANE_FOCUSED;
} else
log_debug("%s: %%%u focus unchanged", __func__, wp->id);
}
}
int
window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
{
@ -478,6 +524,11 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
if (options_get_number(global_options, "focus-events")) {
window_pane_update_focus(w->last);
window_pane_update_focus(w->active);
}
tty_update_window_offset(w);
if (notify)