mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
8a57d14f4b
@ -154,6 +154,7 @@ dist_tmux_SOURCES = \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
2
cmd.c
@ -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
19
job.c
@ -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
17
menu.c
@ -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
447
popup.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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
91
tmux.1
@ -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
20
tmux.h
@ -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
19
tty.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user