Compare commits

...

29 Commits

Author SHA1 Message Date
Michael Grant
2f7429c556
Merge 76b8ee08ef244537c4050bb99346a550c7d5222d into 7e439539377e272f37d18bb10dbff374b87acee6 2025-07-02 22:29:03 +02:00
Thomas Adam
7e43953937 Merge branch 'obsd-master' 2025-07-02 12:01:08 +01:00
nicm
28481e984b Add sorting to W, P, L operators as well, and add some new session
format variables. From Michael Grant in GitHub issue 4516.
2025-07-02 08:13:09 +00:00
Michael Grant
76b8ee08ef
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-06-16 16:56:26 -04:00
Michael Grant
b9d7771f2a
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-05-15 01:57:02 -04:00
Michael Grant
c22a60e412 Only redraw the whole window if the menu was closed, otherwise the user will see flashing when the mouse moves. 2025-05-06 10:52:48 +02:00
Michael Grant
b9222a6613 A better fix. 2025-05-06 06:56:26 +02:00
Michael Grant
71a7206e8b Merge branch 'non-blocking-popup-windows' of github.com:mgrant0/tmux into non-blocking-popup-windows 2025-05-05 22:19:36 +02:00
Michael Grant
eb3867d02e Fix bug if pane is focused and its menu is open that it does not change focus to the overlay popup if the mouse moves over that rectangle area. 2025-05-05 22:18:27 +02:00
Michael Grant
4ac0c79d8e
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-05-04 07:42:10 -04:00
Michael Grant
2bae40ec7e Move window menu out of overlay into window struct. 2025-04-17 15:10:33 +01:00
Michael Grant
fe3ed1d7a8
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-04-17 08:50:54 -04:00
Michael Grant
f11fa9d7f0 Check for right mouse button if pane is focused, let pane handle it. 2025-04-05 15:48:27 +01:00
Michael Grant
e7bc34df3d fix segv when overlay_check is null 2025-04-05 15:44:22 +01:00
Michael Grant
9327991d8b
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-04-04 05:01:51 -04:00
Michael Grant
5001c8148a To fix a race condition by inhibitting it from calling popup_free_cb twice 2025-04-03 14:12:45 +01:00
Michael Grant
f755a007fa update man page 2025-04-01 17:41:26 +01:00
Michael Grant
4b545ac620
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-03-31 10:52:31 -04:00
Michael Grant
5091236d4d skip foreach loop if done 2025-03-29 23:04:14 +00:00
Michael Grant
7fa11dcd24 -D arg to enable do not block 2025-03-29 22:47:49 +00:00
Michael Grant
6ab507c9ce rename CLIENT_OVERLAYPOPUP_FOCUSED to CLIENT_OVERLAYFOCUSED 2025-03-27 14:34:35 +00:00
Michael Grant
f6818a097f
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-03-26 12:53:30 -04:00
Michael Grant
0a0e9852a2 Add overlay check to scrollbar code to prevent scrollbars obscured by an overlay from flashing while being dragged around. 2025-03-12 15:44:04 -04:00
Michael Grant
c0ff4831fc Add check to check if cursor is behind the overlay popup. 2025-03-12 15:34:48 -04:00
Michael Grant
5327f39134 Try 2. Move popup focus flag into client struct. 2025-03-12 13:52:17 -04:00
Michael Grant
66bf623259
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-03-11 14:29:42 -04:00
Michael Grant
616143ea31
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-03-04 15:20:12 -05:00
Michael Grant
43c947c348
Merge branch 'tmux:master' into non-blocking-popup-windows 2025-02-22 13:47:03 -05:00
Michael Grant
41ef18debb initial commit 2025-01-19 16:20:14 -04:00
10 changed files with 486 additions and 56 deletions

View File

