mirror of
https://github.com/tmux/tmux.git
synced 2025-09-03 14:27:09 +00:00
Merge branch 'obsd-master'
Conflicts: format.c window.c
This commit is contained in:
327
window.c
327
window.c
@ -55,15 +55,14 @@ struct windows windows;
|
||||
struct window_pane_tree all_window_panes;
|
||||
u_int next_window_pane_id;
|
||||
u_int next_window_id;
|
||||
|
||||
struct window_pane *window_pane_active_set(struct window_pane *,
|
||||
struct window_pane *);
|
||||
void window_pane_active_lost(struct window_pane *, struct window_pane *);
|
||||
u_int next_active_point;
|
||||
|
||||
void window_pane_timer_callback(int, short, void *);
|
||||
void window_pane_read_callback(struct bufferevent *, void *);
|
||||
void window_pane_error_callback(struct bufferevent *, short, void *);
|
||||
|
||||
struct window_pane *window_pane_choose_best(struct window_pane_list *);
|
||||
|
||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
|
||||
|
||||
int
|
||||
@ -307,7 +306,7 @@ window_create1(u_int sx, u_int sy)
|
||||
}
|
||||
|
||||
struct window *
|
||||
window_create(const char *name, const char *cmd, const char *path,
|
||||
window_create(const char *name, int argc, char **argv, const char *path,
|
||||
const char *shell, int cwd, struct environ *env, struct termios *tio,
|
||||
u_int sx, u_int sy, u_int hlimit, char **cause)
|
||||
{
|
||||
@ -318,7 +317,7 @@ window_create(const char *name, const char *cmd, const char *path,
|
||||
wp = window_add_pane(w, hlimit);
|
||||
layout_init(w, wp);
|
||||
|
||||
if (window_pane_spawn(wp, cmd, path, shell, cwd, env, tio,
|
||||
if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
|
||||
cause) != 0) {
|
||||
window_destroy(w);
|
||||
return (NULL);
|
||||
@ -386,64 +385,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
|
||||
w->sy = sy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore previously active pane when changing from wp to nextwp. The intended
|
||||
* pane is in nextwp and it returns the previously focused pane.
|
||||
*/
|
||||
struct window_pane *
|
||||
window_pane_active_set(struct window_pane *wp, struct window_pane *nextwp)
|
||||
{
|
||||
struct layout_cell *lc;
|
||||
struct window_pane *lastwp;
|
||||
|
||||
/* Target pane's parent must not be an ancestor of source pane. */
|
||||
for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
|
||||
if (lc == nextwp->layout_cell->parent)
|
||||
return (nextwp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Previously active pane, if any, must not be the same as the source
|
||||
* pane.
|
||||
*/
|
||||
lc = nextwp->layout_cell->parent;
|
||||
if (lc != NULL && lc->lastwp != NULL) {
|
||||
lastwp = lc->lastwp;
|
||||
if (lastwp != wp && window_pane_visible(lastwp))
|
||||
return (lastwp);
|
||||
}
|
||||
return (nextwp);
|
||||
}
|
||||
|
||||
/* Remember previously active pane when changing from wp to nextwp. */
|
||||
void
|
||||
window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp)
|
||||
{
|
||||
struct layout_cell *lc, *lc2, *lcparent;
|
||||
|
||||
/* Get the parent cell. */
|
||||
lcparent = nextwp->layout_cell->parent;
|
||||
if (lcparent == NULL)
|
||||
return;
|
||||
|
||||
/* Save the target pane in its parent. */
|
||||
lcparent->lastwp = nextwp;
|
||||
|
||||
/*
|
||||
* Save the source pane in all of its parents up to, but not including,
|
||||
* the common ancestor of itself and the target panes.
|
||||
*/
|
||||
if (wp == NULL)
|
||||
return;
|
||||
for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
|
||||
for (lc2 = lcparent; lc2 != NULL; lc2 = lc2->parent) {
|
||||
if (lc == lc2)
|
||||
return;
|
||||
}
|
||||
lc->lastwp = wp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_set_active_pane(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
@ -451,7 +392,6 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
|
||||
return;
|
||||
w->last = w->active;
|
||||
w->active = wp;
|
||||
window_pane_active_lost(w->last, wp);
|
||||
while (!window_pane_visible(w->active)) {
|
||||
w->active = TAILQ_PREV(w->active, window_panes, entry);
|
||||
if (w->active == NULL)
|
||||
@ -459,6 +399,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
|
||||
if (w->active == wp)
|
||||
return;
|
||||
}
|
||||
w->active->active_point = next_active_point++;
|
||||
}
|
||||
|
||||
struct window_pane *
|
||||
@ -736,7 +677,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
wp->id = next_window_pane_id++;
|
||||
RB_INSERT(window_pane_tree, &all_window_panes, wp);
|
||||
|
||||
wp->cmd = NULL;
|
||||
wp->argc = 0;
|
||||
wp->argv = NULL;
|
||||
wp->shell = NULL;
|
||||
wp->cwd = -1;
|
||||
|
||||
@ -770,16 +712,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
void
|
||||
window_pane_destroy(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
|
||||
/* Forget removed pane in all layout cells that remember it. */
|
||||
RB_FOREACH(wp2, window_pane_tree, &all_window_panes) {
|
||||
if (wp2->layout_cell != NULL &&
|
||||
wp2->layout_cell->parent != NULL &&
|
||||
wp2->layout_cell->parent->lastwp == wp)
|
||||
wp2->layout_cell->parent->lastwp = NULL;
|
||||
}
|
||||
|
||||
window_pane_reset_mode(wp);
|
||||
|
||||
if (event_initialized(&wp->changes_timer))
|
||||
@ -808,30 +740,32 @@ window_pane_destroy(struct window_pane *wp)
|
||||
|
||||
close(wp->cwd);
|
||||
free(wp->shell);
|
||||
free(wp->cmd);
|
||||
cmd_free_argv(wp->argc, wp->argv);
|
||||
free(wp);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
|
||||
const char *shell, int cwd, struct environ *env, struct termios *tio,
|
||||
char **cause)
|
||||
window_pane_spawn(struct window_pane *wp, int argc, char **argv,
|
||||
const char *path, const char *shell, int cwd, struct environ *env,
|
||||
struct termios *tio, char **cause)
|
||||
{
|
||||
struct winsize ws;
|
||||
char *argv0, paneid[16];
|
||||
const char *ptr;
|
||||
char *argv0, *cmd, **argvp, paneid[16];
|
||||
const char *ptr, *first;
|
||||
struct termios tio2;
|
||||
#ifdef HAVE_UTEMPTER
|
||||
char s[32];
|
||||
#endif
|
||||
int i;
|
||||
|
||||
if (wp->fd != -1) {
|
||||
bufferevent_free(wp->event);
|
||||
close(wp->fd);
|
||||
}
|
||||
if (cmd != NULL) {
|
||||
free(wp->cmd);
|
||||
wp->cmd = xstrdup(cmd);
|
||||
if (argc > 0) {
|
||||
cmd_free_argv(wp->argc, wp->argv);
|
||||
wp->argc = argc;
|
||||
wp->argv = cmd_copy_argv(argc, argv);
|
||||
}
|
||||
if (shell != NULL) {
|
||||
free(wp->shell);
|
||||
@ -842,7 +776,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
|
||||
wp->cwd = dup(cwd);
|
||||
}
|
||||
|
||||
log_debug("spawn: %s -- %s", wp->shell, wp->cmd);
|
||||
cmd = cmd_stringify_argv(wp->argc, wp->argv);
|
||||
log_debug("spawn: %s -- %s", wp->shell, cmd);
|
||||
for (i = 0; i < wp->argc; i++)
|
||||
log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
|
||||
|
||||
memset(&ws, 0, sizeof ws);
|
||||
ws.ws_col = screen_size_x(&wp->base);
|
||||
@ -852,6 +789,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
|
||||
case -1:
|
||||
wp->fd = -1;
|
||||
xasprintf(cause, "%s: %s", cmd, strerror(errno));
|
||||
free(cmd);
|
||||
return (-1);
|
||||
case 0:
|
||||
if (fchdir(wp->cwd) != 0)
|
||||
@ -883,22 +821,32 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
|
||||
setenv("SHELL", wp->shell, 1);
|
||||
ptr = strrchr(wp->shell, '/');
|
||||
|
||||
if (*wp->cmd != '\0') {
|
||||
/* Use the command. */
|
||||
/*
|
||||
* If given one argument, assume it should be passed to sh -c;
|
||||
* with more than one argument, use execvp(). If there is no
|
||||
* arguments, create a login shell.
|
||||
*/
|
||||
if (wp->argc > 0) {
|
||||
if (wp->argc != 1) {
|
||||
/* Copy to ensure argv ends in NULL. */
|
||||
argvp = cmd_copy_argv(wp->argc, wp->argv);
|
||||
execvp(argvp[0], argvp);
|
||||
fatal("execvp failed");
|
||||
}
|
||||
first = wp->argv[0];
|
||||
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
xasprintf(&argv0, "%s", ptr + 1);
|
||||
else
|
||||
xasprintf(&argv0, "%s", wp->shell);
|
||||
execl(wp->shell, argv0, "-c", wp->cmd, (char *) NULL);
|
||||
execl(wp->shell, argv0, "-c", first, (char *)NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
||||
/* No command; fork a login shell. */
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
xasprintf(&argv0, "-%s", ptr + 1);
|
||||
else
|
||||
xasprintf(&argv0, "-%s", wp->shell);
|
||||
execl(wp->shell, argv0, (char *) NULL);
|
||||
execl(wp->shell, argv0, (char *)NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
||||
@ -909,10 +857,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
|
||||
|
||||
setblocking(wp->fd, 0);
|
||||
|
||||
wp->event = bufferevent_new(wp->fd,
|
||||
window_pane_read_callback, NULL, window_pane_error_callback, wp);
|
||||
wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
|
||||
window_pane_error_callback, wp);
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
|
||||
free(cmd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1201,114 +1150,198 @@ window_pane_search(struct window_pane *wp, const char *searchstr,
|
||||
return (msg);
|
||||
}
|
||||
|
||||
/* Find the pane directly above another. */
|
||||
/* Get MRU pane from a list. */
|
||||
struct window_pane *
|
||||
window_pane_choose_best(struct window_pane_list *list)
|
||||
{
|
||||
struct window_pane *next, *best;
|
||||
u_int i;
|
||||
|
||||
if (ARRAY_LENGTH(list) == 0)
|
||||
return (NULL);
|
||||
|
||||
best = ARRAY_FIRST(list);
|
||||
for (i = 1; i < ARRAY_LENGTH(list); i++) {
|
||||
next = ARRAY_ITEM(list, i);
|
||||
if (next->active_point > best->active_point)
|
||||
best = next;
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pane directly above another. We build a list of those adjacent to
|
||||
* top edge and then choose the best.
|
||||
*/
|
||||
struct window_pane *
|
||||
window_pane_find_up(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, top;
|
||||
struct window_pane *next, *best;
|
||||
u_int edge, left, right, end;
|
||||
struct window_pane_list list;
|
||||
int found;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
ARRAY_INIT(&list);
|
||||
|
||||
edge = wp->yoff;
|
||||
if (edge == 0)
|
||||
edge = wp->window->sy + 1;
|
||||
|
||||
top = wp->yoff;
|
||||
if (top == 0)
|
||||
top = wp->window->sy + 1;
|
||||
left = wp->xoff;
|
||||
right = wp->xoff + wp->sx;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
TAILQ_FOREACH(next, &wp->window->panes, entry) {
|
||||
if (next == wp || !window_pane_visible(next))
|
||||
continue;
|
||||
if (wp2->yoff + wp2->sy + 1 != top)
|
||||
if (next->yoff + next->sy + 1 != edge)
|
||||
continue;
|
||||
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
|
||||
return (window_pane_active_set(wp, wp2));
|
||||
end = next->xoff + next->sx - 1;
|
||||
|
||||
found = 0;
|
||||
if (next->xoff < left && end > right)
|
||||
found = 1;
|
||||
else if (next->xoff >= left && next->xoff <= right)
|
||||
found = 1;
|
||||
else if (end >= left && end <= right)
|
||||
found = 1;
|
||||
if (found)
|
||||
ARRAY_ADD(&list, next);
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
best = window_pane_choose_best(&list);
|
||||
ARRAY_FREE(&list);
|
||||
return (best);
|
||||
}
|
||||
|
||||
/* Find the pane directly below another. */
|
||||
struct window_pane *
|
||||
window_pane_find_down(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, bottom;
|
||||
struct window_pane *next, *best;
|
||||
u_int edge, left, right, end;
|
||||
struct window_pane_list list;
|
||||
int found;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
ARRAY_INIT(&list);
|
||||
|
||||
edge = wp->yoff + wp->sy + 1;
|
||||
if (edge >= wp->window->sy)
|
||||
edge = 0;
|
||||
|
||||
bottom = wp->yoff + wp->sy + 1;
|
||||
if (bottom >= wp->window->sy)
|
||||
bottom = 0;
|
||||
left = wp->xoff;
|
||||
right = wp->xoff + wp->sx;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
TAILQ_FOREACH(next, &wp->window->panes, entry) {
|
||||
if (next == wp || !window_pane_visible(next))
|
||||
continue;
|
||||
if (wp2->yoff != bottom)
|
||||
if (next->yoff != edge)
|
||||
continue;
|
||||
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
|
||||
return (window_pane_active_set(wp, wp2));
|
||||
end = next->xoff + next->sx - 1;
|
||||
|
||||
found = 0;
|
||||
if (next->xoff < left && end > right)
|
||||
found = 1;
|
||||
else if (next->xoff >= left && next->xoff <= right)
|
||||
found = 1;
|
||||
else if (end >= left && end <= right)
|
||||
found = 1;
|
||||
if (found)
|
||||
ARRAY_ADD(&list, next);
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
best = window_pane_choose_best(&list);
|
||||
ARRAY_FREE(&list);
|
||||
return (best);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pane directly to the left of another, adjacent to the left side and
|
||||
* containing the top edge.
|
||||
*/
|
||||
/* Find the pane directly to the left of another. */
|
||||
struct window_pane *
|
||||
window_pane_find_left(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, top;
|
||||
struct window_pane *next, *best;
|
||||
u_int edge, top, bottom, end;
|
||||
struct window_pane_list list;
|
||||
int found;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
ARRAY_INIT(&list);
|
||||
|
||||
edge = wp->xoff;
|
||||
if (edge == 0)
|
||||
edge = wp->window->sx + 1;
|
||||
|
||||
left = wp->xoff;
|
||||
if (left == 0)
|
||||
left = wp->window->sx + 1;
|
||||
top = wp->yoff;
|
||||
bottom = wp->yoff + wp->sy;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
TAILQ_FOREACH(next, &wp->window->panes, entry) {
|
||||
if (next == wp || !window_pane_visible(next))
|
||||
continue;
|
||||
if (wp2->xoff + wp2->sx + 1 != left)
|
||||
if (next->xoff + next->sx + 1 != edge)
|
||||
continue;
|
||||
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
|
||||
return (window_pane_active_set(wp, wp2));
|
||||
end = next->yoff + next->sy - 1;
|
||||
|
||||
found = 0;
|
||||
if (next->yoff < top && end > bottom)
|
||||
found = 1;
|
||||
else if (next->yoff >= top && next->yoff <= bottom)
|
||||
found = 1;
|
||||
else if (end >= top && end <= bottom)
|
||||
found = 1;
|
||||
if (found)
|
||||
ARRAY_ADD(&list, next);
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
best = window_pane_choose_best(&list);
|
||||
ARRAY_FREE(&list);
|
||||
return (best);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pane directly to the right of another, that is adjacent to the
|
||||
* right edge and including the top edge.
|
||||
*/
|
||||
/* Find the pane directly to the right of another. */
|
||||
struct window_pane *
|
||||
window_pane_find_right(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int right, top;
|
||||
struct window_pane *next, *best;
|
||||
u_int edge, top, bottom, end;
|
||||
struct window_pane_list list;
|
||||
int found;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
ARRAY_INIT(&list);
|
||||
|
||||
edge = wp->xoff + wp->sx + 1;
|
||||
if (edge >= wp->window->sx)
|
||||
edge = 0;
|
||||
|
||||
right = wp->xoff + wp->sx + 1;
|
||||
if (right >= wp->window->sx)
|
||||
right = 0;
|
||||
top = wp->yoff;
|
||||
bottom = wp->yoff + wp->sy;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
TAILQ_FOREACH(next, &wp->window->panes, entry) {
|
||||
if (next == wp || !window_pane_visible(next))
|
||||
continue;
|
||||
if (wp2->xoff != right)
|
||||
if (next->xoff != edge)
|
||||
continue;
|
||||
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
|
||||
return (window_pane_active_set(wp, wp2));
|
||||
end = next->yoff + next->sy - 1;
|
||||
|
||||
found = 0;
|
||||
if (next->yoff < top && end > bottom)
|
||||
found = 1;
|
||||
else if (next->yoff >= top && next->yoff <= bottom)
|
||||
found = 1;
|
||||
else if (end >= top && end <= bottom)
|
||||
found = 1;
|
||||
if (found)
|
||||
ARRAY_ADD(&list, next);
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
best = window_pane_choose_best(&list);
|
||||
ARRAY_FREE(&list);
|
||||
return (best);
|
||||
}
|
||||
|
||||
/* Clear alert flags for a winlink */
|
||||
|
Reference in New Issue
Block a user