Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2020-03-26 11:11:37 +00:00
commit 8a57d14f4b
12 changed files with 749 additions and 36 deletions

View File

@ -154,6 +154,7 @@ dist_tmux_SOURCES = \
options-table.c \
options.c \
paste.c \
popup.c \
proc.c \
regsub.c \
resize.c \

View File

@ -29,6 +29,8 @@
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
@ -44,6 +46,21 @@ const struct cmd_entry cmd_display_menu_entry = {
.exec = cmd_display_menu_exec
};
const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "CEKc:d:h:R:t:w:x:y:", 0, -1 },
.usage = "[-CEK] [-c target-client] [-d start-directory] [-h height] "
"[-R shell-command] " CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [command line ...]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_display_popup_exec
};
static void
cmd_display_menu_get_position(struct client *c, struct cmdq_item *item,
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
@ -190,3 +207,79 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct cmd_find_state *fs = &item->target;
const char *value, *cmd = NULL, **lines = NULL;
const char *shellcmd = NULL;
char *cwd, *cause;
int flags = 0;
u_int px, py, w, h, nlines = 0;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'C')) {
server_client_clear_overlay(c);
return (CMD_RETURN_NORMAL);
}
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (args->argc >= 1)
cmd = args->argv[0];
if (args->argc >= 2) {
lines = (const char **)args->argv + 1;
nlines = args->argc - 1;
}
if (nlines != 0)
h = nlines + 2;
else
h = c->tty.sy / 2;
if (args_has(args, 'h')) {
h = args_percentage(args, 'h', 1, c->tty.sy, c->tty.sy, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (nlines != 0)
w = popup_width(item, nlines, lines, c, fs) + 2;
else
w = c->tty.sx / 2;
if (args_has(args, 'w')) {
w = args_percentage(args, 'w', 1, c->tty.sx, c->tty.sx, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
cmd_display_menu_get_position(c, item, args, &px, &py, w, h);
value = args_get(args, 'd');
if (value != NULL)
cwd = format_single(NULL, value, c, fs->s, fs->wl, fs->wp);
else
cwd = xstrdup(server_client_get_cwd(c, fs->s));
value = args_get(args, 'R');
if (value != NULL)
shellcmd = format_single(NULL, value, c, fs->s, fs->wl, fs->wp);
if (args_has(args, 'K'))
flags |= POPUP_WRITEKEYS;
if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (popup_display(flags, item, px, py, w, h, nlines, lines, shellcmd,
cmd, cwd, c, fs) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@ -273,7 +273,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
else
cdata->item = item;
server_client_set_overlay(c, delay, cmd_display_panes_draw,
server_client_set_overlay(c, delay, NULL, NULL, cmd_display_panes_draw,
cmd_display_panes_key, cmd_display_panes_free, cdata);
if (args_has(args, 'b'))

2
cmd.c
View File

@ -43,6 +43,7 @@ extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry;
extern const struct cmd_entry cmd_display_menu_entry;
extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_popup_entry;
extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
extern const struct cmd_entry cmd_find_window_entry;
@ -132,6 +133,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry,
&cmd_display_popup_entry,
&cmd_display_panes_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,

19
job.c
View File

@ -17,6 +17,7 @@
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <fcntl.h>
@ -203,6 +204,24 @@ job_free(struct job *job)
free(job);
}
/* Resize job. */
void
job_resize(struct job *job, u_int sx, u_int sy)
{
struct winsize ws;
if (job->fd == -1 || (~job->flags & JOB_PTY))
return;
log_debug("resize job %p: %ux%u", job, sx, sy);
memset(&ws, 0, sizeof ws);
ws.ws_col = sx;
ws.ws_row = sy;
if (ioctl(job->fd, TIOCSWINSZ, &ws) == -1)
fatal("ioctl failed");
}
/* Job buffer read callback. */
static void
job_read_callback(__unused struct bufferevent *bufev, void *data)

17
menu.c
View File

@ -130,6 +130,16 @@ menu_free(struct menu *menu)
free(menu);
}
static int
menu_mode_cb(struct client *c, __unused u_int *cx, __unused u_int *cy)
{
struct menu_data *md = c->overlay_data;
if (~md->flags & MENU_NOMOUSE)
return (MODE_MOUSE_ALL);
return (0);
}
static void
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
{
@ -147,9 +157,6 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
for (i = 0; i < screen_size_y(&md->s); i++)
tty_draw_line(tty, NULL, s, 0, i, menu->width + 4, px, py + i);
if (~md->flags & MENU_NOMOUSE)
tty_update_mode(tty, MODE_MOUSE_ALL, NULL);
}
static void
@ -317,7 +324,7 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
md->cb = cb;
md->data = data;
server_client_set_overlay(c, 0, menu_draw_cb, menu_key_cb, menu_free_cb,
md);
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
menu_key_cb, menu_free_cb, md);
return (0);
}

447
popup.c Normal file
View File

@ -0,0 +1,447 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2020 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.
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct popup_data {
struct client *c;
struct cmdq_item *item;
int flags;
char **lines;
u_int nlines;
char *cmd;
struct cmd_find_state fs;
struct screen s;
struct job *job;
struct input_ctx *ictx;
int status;
u_int px;
u_int py;
u_int sx;
u_int sy;
enum { OFF, MOVE, SIZE } dragging;
u_int dx;
u_int dy;
u_int lx;
u_int ly;
u_int lb;
};
static void
popup_write_screen(struct client *c, struct popup_data *pd)
{
struct cmdq_item *item = pd->item;
struct screen_write_ctx ctx;
char *copy, *next, *loop, *tmp;
struct format_tree *ft;
u_int i, y;
ft = format_create(item->client, item, FORMAT_NONE, 0);
if (cmd_find_valid_state(&pd->fs))
format_defaults(ft, c, pd->fs.s, pd->fs.wl, pd->fs.wp);
else
format_defaults(ft, c, NULL, NULL, NULL);
screen_write_start(&ctx, NULL, &pd->s);
screen_write_clearscreen(&ctx, 8);
y = 0;
for (i = 0; i < pd->nlines; i++) {
if (y == pd->sy - 2)
break;
copy = next = xstrdup(pd->lines[i]);
while ((loop = strsep(&next, "\n")) != NULL) {
if (y == pd->sy - 2)
break;
tmp = format_expand(ft, loop);
screen_write_cursormove(&ctx, 0, y, 0);
format_draw(&ctx, &grid_default_cell, pd->sx - 2, tmp,
NULL);
free(tmp);
y++;
}
free(copy);
}
format_free(ft);
screen_write_cursormove(&ctx, 0, y, 0);
screen_write_stop(&ctx);
}
static int
popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
{
struct popup_data *pd = c->overlay_data;
if (pd->ictx == NULL)
return (0);
*cx = pd->px + 1 + pd->s.cx;
*cy = pd->py + 1 + pd->s.cy;
return (pd->s.mode);
}
static int
popup_check_cb(struct client *c, u_int px, u_int py)
{
struct popup_data *pd = c->overlay_data;
if (px < pd->px || px > pd->px + pd->sx - 1)
return (1);
if (py < pd->py || py > pd->py + pd->sy - 1)
return (1);
return (0);
}
static void
popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
{
struct popup_data *pd = c->overlay_data;
struct tty *tty = &c->tty;
struct screen s;
struct screen_write_ctx ctx;
u_int i, px = pd->px, py = pd->py;
screen_init(&s, pd->sx, pd->sy, 0);
screen_write_start(&ctx, NULL, &s);
screen_write_clearscreen(&ctx, 8);
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, pd->sy - 2);
screen_write_stop(&ctx);
c->overlay_check = NULL;
for (i = 0; i < pd->sy; i++)
tty_draw_line(tty, NULL, &s, 0, i, pd->sx, px, py + i);
c->overlay_check = popup_check_cb;
}
static void
popup_free_cb(struct client *c)
{
struct popup_data *pd = c->overlay_data;
struct cmdq_item *item = pd->item;
u_int i;
if (item != NULL) {
if (pd->ictx != NULL &&
item->client != NULL &&
item->client->session == NULL)
item->client->retval = pd->status;
cmdq_continue(item);
}
server_client_unref(pd->c);
if (pd->job != NULL)
job_free(pd->job);
if (pd->ictx != NULL)
input_free(pd->ictx);
for (i = 0; i < pd->nlines; i++)
free(pd->lines[i]);
free(pd->lines);
screen_free(&pd->s);
free(pd->cmd);
free(pd);
}
static void
popup_handle_drag(struct client *c, struct popup_data *pd,
struct mouse_event *m)
{
u_int px, py;
if (!MOUSE_DRAG(m->b))
pd->dragging = OFF;
else if (pd->dragging == MOVE) {
if (m->x < pd->dx)
px = 0;
else if (m->x - pd->dx + pd->sx > c->tty.sx)
px = c->tty.sx - pd->sx;
else
px = m->x - pd->dx;
if (m->y < pd->dy)
py = 0;
else if (m->y - pd->dy + pd->sy > c->tty.sy)
py = c->tty.sy - pd->sy;
else
py = m->y - pd->dy;
pd->px = px;
pd->py = py;
pd->dx = m->x - pd->px;
pd->dy = m->y - pd->py;
server_redraw_client(c);
} else if (pd->dragging == SIZE) {
if (m->x < pd->px + 2)
return;
if (m->y < pd->py + 2)
return;
pd->sx = m->x - pd->px;
pd->sy = m->y - pd->py;
screen_resize(&pd->s, pd->sx, pd->sy, 0);
if (pd->ictx == NULL)
popup_write_screen(c, pd);
else 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)
{
struct popup_data *pd = c->overlay_data;
struct mouse_event *m = &event->m;
struct cmd_find_state *fs = &pd->fs;
struct cmdq_item *new_item;
struct cmd_parse_result *pr;
struct format_tree *ft;
const char *cmd;
if (KEYC_IS_MOUSE(event->key)) {
if (pd->dragging != OFF) {
popup_handle_drag(c, pd, m);
goto out;
}
if (m->x < pd->px ||
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);
return (0);
}
if ((m->b & MOUSE_MASK_META) ||
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)
pd->dragging = MOVE;
else if (MOUSE_BUTTONS(m->lb) == 2)
pd->dragging = SIZE;
pd->dx = m->lx - pd->px;
pd->dy = m->ly - pd->py;
goto out;
}
}
if (pd->ictx != NULL && (pd->flags & POPUP_WRITEKEYS)) {
if (KEYC_IS_MOUSE(event->key))
return (0);
if ((~pd->flags & POPUP_CLOSEEXIT) &&
(event->key == '\033' || event->key == '\003'))
return (1);
if (pd->job == NULL)
return (0);
input_key(NULL, &pd->s, job_get_event(pd->job), event->key);
return (0);
}
if (pd->cmd == NULL)
return (1);
ft = format_create(NULL, pd->item, FORMAT_NONE, 0);
if (cmd_find_valid_state(fs))
format_defaults(ft, c, fs->s, fs->wl, fs->wp);
else
format_defaults(ft, c, NULL, NULL, NULL);
format_add(ft, "popup_key", "%s", key_string_lookup_key(event->key));
if (KEYC_IS_MOUSE(event->key)) {
format_add(ft, "popup_mouse", "1");
format_add(ft, "popup_mouse_x", "%u", m->x - pd->px);
format_add(ft, "popup_mouse_y", "%u", m->y - pd->py);
}
cmd = format_expand(ft, pd->cmd);
format_free(ft);
pr = cmd_parse_from_string(cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
if (pd->item != NULL)
m = &pd->item->shared->mouse;
else
m = NULL;
new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
}
return (1);
out:
pd->lx = m->x;
pd->ly = m->y;
pd->lb = m->b;
return (0);
}
static void
popup_job_update_cb(struct job *job)
{
struct popup_data *pd = job_get_data(job);
struct evbuffer *evb = job_get_event(job)->input;
struct screen *s = &pd->s;
void *data = EVBUFFER_DATA(evb);
size_t size = EVBUFFER_LENGTH(evb);
if (size != 0) {
input_parse_screen(pd->ictx, s, data, size);
evbuffer_drain(evb, size);
pd->c->flags |= CLIENT_REDRAWOVERLAY;
}
}
static void
popup_job_complete_cb(struct job *job)
{
struct popup_data *pd = job_get_data(job);
int status;
status = job_get_status(pd->job);
if (WIFEXITED(status))
pd->status = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
pd->status = WTERMSIG(status);
else
pd->status = 0;
pd->job = NULL;
if (pd->flags & POPUP_CLOSEEXIT)
server_client_clear_overlay(pd->c);
}
u_int
popup_width(struct cmdq_item *item, u_int nlines, const char **lines,
struct client *c, struct cmd_find_state *fs)
{
char *copy, *next, *loop, *tmp;
struct format_tree *ft;
u_int i, width = 0, tmpwidth;
ft = format_create(item->client, item, FORMAT_NONE, 0);
if (fs != NULL && cmd_find_valid_state(fs))
format_defaults(ft, c, fs->s, fs->wl, fs->wp);
else
format_defaults(ft, c, NULL, NULL, NULL);
for (i = 0; i < nlines; i++) {
copy = next = xstrdup(lines[i]);
while ((loop = strsep(&next, "\n")) != NULL) {
tmp = format_expand(ft, loop);
tmpwidth = format_width(tmp);
if (tmpwidth > width)
width = tmpwidth;
free(tmp);
}
}
free(copy);
format_free(ft);
return (width);
}
int
popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
u_int sy, u_int nlines, const char **lines, const char *shellcmd,
const char *cmd, const char *cwd, struct client *c,
struct cmd_find_state *fs)
{
struct popup_data *pd;
u_int i;
struct session *s;
int jobflags;
if (sx < 3 || sy < 3)
return (-1);
if (c->tty.sx < sx || c->tty.sy < sy)
return (-1);
if (nlines > sy - 2)
nlines = sy - 2;
pd = xcalloc(1, sizeof *pd);
pd->item = item;
pd->flags = flags;
pd->c = c;
pd->c->references++;
pd->status = 128 + SIGHUP;
if (fs != NULL)
cmd_find_copy_state(&pd->fs, fs);
screen_init(&pd->s, sx - 2, sy - 2, 0);
if (cmd != NULL)
pd->cmd = xstrdup(cmd);
pd->px = px;
pd->py = py;
pd->sx = sx;
pd->sy = sy;
pd->nlines = nlines;
if (pd->nlines != 0)
pd->lines = xreallocarray(NULL, pd->nlines, sizeof *pd->lines);
for (i = 0; i < pd->nlines; i++)
pd->lines[i] = xstrdup(lines[i]);
popup_write_screen(c, pd);
if (shellcmd != NULL) {
pd->ictx = input_init(NULL);
if (fs != NULL)
s = fs->s;
else
s = NULL;
jobflags = JOB_NOWAIT|JOB_PTY;
if (flags & POPUP_WRITEKEYS)
jobflags |= JOB_KEEPWRITE;
pd->job = job_run(shellcmd, s, cwd, popup_job_update_cb,
popup_job_complete_cb, NULL, pd, jobflags, pd->sx - 2,
pd->sy - 2);
}
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
popup_draw_cb, popup_key_cb, popup_free_cb, pd);
return (0);
}

