mirror of
https://github.com/tmux/tmux.git
synced 2026-10-14 15:04:50 +00:00
Merge branch 'master' into floating_panes
This commit is contained in:
352
window.c
352
window.c
@@ -71,6 +71,7 @@ struct window_pane_input_data {
|
||||
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
|
||||
u_int);
|
||||
static void window_pane_destroy(struct window_pane *);
|
||||
static void window_pane_scrollbar_timer(int, short, void *);
|
||||
static void window_pane_full_size_offset(struct window_pane *wp,
|
||||
int *xoff, int *yoff, u_int *sx, u_int *sy);
|
||||
|
||||
@@ -78,6 +79,14 @@ RB_GENERATE(windows, window, entry, window_cmp);
|
||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
|
||||
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
|
||||
|
||||
struct window_pane_prompt {
|
||||
u_int wp_id;
|
||||
struct client *c;
|
||||
status_prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int
|
||||
window_cmp(struct window *w1, struct window *w2)
|
||||
{
|
||||
@@ -411,11 +420,11 @@ window_remove_ref(struct window *w, const char *from)
|
||||
}
|
||||
|
||||
void
|
||||
window_set_name(struct window *w, const char *new_name, const char *forbid)
|
||||
window_set_name(struct window *w, const char *new_name, int untrusted)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = clean_name(new_name, forbid);
|
||||
name = clean_name(new_name, untrusted);
|
||||
if (name != NULL) {
|
||||
free(w->name);
|
||||
w->name = name;
|
||||
@@ -635,6 +644,7 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
redraw_invalidate_scene(w);
|
||||
}
|
||||
|
||||
wp = w->active;
|
||||
@@ -772,6 +782,7 @@ window_zoom(struct window_pane *wp)
|
||||
w->flags |= WINDOW_ZOOMED;
|
||||
notify_window("window-layout-changed", w);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -798,6 +809,7 @@ window_unzoom(struct window *w, int notify)
|
||||
if (notify)
|
||||
notify_window("window-layout-changed", w);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -854,6 +866,7 @@ window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
|
||||
else {
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
@@ -895,6 +908,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
notify_window("window-pane-changed", w);
|
||||
window_update_focus(w);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -903,6 +917,7 @@ window_remove_pane(struct window *w, struct window_pane *wp)
|
||||
window_lost_pane(w, wp);
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
redraw_invalidate_scene(w);
|
||||
window_pane_destroy(wp);
|
||||
}
|
||||
|
||||
@@ -1126,6 +1141,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
|
||||
screen_init(&wp->status_screen, 1, 1, 0);
|
||||
style_ranges_init(&wp->border_status_line.ranges);
|
||||
evtimer_set(&wp->sb_auto_timer, window_pane_scrollbar_timer, wp);
|
||||
|
||||
if (gethostname(host, sizeof host) == 0)
|
||||
screen_set_title(&wp->base, host, 0);
|
||||
@@ -1157,13 +1173,71 @@ window_pane_wait_finish(struct window_pane *wp)
|
||||
cmdq_continue(item);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_free_modes(struct window_pane *wp)
|
||||
{
|
||||
struct window_mode_entry *wme;
|
||||
|
||||
while (!TAILQ_EMPTY(&wp->modes)) {
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
TAILQ_REMOVE(&wp->modes, wme, entry);
|
||||
wme->mode->free(wme);
|
||||
free(wme);
|
||||
}
|
||||
|
||||
wp->screen = &wp->base;
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_scrollbar_timer(__unused int fd, __unused short events, void *arg)
|
||||
{
|
||||
struct window_pane *wp = arg;
|
||||
|
||||
wp->sb_auto_hover = 0;
|
||||
window_pane_scrollbar_hide(wp);
|
||||
}
|
||||
|
||||
static int
|
||||
window_pane_scrollbar_auto_hide(struct window_pane *wp)
|
||||
{
|
||||
return (wp->window->sb == PANE_SCROLLBARS_MODAL ||
|
||||
wp->window->sb == PANE_SCROLLBARS_AUTOHIDE);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_overlay_visible(struct window_pane *wp)
|
||||
{
|
||||
return (window_pane_scrollbar_overlay(wp) &&
|
||||
window_pane_scrollbar_visible(wp));
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_redraw(struct window_pane *wp)
|
||||
{
|
||||
if (window_pane_scrollbar_overlay_visible(wp)) {
|
||||
wp->flags |= PANE_REDRAW;
|
||||
return;
|
||||
}
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_scrollbar_redraw_visibility(struct window_pane *wp)
|
||||
{
|
||||
redraw_invalidate_scene(wp->window);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_destroy(struct window_pane *wp)
|
||||
{
|
||||
window_pane_wait_finish(wp);
|
||||
spawn_editor_finish(wp);
|
||||
|
||||
window_pane_reset_mode_all(wp);
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
window_pane_free_modes(wp);
|
||||
free(wp->searchstr);
|
||||
|
||||
if (wp->fd != -1) {
|
||||
@@ -1190,6 +1264,8 @@ window_pane_destroy(struct window_pane *wp)
|
||||
event_del(&wp->resize_timer);
|
||||
if (event_initialized(&wp->sync_timer))
|
||||
event_del(&wp->sync_timer);
|
||||
if (event_initialized(&wp->sb_auto_timer))
|
||||
event_del(&wp->sb_auto_timer);
|
||||
window_pane_clear_resizes(wp, NULL);
|
||||
|
||||
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
|
||||
@@ -1259,7 +1335,8 @@ window_pane_set_event(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_clear_resizes(struct window_pane *wp, struct window_pane_resize *except)
|
||||
window_pane_clear_resizes(struct window_pane *wp,
|
||||
struct window_pane_resize *except)
|
||||
{
|
||||
struct window_pane_resize *r, *r1;
|
||||
|
||||
@@ -1379,6 +1456,7 @@ window_pane_reset_mode(struct window_pane *wp)
|
||||
server_kill_pane(wp);
|
||||
}
|
||||
|
||||
/* Reset all modes. */
|
||||
void
|
||||
window_pane_reset_mode_all(struct window_pane *wp)
|
||||
{
|
||||
@@ -1386,6 +1464,165 @@ window_pane_reset_mode_all(struct window_pane *wp)
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
|
||||
/* Prompt input callback. */
|
||||
static enum prompt_result
|
||||
window_pane_prompt_input_callback(void *data, const char *s,
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
|
||||
if (wpp->inputcb != NULL)
|
||||
return (wpp->inputcb(wpp->c, wpp->data, s, key));
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
/* Prompt free callback. */
|
||||
static void
|
||||
window_pane_prompt_free_callback(void *data)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
struct window_pane *wp;
|
||||
|
||||
wp = window_pane_find_by_id(wpp->wp_id);
|
||||
if (wp != NULL && wp->prompt_data == wpp)
|
||||
wp->prompt_data = NULL;
|
||||
if (wpp->freecb != NULL)
|
||||
wpp->freecb(wpp->data);
|
||||
free(wpp);
|
||||
}
|
||||
|
||||
/* Open a prompt owned by a pane, drawn over the pane instead of the status. */
|
||||
void
|
||||
window_pane_set_prompt(struct window_pane *wp, struct client *c,
|
||||
struct cmd_find_state *fs, const char *msg, const char *input,
|
||||
status_prompt_input_cb inputcb, prompt_free_cb freecb, void *data,
|
||||
int flags, enum prompt_type type)
|
||||
{
|
||||
struct session *s = NULL;
|
||||
struct prompt_create_data pd;
|
||||
struct window_pane_prompt *wpp;
|
||||
|
||||
if (c != NULL)
|
||||
s = c->session;
|
||||
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
wpp = xcalloc(1, sizeof *wpp);
|
||||
wpp->wp_id = wp->id;
|
||||
wpp->c = c;
|
||||
wpp->inputcb = inputcb;
|
||||
wpp->freecb = freecb;
|
||||
wpp->data = data;
|
||||
|
||||
memset(&pd, 0, sizeof pd);
|
||||
prompt_set_options(&pd, s);
|
||||
pd.fs = fs;
|
||||
pd.prompt = msg;
|
||||
pd.input = input;
|
||||
pd.type = type;
|
||||
pd.flags = flags;
|
||||
pd.inputcb = window_pane_prompt_input_callback;
|
||||
pd.freecb = window_pane_prompt_free_callback;
|
||||
pd.data = wpp;
|
||||
|
||||
wp->prompt = prompt_create(&pd);
|
||||
wp->prompt_data = wpp;
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
prompt_incremental_start(wp->prompt);
|
||||
}
|
||||
|
||||
/* Close a pane prompt. */
|
||||
void
|
||||
window_pane_clear_prompt(struct window_pane *wp)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
|
||||
if (prompt == NULL)
|
||||
return;
|
||||
wp->prompt = NULL;
|
||||
prompt_free(prompt);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
/* Does this pane have an open prompt? */
|
||||
int
|
||||
window_pane_has_prompt(struct window_pane *wp)
|
||||
{
|
||||
return (wp->prompt != NULL);
|
||||
}
|
||||
|
||||
/* Replace the message and input of an open pane prompt. */
|
||||
void
|
||||
window_pane_update_prompt(struct window_pane *wp, const char *msg,
|
||||
const char *input)
|
||||
{
|
||||
if (wp->prompt != NULL) {
|
||||
prompt_update(wp->prompt, msg, input);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a key to a pane prompt. The client is set transiently for the duration
|
||||
* of the key in case the prompt or pane is destroyed by the callback.
|
||||
*/
|
||||
enum prompt_key_result
|
||||
window_pane_prompt_key(struct window_pane *wp, struct client *c, key_code key,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
struct window_pane_prompt *wpp = wp->prompt_data;
|
||||
enum prompt_key_result result;
|
||||
u_int wp_id = wp->id, x, y, py;
|
||||
int redraw = 0;
|
||||
|
||||
if (prompt == NULL)
|
||||
return (PROMPT_KEY_NOT_HANDLED);
|
||||
|
||||
if (wpp != NULL)
|
||||
wpp->c = c;
|
||||
if (KEYC_IS_MOUSE(key)) {
|
||||
if (m == NULL ||
|
||||
MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1 ||
|
||||
MOUSE_DRAG(m->b) ||
|
||||
MOUSE_RELEASE(m->b) ||
|
||||
cmd_mouse_at(wp, m, &x, &y, 0) != 0)
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
else {
|
||||
if (c != NULL && status_at_line(c) == 0)
|
||||
py = 0;
|
||||
else
|
||||
py = wp->sy - 1;
|
||||
if (y == py) {
|
||||
result = prompt_mouse(prompt, x, 0, wp->sx,
|
||||
&redraw);
|
||||
} else
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
}
|
||||
} else
|
||||
result = prompt_key(prompt, key, &redraw);
|
||||
|
||||
wp = window_pane_find_by_id(wp_id);
|
||||
if (wp == NULL)
|
||||
return (result);
|
||||
if (wpp != NULL && wp->prompt_data == wpp)
|
||||
wpp->c = NULL;
|
||||
|
||||
/*
|
||||
* Only an explicit close or the prompt marking itself closed ends it;
|
||||
* cursor movement and editing keep it open.
|
||||
*/
|
||||
if (wp->prompt == prompt &&
|
||||
(result == PROMPT_KEY_CLOSE || prompt_closed(prompt)))
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
if (redraw || wp->prompt != prompt)
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len)
|
||||
{
|
||||
@@ -1450,6 +1687,12 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
|
||||
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme != NULL) {
|
||||
/*
|
||||
* No mode uses mouse motion events, so drop them here rather
|
||||
* than passing them on and causing a redraw on every movement.
|
||||
*/
|
||||
if (KEYC_IS_TYPE(key, KEYC_TYPE_MOUSEMOVE))
|
||||
return (0);
|
||||
if (wme->mode->key != NULL && c != NULL) {
|
||||
key &= ~KEYC_MASK_FLAGS;
|
||||
wme->mode->key(wme, c, s, wl, key, m);
|
||||
@@ -1563,17 +1806,13 @@ window_pane_full_size_offset(struct window_pane *wp, int *xoff, int *yoff,
|
||||
u_int *sx, u_int *sy)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
int pane_scrollbars;
|
||||
u_int sb_w, sb_pos;
|
||||
u_int sb_w;
|
||||
|
||||
pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
|
||||
if (window_pane_show_scrollbar(wp, pane_scrollbars))
|
||||
if (window_pane_scrollbar_reserve(wp))
|
||||
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
else
|
||||
sb_w = 0;
|
||||
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
*xoff = wp->xoff - sb_w;
|
||||
*sx = wp->sx + sb_w;
|
||||
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
|
||||
@@ -1989,19 +2228,93 @@ window_pane_mode(struct window_pane *wp)
|
||||
return (WINDOW_PANE_NO_MODE);
|
||||
}
|
||||
|
||||
/* Return 1 if scrollbar is or should be displayed. */
|
||||
int
|
||||
window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
|
||||
window_pane_show_scrollbar(struct window_pane *wp)
|
||||
{
|
||||
if (SCREEN_IS_ALTERNATE(&wp->base))
|
||||
return (0);
|
||||
if (sb_option == PANE_SCROLLBARS_ALWAYS ||
|
||||
(sb_option == PANE_SCROLLBARS_MODAL &&
|
||||
if (wp->window->sb == PANE_SCROLLBARS_ALWAYS ||
|
||||
wp->window->sb == PANE_SCROLLBARS_AUTOHIDE ||
|
||||
(wp->window->sb == PANE_SCROLLBARS_MODAL &&
|
||||
window_pane_mode(wp) != WINDOW_PANE_NO_MODE))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_reserve(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
return (wp->window->sb == PANE_SCROLLBARS_ALWAYS);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_overlay(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
return (window_pane_scrollbar_auto_hide(wp));
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_visible(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
if (!window_pane_scrollbar_auto_hide(wp))
|
||||
return (1);
|
||||
return (wp->sb_auto_visible);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_start_timer(struct window_pane *wp)
|
||||
{
|
||||
struct timeval tv;
|
||||
u_int delay;
|
||||
|
||||
if (!window_pane_scrollbar_auto_hide(wp) || !wp->sb_auto_visible)
|
||||
return;
|
||||
|
||||
delay = options_get_number(wp->window->options,
|
||||
"pane-scrollbars-timeout");
|
||||
tv.tv_sec = delay / 1000;
|
||||
tv.tv_usec = (delay % 1000) * 1000L;
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
evtimer_add(&wp->sb_auto_timer, &tv);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_show(struct window_pane *wp, int start_timer)
|
||||
{
|
||||
int changed = 0;
|
||||
if (!window_pane_scrollbar_auto_hide(wp))
|
||||
return;
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return;
|
||||
if (!wp->sb_auto_visible) {
|
||||
wp->sb_auto_visible = 1;
|
||||
changed = 1;
|
||||
}
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
if (start_timer)
|
||||
window_pane_scrollbar_start_timer(wp);
|
||||
if (changed)
|
||||
window_pane_scrollbar_redraw_visibility(wp);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_hide(struct window_pane *wp)
|
||||
{
|
||||
if (event_initialized(&wp->sb_auto_timer))
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
wp->sb_auto_hover = 0;
|
||||
if (!wp->sb_auto_visible)
|
||||
return;
|
||||
wp->sb_auto_visible = 0;
|
||||
window_pane_scrollbar_redraw_visibility(wp);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_get_bg(struct window_pane *wp)
|
||||
{
|
||||
@@ -2202,6 +2515,15 @@ window_pane_status_get_range(struct window_pane *wp, u_int x, u_int y)
|
||||
return (style_ranges_get_range(srs, x - wp->xoff - 2));
|
||||
}
|
||||
|
||||
enum pane_lines
|
||||
window_get_pane_lines(struct window *w)
|
||||
{
|
||||
struct options *oo;
|
||||
|
||||
oo = w->options;
|
||||
return (options_get_number(oo, "pane-border-lines"));
|
||||
}
|
||||
|
||||
enum pane_lines
|
||||
window_pane_get_pane_lines(struct window_pane *wp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user