mirror of
https://github.com/tmux/tmux.git
synced 2025-09-02 05:21:10 +00:00
Merge branch 'obsd-master'
This commit is contained in:
5
client.c
5
client.c
@ -404,6 +404,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
|||||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||||
fprintf(stderr, "%s\n", client_exit_message());
|
fprintf(stderr, "%s\n", client_exit_message());
|
||||||
setblocking(STDIN_FILENO, 1);
|
setblocking(STDIN_FILENO, 1);
|
||||||
|
setblocking(STDOUT_FILENO, 1);
|
||||||
|
setblocking(STDERR_FILENO, 1);
|
||||||
return (client_exitval);
|
return (client_exitval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,6 +433,9 @@ client_send_identify(const char *ttynam, const char *cwd, int feat)
|
|||||||
if ((fd = dup(STDIN_FILENO)) == -1)
|
if ((fd = dup(STDIN_FILENO)) == -1)
|
||||||
fatal("dup failed");
|
fatal("dup failed");
|
||||||
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
||||||
|
if ((fd = dup(STDOUT_FILENO)) == -1)
|
||||||
|
fatal("dup failed");
|
||||||
|
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
|
||||||
|
|
||||||
pid = getpid();
|
pid = getpid();
|
||||||
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
|
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
|
||||||
|
@ -80,6 +80,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
if (args_has(args, 'n')) {
|
||||||
|
window_set_name(w, args_get(args, 'n'));
|
||||||
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
|
}
|
||||||
server_unlink_window(src_s, wl);
|
server_unlink_window(src_s, wl);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,10 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'm') || args_has(args, 'M')) {
|
if (args_has(args, 'm') || args_has(args, 'M')) {
|
||||||
if (args_has(args, 'm') && !window_pane_visible(wp))
|
if (args_has(args, 'm') && !window_pane_visible(wp))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
lastwp = marked_pane.wp;
|
if (server_check_marked())
|
||||||
|
lastwp = marked_pane.wp;
|
||||||
|
else
|
||||||
|
lastwp = NULL;
|
||||||
|
|
||||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||||
server_clear_marked();
|
server_clear_marked();
|
||||||
|
81
control.c
81
control.c
@ -23,10 +23,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/* Control offsets. */
|
/* Control client offset. */
|
||||||
struct control_offset {
|
struct control_offset {
|
||||||
u_int pane;
|
u_int pane;
|
||||||
|
|
||||||
@ -34,13 +35,16 @@ struct control_offset {
|
|||||||
int flags;
|
int flags;
|
||||||
#define CONTROL_OFFSET_OFF 0x1
|
#define CONTROL_OFFSET_OFF 0x1
|
||||||
|
|
||||||
RB_ENTRY(control_offset) entry;
|
RB_ENTRY(control_offset) entry;
|
||||||
};
|
};
|
||||||
RB_HEAD(control_offsets, control_offset);
|
RB_HEAD(control_offsets, control_offset);
|
||||||
|
|
||||||
/* Control state. */
|
/* Control client state. */
|
||||||
struct control_state {
|
struct control_state {
|
||||||
struct control_offsets offsets;
|
struct control_offsets offsets;
|
||||||
|
|
||||||
|
struct bufferevent *read_event;
|
||||||
|
struct bufferevent *write_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Compare client offsets. */
|
/* Compare client offsets. */
|
||||||
@ -146,18 +150,24 @@ control_set_pane_off(struct client *c, struct window_pane *wp)
|
|||||||
void
|
void
|
||||||
control_write(struct client *c, const char *fmt, ...)
|
control_write(struct client *c, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
struct control_state *cs = c->control_state;
|
||||||
|
va_list ap;
|
||||||
|
char *s;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
file_vprint(c, fmt, ap);
|
xvasprintf(&s, fmt, ap);
|
||||||
file_print(c, "\n");
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
bufferevent_write(cs->write_event, s, strlen(s));
|
||||||
|
bufferevent_write(cs->write_event, "\n", 1);
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write output from a pane. */
|
/* Write output from a pane. */
|
||||||
void
|
void
|
||||||
control_write_output(struct client *c, struct window_pane *wp)
|
control_write_output(struct client *c, struct window_pane *wp)
|
||||||
{
|
{
|
||||||
|
struct control_state *cs = c->control_state;
|
||||||
struct control_offset *co;
|
struct control_offset *co;
|
||||||
struct evbuffer *message;
|
struct evbuffer *message;
|
||||||
u_char *new_data;
|
u_char *new_data;
|
||||||
@ -165,11 +175,6 @@ control_write_output(struct client *c, struct window_pane *wp)
|
|||||||
|
|
||||||
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
|
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* Only write input if the window pane is linked to a window belonging
|
|
||||||
* to the client's session.
|
|
||||||
*/
|
|
||||||
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -193,15 +198,15 @@ control_write_output(struct client *c, struct window_pane *wp)
|
|||||||
else
|
else
|
||||||
evbuffer_add_printf(message, "%c", new_data[i]);
|
evbuffer_add_printf(message, "%c", new_data[i]);
|
||||||
}
|
}
|
||||||
evbuffer_add(message, "", 1);
|
evbuffer_add(message, "\n", 1);
|
||||||
|
|
||||||
control_write(c, "%s", EVBUFFER_DATA(message));
|
bufferevent_write_buffer(cs->write_event, message);
|
||||||
evbuffer_free(message);
|
evbuffer_free(message);
|
||||||
|
|
||||||
window_pane_update_used_data(wp, &co->offset, new_size, 1);
|
window_pane_update_used_data(wp, &co->offset, new_size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Control error callback. */
|
/* Control client error callback. */
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
control_error(struct cmdq_item *item, void *data)
|
control_error(struct cmdq_item *item, void *data)
|
||||||
{
|
{
|
||||||
@ -216,18 +221,27 @@ control_error(struct cmdq_item *item, void *data)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Control input callback. Read lines and fire commands. */
|
/* Control client error callback. */
|
||||||
static void
|
static void
|
||||||
control_callback(__unused struct client *c, __unused const char *path,
|
control_error_callback(__unused struct bufferevent *bufev,
|
||||||
int read_error, int closed, struct evbuffer *buffer, __unused void *data)
|
__unused short what, void *data)
|
||||||
{
|
{
|
||||||
|
struct client *c = data;
|
||||||
|
|
||||||
|
c->flags |= CLIENT_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Control client input callback. Read lines and fire commands. */
|
||||||
|
static void
|
||||||
|
control_read_callback(__unused struct bufferevent *bufev, void *data)
|
||||||
|
{
|
||||||
|
struct client *c = data;
|
||||||
|
struct control_state *cs = c->control_state;
|
||||||
|
struct evbuffer *buffer = cs->read_event->input;
|
||||||
char *line, *error;
|
char *line, *error;
|
||||||
struct cmdq_state *state;
|
struct cmdq_state *state;
|
||||||
enum cmd_parse_status status;
|
enum cmd_parse_status status;
|
||||||
|
|
||||||
if (closed || read_error != 0)
|
|
||||||
c->flags |= CLIENT_EXIT;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
|
line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
@ -255,13 +269,30 @@ control_start(struct client *c)
|
|||||||
{
|
{
|
||||||
struct control_state *cs;
|
struct control_state *cs;
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_CONTROLCONTROL) {
|
||||||
|
close(c->out_fd);
|
||||||
|
c->out_fd = -1;
|
||||||
|
} else
|
||||||
|
setblocking(c->out_fd, 0);
|
||||||
|
setblocking(c->fd, 0);
|
||||||
|
|
||||||
cs = c->control_state = xcalloc(1, sizeof *cs);
|
cs = c->control_state = xcalloc(1, sizeof *cs);
|
||||||
RB_INIT(&cs->offsets);
|
RB_INIT(&cs->offsets);
|
||||||
|
|
||||||
file_read(c, "-", control_callback, c);
|
cs->read_event = bufferevent_new(c->fd, control_read_callback, NULL,
|
||||||
|
control_error_callback, c);
|
||||||
|
bufferevent_enable(cs->read_event, EV_READ);
|
||||||
|
|
||||||
if (c->flags & CLIENT_CONTROLCONTROL)
|
if (c->flags & CLIENT_CONTROLCONTROL)
|
||||||
file_print(c, "\033P1000p");
|
cs->write_event = cs->read_event;
|
||||||
|
else {
|
||||||
|
cs->write_event = bufferevent_new(c->out_fd, NULL, NULL,
|
||||||
|
control_error_callback, c);
|
||||||
|
}
|
||||||
|
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_CONTROLCONTROL)
|
||||||
|
control_write(c, "\033P1000p");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop control mode. */
|
/* Stop control mode. */
|
||||||
@ -270,6 +301,10 @@ control_stop(struct client *c)
|
|||||||
{
|
{
|
||||||
struct control_state *cs = c->control_state;
|
struct control_state *cs = c->control_state;
|
||||||
|
|
||||||
|
if (~c->flags & CLIENT_CONTROLCONTROL)
|
||||||
|
bufferevent_free(cs->write_event);
|
||||||
|
bufferevent_free(cs->read_event);
|
||||||
|
|
||||||
control_free_offsets(c);
|
control_free_offsets(c);
|
||||||
free(cs);
|
free(cs);
|
||||||
}
|
}
|
||||||
|
8
file.c
8
file.c
@ -239,7 +239,9 @@ file_write(struct client *c, const char *path, int flags, const void *bdata,
|
|||||||
cf->path = xstrdup("-");
|
cf->path = xstrdup("-");
|
||||||
|
|
||||||
fd = STDOUT_FILENO;
|
fd = STDOUT_FILENO;
|
||||||
if (c == NULL || c->flags & CLIENT_ATTACHED) {
|
if (c == NULL ||
|
||||||
|
(c->flags & CLIENT_ATTACHED) ||
|
||||||
|
(c->flags & CLIENT_CONTROL)) {
|
||||||
cf->error = EBADF;
|
cf->error = EBADF;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -308,7 +310,9 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
|||||||
cf->path = xstrdup("-");
|
cf->path = xstrdup("-");
|
||||||
|
|
||||||
fd = STDIN_FILENO;
|
fd = STDIN_FILENO;
|
||||||
if (c == NULL || c->flags & CLIENT_ATTACHED) {
|
if (c == NULL ||
|
||||||
|
(c->flags & CLIENT_ATTACHED) ||
|
||||||
|
(c->flags & CLIENT_CONTROL)) {
|
||||||
cf->error = EBADF;
|
cf->error = EBADF;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
1
grid.c
1
grid.c
@ -496,7 +496,6 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
|
|||||||
gc->fg = gee->fg;
|
gc->fg = gee->fg;
|
||||||
gc->bg = gee->bg;
|
gc->bg = gee->bg;
|
||||||
gc->us = gee->us;
|
gc->us = gee->us;
|
||||||
log_debug("!!! %x", gc->flags);
|
|
||||||
utf8_to_data(gee->data, &gc->data);
|
utf8_to_data(gee->data, &gc->data);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -221,7 +221,7 @@ server_client_create(int fd)
|
|||||||
c->environ = environ_create();
|
c->environ = environ_create();
|
||||||
|
|
||||||
c->fd = -1;
|
c->fd = -1;
|
||||||
c->cwd = NULL;
|
c->out_fd = -1;
|
||||||
|
|
||||||
c->queue = cmdq_new();
|
c->queue = cmdq_new();
|
||||||
RB_INIT(&c->windows);
|
RB_INIT(&c->windows);
|
||||||
@ -336,6 +336,8 @@ server_client_lost(struct client *c)
|
|||||||
proc_remove_peer(c->peer);
|
proc_remove_peer(c->peer);
|
||||||
c->peer = NULL;
|
c->peer = NULL;
|
||||||
|
|
||||||
|
if (c->out_fd != -1)
|
||||||
|
close(c->out_fd);
|
||||||
if (c->fd != -1) {
|
if (c->fd != -1) {
|
||||||
close(c->fd);
|
close(c->fd);
|
||||||
c->fd = -1;
|
c->fd = -1;
|
||||||
@ -1571,10 +1573,9 @@ server_client_check_pane_buffer(struct window_pane *wp)
|
|||||||
out:
|
out:
|
||||||
/*
|
/*
|
||||||
* If there is data remaining, and there are no clients able to consume
|
* If there is data remaining, and there are no clients able to consume
|
||||||
* it, do not read any more. This is true when 1) there are attached
|
* it, do not read any more. This is true when there are attached
|
||||||
* clients 2) all the clients are control clients 3) all of them have
|
* clients, all of which are control clients which are not able to
|
||||||
* either the OFF flag set, or are otherwise not able to accept any
|
* accept any more data.
|
||||||
* more data for this pane.
|
|
||||||
*/
|
*/
|
||||||
if (off)
|
if (off)
|
||||||
bufferevent_disable(wp->event, EV_READ);
|
bufferevent_disable(wp->event, EV_READ);
|
||||||
@ -1967,6 +1968,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
|||||||
case MSG_IDENTIFY_TTYNAME:
|
case MSG_IDENTIFY_TTYNAME:
|
||||||
case MSG_IDENTIFY_CWD:
|
case MSG_IDENTIFY_CWD:
|
||||||
case MSG_IDENTIFY_STDIN:
|
case MSG_IDENTIFY_STDIN:
|
||||||
|
case MSG_IDENTIFY_STDOUT:
|
||||||
case MSG_IDENTIFY_ENVIRON:
|
case MSG_IDENTIFY_ENVIRON:
|
||||||
case MSG_IDENTIFY_CLIENTPID:
|
case MSG_IDENTIFY_CLIENTPID:
|
||||||
case MSG_IDENTIFY_DONE:
|
case MSG_IDENTIFY_DONE:
|
||||||
@ -2177,6 +2179,12 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
|||||||
c->fd = imsg->fd;
|
c->fd = imsg->fd;
|
||||||
log_debug("client %p IDENTIFY_STDIN %d", c, imsg->fd);
|
log_debug("client %p IDENTIFY_STDIN %d", c, imsg->fd);
|
||||||
break;
|
break;
|
||||||
|
case MSG_IDENTIFY_STDOUT:
|
||||||
|
if (datalen != 0)
|
||||||
|
fatalx("bad MSG_IDENTIFY_STDOUT size");
|
||||||
|
c->out_fd = imsg->fd;
|
||||||
|
log_debug("client %p IDENTIFY_STDOUT %d", c, imsg->fd);
|
||||||
|
break;
|
||||||
case MSG_IDENTIFY_ENVIRON:
|
case MSG_IDENTIFY_ENVIRON:
|
||||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||||
fatalx("bad MSG_IDENTIFY_ENVIRON string");
|
fatalx("bad MSG_IDENTIFY_ENVIRON string");
|
||||||
@ -2209,11 +2217,9 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
|||||||
c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
|
c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (c->flags & CLIENT_CONTROL) {
|
if (c->flags & CLIENT_CONTROL)
|
||||||
close(c->fd);
|
|
||||||
c->fd = -1;
|
|
||||||
control_start(c);
|
control_start(c);
|
||||||
} else if (c->fd != -1) {
|
else if (c->fd != -1) {
|
||||||
if (tty_init(&c->tty, c) != 0) {
|
if (tty_init(&c->tty, c) != 0) {
|
||||||
close(c->fd);
|
close(c->fd);
|
||||||
c->fd = -1;
|
c->fd = -1;
|
||||||
@ -2221,6 +2227,8 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
|||||||
tty_resize(&c->tty);
|
tty_resize(&c->tty);
|
||||||
c->flags |= CLIENT_TERMINAL;
|
c->flags |= CLIENT_TERMINAL;
|
||||||
}
|
}
|
||||||
|
close(c->out_fd);
|
||||||
|
c->out_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2337,7 +2345,8 @@ void
|
|||||||
server_client_set_flags(struct client *c, const char *flags)
|
server_client_set_flags(struct client *c, const char *flags)
|
||||||
{
|
{
|
||||||
char *s, *copy, *next;
|
char *s, *copy, *next;
|
||||||
int flag, not;
|
uint64_t flag;
|
||||||
|
int not;
|
||||||
|
|
||||||
s = copy = xstrdup (flags);
|
s = copy = xstrdup (flags);
|
||||||
while ((next = strsep(&s, ",")) != NULL) {
|
while ((next = strsep(&s, ",")) != NULL) {
|
||||||
|
5
status.c
5
status.c
@ -1275,7 +1275,10 @@ process_key:
|
|||||||
append_key:
|
append_key:
|
||||||
if (key <= 0x1f || key >= KEYC_BASE)
|
if (key <= 0x1f || key >= KEYC_BASE)
|
||||||
return (0);
|
return (0);
|
||||||
utf8_to_data(key, &tmp);
|
if (key <= 0x7f)
|
||||||
|
utf8_set(&tmp, key);
|
||||||
|
else
|
||||||
|
utf8_to_data(key, &tmp);
|
||||||
|
|
||||||
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 2,
|
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 2,
|
||||||
sizeof *c->prompt_buffer);
|
sizeof *c->prompt_buffer);
|
||||||
|
3
tmux.h
3
tmux.h
@ -500,6 +500,7 @@ enum msgtype {
|
|||||||
MSG_IDENTIFY_CLIENTPID,
|
MSG_IDENTIFY_CLIENTPID,
|
||||||
MSG_IDENTIFY_CWD,
|
MSG_IDENTIFY_CWD,
|
||||||
MSG_IDENTIFY_FEATURES,
|
MSG_IDENTIFY_FEATURES,
|
||||||
|
MSG_IDENTIFY_STDOUT,
|
||||||
|
|
||||||
MSG_COMMAND = 200,
|
MSG_COMMAND = 200,
|
||||||
MSG_DETACH,
|
MSG_DETACH,
|
||||||
@ -969,6 +970,7 @@ struct window_pane {
|
|||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
struct bufferevent *event;
|
struct bufferevent *event;
|
||||||
|
|
||||||
struct window_pane_offset offset;
|
struct window_pane_offset offset;
|
||||||
size_t base_offset;
|
size_t base_offset;
|
||||||
|
|
||||||
@ -1583,6 +1585,7 @@ struct client {
|
|||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int fd;
|
int fd;
|
||||||
|
int out_fd;
|
||||||
struct event event;
|
struct event event;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user