View File

@ -482,6 +482,8 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j,
u_int type, x = ctx->ox + i, y = ctx->oy + j;
int flag, pane_status = ctx->pane_status;
if (c->overlay_check != NULL && !c->overlay_check(c, x, y))
return;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE)
return;

View File

@ -41,7 +41,6 @@ static void server_client_check_redraw(struct client *);
static void server_client_set_title(struct client *);
static void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *);
static void server_client_clear_overlay(struct client *);
static void server_client_resize_event(int, short, void *);
static void server_client_dispatch(struct imsg *, void *);
@ -79,8 +78,10 @@ server_client_overlay_timer(__unused int fd, __unused short events, void *data)
/* Set an overlay on client. */
void
server_client_set_overlay(struct client *c, u_int delay, overlay_draw_cb drawcb,
overlay_key_cb keycb, overlay_free_cb freecb, void *data)
server_client_set_overlay(struct client *c, u_int delay,
overlay_check_cb checkcb, overlay_mode_cb modecb,
overlay_draw_cb drawcb, overlay_key_cb keycb, overlay_free_cb freecb,
void *data)
{
struct timeval tv;
@ -96,17 +97,21 @@ server_client_set_overlay(struct client *c, u_int delay, overlay_draw_cb drawcb,
if (delay != 0)
evtimer_add(&c->overlay_timer, &tv);
c->overlay_check = checkcb;
c->overlay_mode = modecb;
c->overlay_draw = drawcb;
c->overlay_key = keycb;
c->overlay_free = freecb;
c->overlay_data = data;
c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR);
c->tty.flags |= TTY_FREEZE;
if (c->overlay_mode == NULL)
c->tty.flags |= TTY_NOCURSOR;
server_redraw_client(c);
}
/* Clear overlay mode on client. */
static void
void
server_client_clear_overlay(struct client *c)
{
if (c->overlay_draw == NULL)
@ -118,8 +123,12 @@ server_client_clear_overlay(struct client *c)
if (c->overlay_free != NULL)
c->overlay_free(c);
c->overlay_check = NULL;
c->overlay_mode = NULL;
c->overlay_draw = NULL;
c->overlay_key = NULL;
c->overlay_free = NULL;
c->overlay_data = NULL;
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
server_redraw_client(c);
@ -1483,35 +1492,48 @@ server_client_reset_state(struct client *c)
{
struct window *w = c->session->curw->window;
struct window_pane *wp = w->active, *loop;
struct screen *s = wp->screen;
struct screen *s;
struct options *oo = c->session->options;
int mode, cursor = 0;
u_int cx = 0, cy = 0, ox, oy, sx, sy;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
if (c->overlay_draw != NULL)
return;
mode = s->mode;
/* Get mode from overlay if any, else from screen. */
if (c->overlay_draw != NULL) {
s = NULL;
if (c->overlay_mode == NULL)
mode = 0;
else
mode = c->overlay_mode(c, &cx, &cy);
} else {
s = wp->screen;
mode = s->mode;
}
log_debug("%s: client %s mode %x", __func__, c->name, mode);
/* Reset region and margin. */
tty_region_off(&c->tty);
tty_margin_off(&c->tty);
/* Move cursor to pane cursor and offset. */
cursor = 0;
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
cursor = 1;
if (c->overlay_draw == NULL) {
cursor = 0;
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
cursor = 1;
cx = wp->xoff + s->cx - ox;
cy = wp->yoff + s->cy - oy;
cx = wp->xoff + s->cx - ox;
cy = wp->yoff + s->cy - oy;
if (status_at_line(c) == 0)
cy += status_line_size(c);
if (status_at_line(c) == 0)
cy += status_line_size(c);
}
if (!cursor)
mode &= ~MODE_CURSOR;
}
if (!cursor)
mode &= ~MODE_CURSOR;
tty_cursor(&c->tty, cx, cy);
/*
@ -1520,16 +1542,18 @@ server_client_reset_state(struct client *c)
*/
if (options_get_number(oo, "mouse")) {
mode &= ~ALL_MOUSE_MODES;
TAILQ_FOREACH(loop, &w->panes, entry) {
if (loop->screen->mode & MODE_MOUSE_ALL)
mode |= MODE_MOUSE_ALL;
if (c->overlay_draw == NULL) {
TAILQ_FOREACH(loop, &w->panes, entry) {
if (loop->screen->mode & MODE_MOUSE_ALL)
mode |= MODE_MOUSE_ALL;
}
}
if (~mode & MODE_MOUSE_ALL)
mode |= MODE_MOUSE_BUTTON;
}
/* Clear bracketed paste mode if at the prompt. */
if (c->prompt_string != NULL)
if (c->overlay_draw == NULL && c->prompt_string != NULL)
mode &= ~MODE_BRACKETPASTE;
/* Set the terminal mode and reset attributes. */

91
tmux.1
View File

@ -4383,7 +4383,10 @@ The following variables are available, where appropriate:
.It Li "pane_top" Ta "" Ta "Top of pane"
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "" Ta "Width of pane"
.It Li "pid" Ta "" Ta "Server PID"
.It Li "pid" Ta "" Ta "Server PID"
.It Li "popup_key" Ta "" Ta "Key pressed in popup"
.It Li "popup_mouse_x" Ta "" Ta "Mouse X position in popup"
.It Li "popup_mouse_y" Ta "" Ta "Mouse Y position in popup"
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
@ -4973,6 +4976,92 @@ lists the format variables and their values.
.Fl I
forwards any input read from stdin to the empty pane given by
.Ar target-pane .
.It Xo Ic display-popup
.Op Fl CEK
.Op Fl c Ar target-client
.Op Fl d Ar start-directory
.Op Fl h Ar height
.Op Fl R Ar shell-command
.Op Fl t Ar target-pane
.Op Fl w Ar width
.Op Fl x Ar position
.Op Fl y Ar position
.Op Ar command Ar line Ar ...
.Xc
.D1 (alias: Ic popup )
Display a popup on
.Ar target-client .
A popup is a rectangular box drawn over the top of any panes.
Panes are not updated while a popup is present.
The popup content may be given in two ways:
.Bl -enum -offset Ds
.It
A set of lines as arguments.
Each line is a format which is expanded using
.Ar target-pane
as the target.
If a line contains newlines it is split into multiple lines.
Lines may use styles, see the
.Sx STYLES
section.
.It
A shell command given by
.Fl R
which is run and any output shown in the pane.
.El
.Pp
The first argument,
.Ar command ,
is a
.Nm
command which is run when a key is pressed.
The key is available in the
.Ql popup_key
format.
After
.Ar command
is run, the popup is closed.
It may be empty to discard any key presses.
If
.Fl K
is given together with
.Fl R,
key presses are instead passed to the
.Fl R
shell command.
.Fl E
closes the popup automatically when
.Ar shell-command
exits.
With
.Fl K ,
.Ql Escape
and
.Ql C-c
close the popup unless
.Fl E
is also given.
.Pp
.Fl x
and
.Fl y
give the position of the popup, they have the same meaning as for the
.Ic display-menu
command.
.Fl w
and
.Fl h
give the width and height - both may be a percentage (followed by
.Ql % ) .
If omitted, without
.Fl R
they are calculated from the given lines and with
.Fl R
they use half the terminal size.
.Pp
The
.Fl C
flag closes any popup on the client.
.El
.Sh BUFFERS
.Nm

20
tmux.h
View File

@ -1517,6 +1517,8 @@ RB_HEAD(client_files, client_file);
/* 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 int (*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 *);
@ -1632,6 +1634,8 @@ struct client {
u_int pan_ox;
u_int pan_oy;
overlay_check_cb overlay_check;
overlay_mode_cb overlay_mode;
overlay_draw_cb overlay_draw;
overlay_key_cb overlay_key;
overlay_free_cb overlay_free;
@ -1936,6 +1940,7 @@ struct job *job_run(const char *, struct session *, const char *,
job_update_cb, job_complete_cb, job_free_cb, void *, int,
int, int);
void job_free(struct job *);
void job_resize(struct job *, u_int, u_int);
void job_check_died(pid_t, int);
int job_get_status(struct job *);
void *job_get_data(struct job *);
@ -2218,8 +2223,10 @@ void server_add_accept(int);
/* server-client.c */
u_int server_client_how_many(void);
void server_client_set_overlay(struct client *, u_int, overlay_draw_cb,
overlay_key_cb, overlay_free_cb, void *);
void server_client_set_overlay(struct client *, u_int, overlay_check_cb,
overlay_mode_cb, overlay_draw_cb, overlay_key_cb,
overlay_free_cb, void *);
void server_client_clear_overlay(struct client *);
void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *);
@ -2755,6 +2762,15 @@ int menu_display(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *);
/* popup.c */
#define POPUP_WRITEKEYS 0x1
#define POPUP_CLOSEEXIT 0x2
u_int popup_width(struct cmdq_item *, u_int, const char **,
struct client *, struct cmd_find_state *);
int popup_display(int, struct cmdq_item *, u_int, u_int, u_int,
u_int, u_int, const char **, const char *, const char *,
const char *, struct client *, struct cmd_find_state *);
/* style.c */
int style_parse(struct style *,const struct grid_cell *,
const char *);

19
tty.c
View File

@ -1250,6 +1250,16 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
return (&new);
}
static int
tty_check_overlay(struct tty *tty, u_int px, u_int py)
{
struct client *c = tty->client;
if (c->overlay_check == NULL)
return (1);
return (c->overlay_check(c, px, py));
}
void
tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
u_int px, u_int py, u_int nx, u_int atx, u_int aty)
@ -1329,7 +1339,8 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
grid_view_get_cell(gd, px + i, py, &gc);
gcp = tty_check_codeset(tty, &gc);
if (len != 0 &&
((gcp->attr & GRID_ATTR_CHARSET) ||
(!tty_check_overlay(tty, atx + ux + width, aty) ||
(gcp->attr & GRID_ATTR_CHARSET) ||
gcp->flags != last.flags ||
gcp->attr != last.attr ||
gcp->fg != last.fg ||
@ -1358,7 +1369,9 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
screen_select_cell(s, &last, gcp);
else
memcpy(&last, gcp, sizeof last);
if (ux + gcp->data.width > nx) {
if (!tty_check_overlay(tty, atx + ux, aty))
ux += gcp->data.width;
else if (ux + gcp->data.width > nx) {
tty_attributes(tty, &last, wp);
tty_cursor(tty, atx + ux, aty);
for (j = 0; j < gcp->data.width; j++) {
@ -1372,7 +1385,7 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
tty_cursor(tty, atx + ux, aty);
for (j = 0; j < gcp->data.size; j++)
tty_putc(tty, gcp->data.data[j]);
ux += gc.data.width;
ux += gcp->data.width;
} else {
memcpy(buf + len, gcp->data.data, gcp->data.size);
len += gcp->data.size;