@ -54,7 +54,7 @@ const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
.args = { "Bb:Cc:Dd:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
.usage = "[-BCE] [-b border-lines] [-c target-client] "
"[-d start-directory] [-e environment] [-h height] "
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
@ -301,7 +301,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
struct options_entry *oe;
if (tc->overlay_draw != NULL)
if ((tc->overlay_draw != NULL) && (tc->flags & CLIENT_OVERLAYFOCUSED))
return (CMD_RETURN_NORMAL);
if (args_has(args, 'C')) {
@ -484,6 +484,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
flags |= POPUP_CLOSEEXITZERO;
else if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (args_has(args, 'D'))
item = NULL;
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
cmd_free_argv(argc, argv);
@ -498,5 +500,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
free(cwd);
free(title);
cmd_free_argv(argc, argv);
return (CMD_RETURN_WAIT);
if (args_has(args, 'D'))
return (CMD_RETURN_NORMAL);
else
return (CMD_RETURN_WAIT);
}

371
format.c
View File

@ -140,8 +140,8 @@ enum format_loop_sort_type {
};
static struct format_loop_sort_criteria {
u_int field;
int reversed;
enum format_loop_sort_type field;
int reversed;
} format_loop_sort_criteria;
struct format_tree {
@ -554,6 +554,38 @@ format_cb_session_attached_list(struct format_tree *ft)
return (value);
}
/* Callback for session_alert. */
static void *
format_cb_session_alert(struct format_tree *ft)
{
struct session *s = ft->s;
struct winlink *wl;
char alerts[1024];
int alerted = 0;
if (s == NULL)
return (NULL);
*alerts = '\0';
RB_FOREACH(wl, winlinks, &s->windows) {
if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
continue;
if (~alerted & wl->flags & WINLINK_ACTIVITY) {
strlcat(alerts, "#", sizeof alerts);
alerted |= WINLINK_ACTIVITY;
}
if (~alerted & wl->flags & WINLINK_BELL) {
strlcat(alerts, "!", sizeof alerts);
alerted |= WINLINK_BELL;
}
if (~alerted & wl->flags & WINLINK_SILENCE) {
strlcat(alerts, "~", sizeof alerts);
alerted |= WINLINK_SILENCE;
}
}
return (xstrdup(alerts));
}
/* Callback for session_alerts. */
static void *
format_cb_session_alerts(struct format_tree *ft)
@ -1743,6 +1775,15 @@ format_cb_keypad_flag(struct format_tree *ft)
return (NULL);
}
/* Callback for loop_last_flag. */
static void *
format_cb_loop_last_flag(struct format_tree *ft)
{
if (ft->flags & FORMAT_LAST)
return (xstrdup("1"));
return (xstrdup("0"));
}
/* Callback for mouse_all_flag. */
static void *
format_cb_mouse_all_flag(struct format_tree *ft)
@ -2264,6 +2305,66 @@ format_cb_server_sessions(__unused struct format_tree *ft)
return (format_printf("%u", n));
}
/* Callback for session_active. */
static void *
format_cb_session_active(struct format_tree *ft)
{
if (ft->s == NULL || ft->c == NULL)
return (NULL);
if (ft->c->session == ft->s)
return (xstrdup("1"));
return (xstrdup("0"));
}
/* Callback for session_activity_flag. */
static void *
format_cb_session_activity_flag(struct format_tree *ft)
{
struct winlink *wl;
if (ft->s != NULL) {
RB_FOREACH(wl, winlinks, &ft->s->windows) {
if (ft->wl->flags & WINLINK_ACTIVITY)
return (xstrdup("1"));
return (xstrdup("0"));
}
}
return (NULL);
}
/* Callback for session_bell_flag. */
static void *
format_cb_session_bell_flag(struct format_tree *ft)
{
struct winlink *wl;
if (ft->s != NULL) {
RB_FOREACH(wl, winlinks, &ft->s->windows) {
if (wl->flags & WINLINK_BELL)
return (xstrdup("1"));
return (xstrdup("0"));
}
}
return (NULL);
}
/* Callback for session_silence_flag. */
static void *
format_cb_session_silence_flag(struct format_tree *ft)
{
struct winlink *wl;
if (ft->s != NULL) {
RB_FOREACH(wl, winlinks, &ft->s->windows) {
if (ft->wl->flags & WINLINK_SILENCE)
return (xstrdup("1"));
return (xstrdup("0"));
}
}
return (NULL);
}
/* Callback for session_attached. */
static void *
format_cb_session_attached(struct format_tree *ft)
@ -3054,6 +3155,9 @@ static const struct format_table_entry format_table[] = {
{ "last_window_index", FORMAT_TABLE_STRING,
format_cb_last_window_index
},
{ "loop_last_flag", FORMAT_TABLE_STRING,
format_cb_loop_last_flag
},
{ "mouse_all_flag", FORMAT_TABLE_STRING,
format_cb_mouse_all_flag
},
@ -3234,9 +3338,18 @@ static const struct format_table_entry format_table[] = {
{ "server_sessions", FORMAT_TABLE_STRING,
format_cb_server_sessions
},
{ "session_active", FORMAT_TABLE_STRING,
format_cb_session_active
},
{ "session_activity", FORMAT_TABLE_TIME,
format_cb_session_activity
},
{ "session_activity_flag", FORMAT_TABLE_STRING,
format_cb_session_activity_flag
},
{ "session_alert", FORMAT_TABLE_STRING,
format_cb_session_alert
},
{ "session_alerts", FORMAT_TABLE_STRING,
format_cb_session_alerts
},
@ -3246,6 +3359,9 @@ static const struct format_table_entry format_table[] = {
{ "session_attached_list", FORMAT_TABLE_STRING,
format_cb_session_attached_list
},
{ "session_bell_flag", FORMAT_TABLE_STRING,
format_cb_session_bell_flag
},
{ "session_created", FORMAT_TABLE_TIME,
format_cb_session_created
},
@ -3291,6 +3407,9 @@ static const struct format_table_entry format_table[] = {
{ "session_path", FORMAT_TABLE_STRING,
format_cb_session_path
},
{ "session_silence_flag", FORMAT_TABLE_STRING,
format_cb_session_silence_flag
},
{ "session_stack", FORMAT_TABLE_STRING,
format_cb_session_stack
},
@ -4044,7 +4163,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
}
/* Now try single character with arguments. */
if (strchr("mCNSst=pReq", cp[0]) == NULL)
if (strchr("mCLNPSst=pReqW", cp[0]) == NULL)
break;
c = cp[0];
@ -4243,13 +4362,14 @@ format_session_name(struct format_expand_state *es, const char *fmt)
static int
format_cmp_session(const void *a0, const void *b0)
{
const struct session *const *a = a0;
const struct session *const *b = b0;
const struct session *sa = *a;
const struct session *sb = *b;
int result = 0;
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
const struct session *const *a = a0;
const struct session *const *b = b0;
const struct session *sa = *a;
const struct session *sb = *b;
int result = 0;
switch (format_loop_sort_criteria.field) {
switch (sc->field) {
case FORMAT_LOOP_BY_INDEX:
result = sa->id - sb->id;
break;
@ -4268,7 +4388,7 @@ format_cmp_session(const void *a0, const void *b0)
break;
}
if (format_loop_sort_criteria.reversed)
if (sc->reversed)
result = -result;
return (result);
}
@ -4285,7 +4405,7 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
char *all, *active, *use, *expanded, *value;
size_t valuelen;
struct session *s;
int i, n;
int i, n, last = 0;
static struct session **l = NULL;
static int lsz = 0;
@ -4315,7 +4435,9 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
use = active;
else
use = all;
nft = format_create(c, item, FORMAT_NONE, ft->flags);
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, FORMAT_NONE, ft->flags|last);
format_defaults(nft, ft->c, s, NULL, NULL);
format_copy_state(&next, es, 0);
next.ft = nft;
@ -4356,6 +4478,40 @@ format_window_name(struct format_expand_state *es, const char *fmt)
return (xstrdup("0"));
}
static int
format_cmp_window(const void *a0, const void *b0)
{
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
const struct winlink *const *a = a0;
const struct winlink *const *b = b0;
const struct window *wa = (*a)->window;
const struct window *wb = (*b)->window;
int result = 0;
switch (sc->field) {
case FORMAT_LOOP_BY_INDEX:
result = wa->id - wb->id;
break;
case FORMAT_LOOP_BY_TIME:
if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
result = -1;
break;
}
if (timercmp(&wa->activity_time, &wb->activity_time, <)) {
result = 1;
break;
}
/* FALLTHROUGH */
case FORMAT_LOOP_BY_NAME:
result = strcmp(wa->name, wb->name);
break;
}
if (sc->reversed)
result = -result;
return (result);
}
/* Loop over windows. */
static char *
format_loop_windows(struct format_expand_state *es, const char *fmt)
@ -4369,6 +4525,9 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
size_t valuelen;
struct winlink *wl;
struct window *w;
int i, n, last = 0;
static struct winlink **l = NULL;
static int lsz = 0;
if (ft->s == NULL) {
format_log(es, "window loop but no session");
@ -4380,17 +4539,32 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
active = NULL;
}
n = 0;
RB_FOREACH(wl, winlinks, &ft->s->windows) {
if (lsz <= n) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[n++] = wl;
}
qsort(l, n, sizeof *l, format_cmp_window);
value = xcalloc(1, 1);
valuelen = 1;
RB_FOREACH(wl, winlinks, &ft->s->windows) {
for (i = 0; i < n; i++) {
wl = l[i];
w = wl->window;
format_log(es, "window loop: %u @%u", wl->idx, w->id);
if (active != NULL && wl == ft->s->curw)
use = active;
else
use = all;
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, FORMAT_WINDOW|w->id,
ft->flags|last);
format_defaults(nft, ft->c, ft->s, wl, NULL);
format_copy_state(&next, es, 0);
next.ft = nft;
@ -4410,6 +4584,23 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
return (value);
}
static int
format_cmp_pane(const void *a0, const void *b0)
{
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
const struct window_pane *const *a = a0;
const struct window_pane *const *b = b0;
const struct window_pane *wpa = *a;
const struct window_pane *wpb = *b;
int result = 0;
if (sc->reversed)
result = wpb->id - wpa->id;
else
result = wpa->id - wpb->id;
return (result);
}
/* Loop over panes. */
static char *
format_loop_panes(struct format_expand_state *es, const char *fmt)
@ -4422,6 +4613,9 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
char *all, *active, *use, *expanded, *value;
size_t valuelen;
struct window_pane *wp;
int i, n, last = 0;
static struct window_pane **l = NULL;
static int lsz = 0;
if (ft->w == NULL) {
format_log(es, "pane loop but no window");
@ -4433,16 +4627,31 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
active = NULL;
}
n = 0;
TAILQ_FOREACH(wp, &ft->w->panes, entry) {
if (lsz <= n) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[n++] = wp;
}
qsort(l, n, sizeof *l, format_cmp_pane);
value = xcalloc(1, 1);
valuelen = 1;
TAILQ_FOREACH(wp, &ft->w->panes, entry) {
for (i = 0; i < n; i++) {
wp = l[i];
format_log(es, "pane loop: %%%u", wp->id);
if (active != NULL && wp == ft->w->active)
use = active;
else
use = all;
nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, FORMAT_PANE|wp->id,
ft->flags|last);
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
format_copy_state(&next, es, 0);
next.ft = nft;
@ -4462,24 +4671,86 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
return (value);
}
static int
format_cmp_client(const void *a0, const void *b0)
{
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
const struct client *const *a = a0;
const struct client *const *b = b0;
const struct client *ca = *a;
const struct client *cb = *b;
int result = 0;
switch (sc->field) {
case FORMAT_LOOP_BY_INDEX:
break;
case FORMAT_LOOP_BY_TIME:
if (timercmp(&ca->activity_time, &cb->activity_time, >)) {
result = -1;
break;
}
if (timercmp(&ca->activity_time, &cb->activity_time, <)) {
result = 1;
break;
}
/* FALLTHROUGH */
case FORMAT_LOOP_BY_NAME:
result = strcmp(ca->name, cb->name);
break;
}
if (sc->reversed)
result = -result;
return (result);
}
/* Loop over clients. */
static char *
format_loop_clients(struct format_expand_state *es, const char *fmt)
{
struct format_tree *ft = es->ft;
struct client *c;
struct cmdq_item *item = ft->item;
struct format_tree *nft;
struct format_expand_state next;
char *expanded, *value;
size_t valuelen;
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
struct format_tree *ft = es->ft;
struct client *c;
struct cmdq_item *item = ft->item;
struct format_tree *nft;
struct format_expand_state next;
char *expanded, *value;
size_t valuelen;
int i, n, last = 0;
static struct client **l = NULL;
static int lsz = 0;
value = xcalloc(1, 1);
valuelen = 1;
n = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (lsz <= n) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[n++] = c;
}
if (sc->field != FORMAT_LOOP_BY_INDEX)
qsort(l, n, sizeof *l, format_cmp_client);
else {
/* Use order in the TAILQ as "index" order. */
if (sc->reversed) {
for (i = 0; i < n / 2; i++) {
c = l[i];
l[i] = l[n - 1 - i];
l[n - 1 - i] = c;
}
}
}
for (i = 0; i < n; i++) {
c = l[i];
format_log(es, "client loop: %s", c->name);
nft = format_create(c, item, 0, ft->flags);
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, 0, ft->flags|last);
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
format_copy_state(&next, es, 0);
next.ft = nft;
@ -4643,6 +4914,7 @@ static int
format_replace(struct format_expand_state *es, const char *key, size_t keylen,
char **buf, size_t *len, size_t *off)
{
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
struct format_tree *ft = es->ft;
struct window_pane *wp = ft->wp;
const char *errstr, *copy, *cp, *cp2;
@ -4658,7 +4930,6 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
struct format_modifier *bool_op_n = NULL;
u_int i, count, nsub = 0, nrep;
struct format_expand_state next;
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
/* Make a copy of the key. */
copy = copy0 = xstrndup(key, keylen);
@ -4769,15 +5040,19 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
break;
case 'S':
modifiers |= FORMAT_SESSIONS;
if (fm->argc < 1)
if (fm->argc < 1) {
sc->field = FORMAT_LOOP_BY_INDEX;
sc->reversed = 0;
break;
}
if (strchr(fm->argv[0], 'i') != NULL)
sc->field = FORMAT_LOOP_BY_INDEX;
else if (strchr(fm->argv[0], 'n') != NULL)
sc->field = FORMAT_LOOP_BY_NAME;
else if (strchr(fm->argv[0], 't') != NULL)
sc->field = FORMAT_LOOP_BY_TIME;
else sc->field = FORMAT_LOOP_BY_INDEX;
else
sc->field = FORMAT_LOOP_BY_INDEX;
if (strchr(fm->argv[0], 'r') != NULL)
sc->reversed = 1;
else
@ -4785,12 +5060,54 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
break;
case 'W':
modifiers |= FORMAT_WINDOWS;
if (fm->argc < 1) {
sc->field = FORMAT_LOOP_BY_INDEX;
sc->reversed = 0;
break;
}
if (strchr(fm->argv[0], 'i') != NULL)
sc->field = FORMAT_LOOP_BY_INDEX;
else if (strchr(fm->argv[0], 'n') != NULL)
sc->field = FORMAT_LOOP_BY_NAME;
else if (strchr(fm->argv[0], 't') != NULL)
sc->field = FORMAT_LOOP_BY_TIME;
else
sc->field = FORMAT_LOOP_BY_INDEX;
if (strchr(fm->argv[0], 'r') != NULL)
sc->reversed = 1;
else
sc->reversed = 0;
break;
case 'P':
modifiers |= FORMAT_PANES;
if (fm->argc < 1) {
sc->reversed = 0;
break;
}
if (strchr(fm->argv[0], 'r') != NULL)
sc->reversed = 1;
else
sc->reversed = 0;
break;
case 'L':
modifiers |= FORMAT_CLIENTS;
if (fm->argc < 1) {
sc->field = FORMAT_LOOP_BY_INDEX;
sc->reversed = 0;
break;
}
if (strchr(fm->argv[0], 'i') != NULL)
sc->field = FORMAT_LOOP_BY_INDEX;
else if (strchr(fm->argv[0], 'n') != NULL)
sc->field = FORMAT_LOOP_BY_NAME;
else if (strchr(fm->argv[0], 't') != NULL)
sc->field = FORMAT_LOOP_BY_TIME;
else
sc->field = FORMAT_LOOP_BY_INDEX;
if (strchr(fm->argv[0], 'r') != NULL)
sc->reversed = 1;
else
sc->reversed = 0;
break;
case 'R':
modifiers |= FORMAT_REPEAT;

11
menu.c
View File

@ -421,10 +421,6 @@ chosen:
return (1);
}
if (md->item != NULL)
event = cmdq_get_event(md->item);
else
event = NULL;
state = cmdq_new_state(&md->fs, event, 0);
status = cmd_parse_and_append(item->command, NULL, c, state, &error);
@ -544,12 +540,17 @@ menu_display(struct menu *menu, int flags, int starting_choice,
void *data)
{
struct menu_data *md;
struct window *w = c->session->curw->window;
md = menu_prepare(menu, flags, starting_choice, item, px, py, c, lines,
style, selected_style, border_style, fs, cb, data);
if (md == NULL)
return (-1);
w->md = md;
c->flags |= CLIENT_REDRAWWINDOW;
/*
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
menu_key_cb, menu_free_cb, NULL, md);
return (0);
*/
return (1);
}

View File

@ -138,7 +138,7 @@ static const char *options_table_allow_passthrough_list[] = {
"#{T:window-status-format}" \
"#[pop-default]" \
"#[norange default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"#{?loop_last_flag,,#{window-status-separator}}" \
"," \
"#[range=window|#{window_index} list=focus " \
"#{?#{!=:#{E:window-status-current-style},default}," \
@ -165,7 +165,7 @@ static const char *options_table_allow_passthrough_list[] = {
"#{T:window-status-current-format}" \
"#[pop-default]" \
"#[norange list=on default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"#{?loop_last_flag,,#{window-status-separator}}" \
"}" \
"#[nolist align=right range=right #{E:status-right-style}]" \
"#[push-default]" \

17
popup.c
View File

@ -218,6 +218,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
u_int i, px = pd->px, py = pd->py;
struct colour_palette *palette = &pd->palette;
struct grid_cell defaults;
struct window *w = c->session->curw->window;
screen_init(&s, pd->sx, pd->sy, 0);
screen_write_start(&ctx, &s);
@ -244,6 +245,9 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
if (pd->md != NULL) {
c->overlay_check = menu_check_cb;
c->overlay_data = pd->md;
} else if (w->md != NULL) {
c->overlay_check = menu_check_cb;
c->overlay_data = w->md;
} else {
c->overlay_check = NULL;
c->overlay_data = NULL;
@ -257,6 +261,10 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
c->overlay_check = NULL;
c->overlay_data = NULL;
menu_draw_cb(c, pd->md, rctx);
} else if (w->md != NULL) {
c->overlay_check = NULL;
c->overlay_data = NULL;
menu_draw_cb(c, w->md, rctx);
}
c->overlay_check = popup_check_cb;
c->overlay_data = pd;
@ -511,10 +519,13 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
m->x > pd->px + pd->sx - 1 ||
m->y < pd->py ||
m->y > pd->py + pd->sy - 1) {
if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3)
if ((c->flags & CLIENT_OVERLAYFOCUSED) &&
(MOUSE_BUTTONS(m->b) & MOUSE_BUTTON_3))
goto menu;
c->flags &= ~CLIENT_OVERLAYFOCUSED;
return (0);
}
c->flags |= CLIENT_OVERLAYFOCUSED;
if (pd->border_lines != BOX_LINES_NONE) {
if (m->x == pd->px)
border = LEFT;
@ -561,7 +572,8 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
bufferevent_write(job_get_event(pd->job), buf, len);
return (0);
}
input_key(&pd->s, job_get_event(pd->job), event->key);
if (c->flags & CLIENT_OVERLAYFOCUSED)
input_key(&pd->s, job_get_event(pd->job), event->key);
}
return (0);
@ -725,6 +737,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
c->flags |= CLIENT_OVERLAYFOCUSED;
return (0);
}

