summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Adam <thomas@xteddy.org>2021-08-14 01:34:54 +0100
committerThomas Adam <thomas@xteddy.org>2021-08-14 01:34:54 +0100
commit54773d23b5ceb779c524dcac6bf3b848886fb6d6 (patch)
tree5c60007637121f63c8c730a04f4e8e741577c21a
parent4c07367bfe626fce990f5b5b2d00516ae8249a93 (diff)
parent63aa96864280ff07f706ebbae302b7c15abb964f (diff)
Merge branch 'obsd-master' into master
-rw-r--r--cmd-attach-session.c23
-rw-r--r--cmd-command-prompt.c60
-rw-r--r--cmd-confirm-before.c15
-rw-r--r--cmd-display-menu.c6
-rw-r--r--cmd-display-panes.c11
-rw-r--r--cmd-if-shell.c5
-rw-r--r--cmd-new-session.c10
-rw-r--r--cmd-run-shell.c1
-rw-r--r--cmd-switch-client.c16
-rw-r--r--input.c8
-rw-r--r--job.c32
-rw-r--r--menu.c57
-rw-r--r--popup.c305
-rw-r--r--screen-redraw.c5
-rw-r--r--server-client.c104
-rw-r--r--server-fn.c16
-rw-r--r--session.c6
-rw-r--r--tmux-protocol.h114
-rw-r--r--tmux.114
-rw-r--r--tmux.h143
-rw-r--r--tty-keys.c17
-rw-r--r--tty.c2
-rw-r--r--window.c51
23 files changed, 681 insertions, 340 deletions
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 6a7ebba7..c2074f4f 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -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);
}
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index a955ac32..7e3d23c5 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -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,20 +75,22 @@ 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->idx = 1;
- cdata->inputs = NULL;
- cdata->next_input = NULL;
-
- cdata->prompts = NULL;
- cdata->next_prompt = NULL;
+ 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);
- cdata->template = NULL;
- cdata->idx = 1;
+ if (wait)
+ cdata->item = item;
if (args->argc != 0 && args_has(args, 'F'))
cdata->template = format_single_from_target(item, args->argv[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);
}
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index 83f9a0f8..6b754370 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -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);
}
diff --git a/cmd-display-menu.c b/cmd-display-menu.c
index 92def23b..9e7bc3a2 100644
--- a/cmd-display-menu.c
+++ b/cmd-display-menu.c
@@ -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);
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index f03b80ed..beadae53 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -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;
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 65fbf19b..f4c81074 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -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);
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 033c707f..f3a5de26 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -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
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 56d5f723..7bc1d7cc 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -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;
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index b10496e3..bc6baa6a 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -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);
}
diff --git a/input.c b/input.c
index 49ed68b7..155144b7 100644
--- a/input.c
+++ b/input.c
@@ -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);
diff --git a/job.c b/job.c
index a1fc0cf5..3624c679 100644
--- a/job.c
+++ b/job.c
@@ -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)
diff --git a/menu.c b/menu.c
index c8de02a8..7fb1996b 100644
--- a/menu.c
+++ b/menu.c
@@ -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 = 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 = c->overlay_data;
+ 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);
diff --git a/popup.c b/popup.c
index eb6ddfa8..9565b012 100644
--- a/popup.c
+++ b/popup.c
@@ -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,7 +278,11 @@ 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);
@@ -225,6 +290,92 @@ popup_resize_cb(struct client *c)
}
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 ((~pd->flags & POPUP_NOBORDER) &&
+ (~m->b & MOUSE_MASK_META) &&