View File

@ -857,6 +857,9 @@ screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
if (window_pane_visible(wp))
screen_redraw_draw_pane(ctx, wp);
}
if (w->md != NULL)
w->menu_draw_cb(c, w->md, ctx);
}
/* Draw the status line. */
@ -1018,6 +1021,7 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
struct tty *tty = &c->tty;
struct grid_cell gc, slgc, *gcp;
struct style *sb_style = &wp->scrollbar_style;
struct overlay_ranges r;
u_int i, j, imax, jmax;
u_int sb_w = sb_style->width, sb_pad = sb_style->pad;
int px, py, ox = ctx->ox, oy = ctx->oy;
@ -1046,6 +1050,16 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
py < yoff - oy - 1 ||
py >= sy || py < 0)
continue;
if (c->overlay_check != NULL) {
c->overlay_check(c, c->overlay_data, px, py, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
continue;
}
if (wp->window->md != NULL) {
menu_check_cb(c, wp->window->md, px, py, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
continue;
}
tty_cursor(tty, px, py);
if ((sb_pos == PANE_SCROLLBARS_LEFT &&
i >= sb_w && i < sb_w + sb_pad) ||

View File

@ -2598,6 +2598,7 @@ paste_key:
out:
if (s != NULL && key != KEYC_FOCUS_OUT)
server_client_update_latest(c);
free(event->buf);
free(event);
return (CMD_RETURN_NORMAL);
@ -2608,7 +2609,10 @@ int
server_client_handle_key(struct client *c, struct key_event *event)
{
struct session *s = c->session;
struct window *w = s->curw->window;
struct cmdq_item *item;
struct window_pane *wp;
int done;
/* Check the client is good to accept input. */
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
@ -2625,17 +2629,27 @@ server_client_handle_key(struct client *c, struct key_event *event)
return (0);
status_message_clear(c);
}
if (c->overlay_key != NULL) {
switch (c->overlay_key(c, c->overlay_data, event)) {
case 0:
return (0);
case 1:
server_client_clear_overlay(c);
return (0);
if (w->md != NULL) {
done = w->menu_key_cb(c, w->md, event);
if (done) {
w->menu_free_cb(c, w->md);
w->md = NULL;
c->flags |= CLIENT_REDRAWWINDOW;
}
}
server_client_clear_overlay(c);
if (c->prompt_string != NULL) {
else if (c->overlay_key != NULL) {
done = c->overlay_key(c, c->overlay_data, event);
if (done)
server_client_clear_overlay(c);
else {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (~c->flags & CLIENT_OVERLAYFOCUSED)
goto focused;
}
}
return (0);
}
focused: if (c->prompt_string != NULL) {
if (status_prompt_key(c, event->key) == 0)
return (0);
}
@ -2885,6 +2899,25 @@ out:
bufferevent_enable(wp->event, EV_READ);
}
static int
server_client_check_overlay(struct client *c, u_int px, u_int py)
{
struct overlay_ranges r;
/*
* A unit width range will always return nx[2] == 0 from a check, even
* with multiple overlays, so it's sufficient to check just the first
* two entries.
*/
if (c->overlay_check == NULL)
return (0);
c->overlay_check(c, c->overlay_data, px, py, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
return (0);
return (1);
}
/*
* Update cursor position and mode settings. The scroll region and attributes
* are cleared when idle (waiting for an event) as this is the most likely time
@ -2894,6 +2927,7 @@ out:
* tty_region/tty_reset/tty_update_mode already take care of not resetting
* things that are already in their default state.
*/
static void
server_client_reset_state(struct client *c)
{
@ -2913,9 +2947,11 @@ server_client_reset_state(struct client *c)
tty->flags &= ~TTY_BLOCK;
/* Get mode from overlay if any, else from screen. */
if (c->overlay_draw != NULL) {
if (c->overlay_draw != NULL && c->flags & CLIENT_OVERLAYFOCUSED) {
if (c->overlay_mode != NULL)
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
} else if (w->md != NULL) {
s = w->menu_mode_cb(c, w->md, &cx, &cy);
} else if (c->prompt_string == NULL)
s = wp->screen;
else
@ -2944,18 +2980,22 @@ server_client_reset_state(struct client *c)
cy = tty->sy - n;
}
cx = c->prompt_cursor;
} else if (c->overlay_draw == NULL) {
} else if (c->overlay_draw == NULL || ~c->flags & CLIENT_OVERLAYFOCUSED) {
cursor = 0;
tty_window_offset(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;
if (status_at_line(c) == 0)
cy += status_line_size(c);
if (c->overlay_draw != NULL &&
!server_client_check_overlay(c, cx, cy))
cursor = 0;
else
cursor = 1;
}
if (!cursor)
mode &= ~MODE_CURSOR;

27
tmux.1
View File

@ -5911,14 +5911,21 @@ or
.Ql L:\&
will loop over each session, window, pane or client and insert the format once
for each.
.Ql S:\& ,
.Ql L:\& ,
.Ql S:\&
and
.Ql W:\&
can take an optional sort argument
.Ql /i\& ,
.Ql /n\& ,
.Ql /t\&
to sort by index, name, or time; or
to sort by index, name, or last activity time; additionally
.Ql /r\&
to sort in reverse order.
.Ql /r\&
can also be used with
.Ql P:\&
to reverse the sort order by pane index.
For example,
.Ql S/nr:\&
to sort sessions by name in reverse order.
@ -6070,8 +6077,10 @@ The following variables are available, where appropriate:
.It Li "insert_flag" Ta "" Ta "Pane insert flag"
.It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
.It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
.It Li "last_session_index" Ta "" Ta "Index of last session"
.It Li "last_window_index" Ta "" Ta "Index of last window in session"
.It Li "line" Ta "" Ta "Line number in the list"
.It Li "loop_last_flag" Ta "" Ta "1 if last window, pane, session, client in the W:, P:, S:, or L: loop"
.It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
.It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag"
.It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag"
@ -6143,10 +6152,13 @@ The following variables are available, where appropriate:
.It Li "selection_start_x" Ta "" Ta "X position of the start of the selection"
.It Li "selection_start_y" Ta "" Ta "Y position of the start of the selection"
.It Li "server_sessions" Ta "" Ta "Number of sessions"
.It Li "session_active" Ta "" Ta "1 if session active"
.It Li "session_activity" Ta "" Ta "Time of session last activity"
.It Li "session_activity_flag" Ta "" Ta "1 if any window in session has activity"
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
.It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
.It Li "session_attached_list" Ta "" Ta "List of clients session is attached to"
.It Li "session_bell_flag" Ta "" Ta "1 if any window in session has bell"
.It Li "session_created" Ta "" Ta "Time session created"
.It Li "session_format" Ta "" Ta "1 if format is for a session"
.It Li "session_group" Ta "" Ta "Name of session group"
@ -6157,11 +6169,13 @@ The following variables are available, where appropriate:
.It Li "session_group_size" Ta "" Ta "Size of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_id" Ta "" Ta "Unique session ID"
.It Li "session_index" Ta "" Ta "Index of session"
.It Li "session_last_attached" Ta "" Ta "Time session last attached"
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
.It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane"
.It Li "session_name" Ta "#S" Ta "Name of session"
.It Li "session_path" Ta "" Ta "Working directory of session"
.It Li "session_silence_flag" Ta "" Ta "1 if any window in session has silence alert"
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path"
@ -6921,7 +6935,7 @@ forwards any input read from stdin to the empty pane given by
.Ar target-pane .
.Tg popup
.It Xo Ic display-popup
.Op Fl BCE
.Op Fl BCDE
.Op Fl b Ar border-lines
.Op Fl c Ar target-client
.Op Fl d Ar start-directory
@ -6944,7 +6958,6 @@ Display a popup running
when omitted) 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.
.Pp
.Fl E
closes the popup automatically when
@ -7003,6 +7016,12 @@ is a format for the popup title (see
The
.Fl C
flag closes any popup on the client.
.Pp
The
.Fl D
flag causes the command not to block and wait for the
.Ar shell-command
to exit.
.Tg showphist
.It Xo Ic show-prompt-history
.Op Fl T Ar prompt-type

15
tmux.h
View File

@ -1225,6 +1225,13 @@ TAILQ_HEAD(window_panes, window_pane);
RB_HEAD(window_pane_tree, window_pane);
/* Window structure. */
struct key_event;
typedef struct screen *(*window_menu_mode_cb)(struct client *, void *, u_int *,
u_int *);
typedef void (*window_menu_draw_cb)(struct client *, void *,
struct screen_redraw_ctx *);
typedef int (*window_menu_key_cb)(struct client *, void *, struct key_event *);
typedef void (*window_menu_free_cb)(struct client *, void *);
struct window {
u_int id;
void *latest;
@ -1247,6 +1254,12 @@ struct window {
struct layout_cell *saved_layout_root;
char *old_layout;
struct menu_data *md;
window_menu_mode_cb menu_mode_cb;
window_menu_draw_cb menu_draw_cb;
window_menu_key_cb menu_key_cb;
window_menu_free_cb menu_free_cb;
u_int sx;
u_int sy;
u_int manual_sx;
@ -1983,6 +1996,7 @@ struct client {
#define CLIENT_ASSUMEPASTING 0x2000000000ULL
#define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL
#define CLIENT_NO_DETACH_ON_DESTROY 0x8000000000ULL
#define CLIENT_OVERLAYFOCUSED 0x10000000000ULL
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
@ -2290,6 +2304,7 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_FORCE 0x2
#define FORMAT_NOJOBS 0x4
#define FORMAT_VERBOSE 0x8
#define FORMAT_LAST 0x10
#define FORMAT_NONE 0
#define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U

View File

@ -319,6 +319,12 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
w->xpixel = xpixel;
w->ypixel = ypixel;
w->md = NULL;
w->menu_mode_cb = menu_mode_cb;
w->menu_draw_cb = menu_draw_cb;
w->menu_key_cb = menu_key_cb;
w->menu_free_cb = menu_free_cb;
w->options = options_create(global_w_options);
w->references = 0;