summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2021-08-13 06:52:52 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2021-08-13 06:52:52 +0000
commited494901095f45650fd129e1f8a6f4c3eceab503 (patch)
tree03fbcabdb314bffc3ffee9e7348f720036e0816c
parenteed9256d707e6d4d197e53024454b58138b4fed8 (diff)
Change focus to be driven by events rather than walking all panes at end
of event loop, this way the ordering of in and out can be enforced. GitHub issue 2808.
-rw-r--r--usr.bin/tmux/cmd-attach-session.c25
-rw-r--r--usr.bin/tmux/cmd-new-session.c12
-rw-r--r--usr.bin/tmux/cmd-switch-client.c18
-rw-r--r--usr.bin/tmux/input.c10
-rw-r--r--usr.bin/tmux/server-client.c98
-rw-r--r--usr.bin/tmux/server-fn.c18
-rw-r--r--usr.bin/tmux/session.c8
-rw-r--r--usr.bin/tmux/tmux.h7
-rw-r--r--usr.bin/tmux/tty-keys.c8
-rw-r--r--usr.bin/tmux/window.c53
10 files changed, 125 insertions, 132 deletions
diff --git a/usr.bin/tmux/cmd-attach-session.c b/usr.bin/tmux/cmd-attach-session.c
index 3c727ea617b..f18a456fab7 100644
--- a/usr.bin/tmux/cmd-attach-session.c
+++ b/usr.bin/tmux/cmd-attach-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-attach-session.c,v 1.85 2020/09/03 12:47:33 nicm Exp $ */
+/* $OpenBSD: cmd-attach-session.c,v 1.86 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -124,17 +124,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
- c->session = s;
+ server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
- tty_update_client_offset(c);
- status_timer_start(c);
- notify_client("client-session-changed", c);
- session_update_activity(s, NULL);
- gettimeofday(&s->last_attached_time, NULL);
- server_redraw_client(c);
- s->curw->flags &= ~WINLINK_ALERTFLAGS;
- s->curw->window->latest = c;
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
@@ -156,25 +148,14 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
- c->session = s;
+ server_client_set_session(c, s);
server_client_set_key_table(c, NULL);
- tty_update_client_offset(c);
- status_timer_start(c);
- notify_client("client-session-changed", c);
- session_update_activity(s, NULL);
- gettimeofday(&s->last_attached_time, NULL);
- server_redraw_client(c);
- s->curw->flags &= ~WINLINK_ALERTFLAGS;
- s->curw->window->latest = c;
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED;
}
- recalculate_sizes();
- alerts_check_session(s);
- server_update_socket();
return (CMD_RETURN_NORMAL);
}
diff --git a/usr.bin/tmux/cmd-new-session.c b/usr.bin/tmux/cmd-new-session.c
index 726d3844172..fbcd907dff0 100644
--- a/usr.bin/tmux/cmd-new-session.c
+++ b/usr.bin/tmux/cmd-new-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-session.c,v 1.138 2021/07/13 10:38:57 nicm Exp $ */
+/* $OpenBSD: cmd-new-session.c,v 1.139 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -329,18 +329,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
- c->session = s;
+ server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
- tty_update_client_offset(c);
- status_timer_start(c);
- notify_client("client-session-changed", c);
- session_update_activity(s, NULL);
- gettimeofday(&s->last_attached_time, NULL);
- server_redraw_client(c);
}
- recalculate_sizes();
- server_update_socket();
/*
* If there are still configuration file errors to display, put the new
diff --git a/usr.bin/tmux/cmd-switch-client.c b/usr.bin/tmux/cmd-switch-client.c
index 6502ee81643..7665b23ef1e 100644
--- a/usr.bin/tmux/cmd-switch-client.c
+++ b/usr.bin/tmux/cmd-switch-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-switch-client.c,v 1.68 2021/03/11 06:31:05 nicm Exp $ */
+/* $OpenBSD: cmd-switch-client.c,v 1.69 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -134,23 +134,9 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'E'))
environ_update(s->options, tc->environ, s->environ);
- if (tc->session != NULL && tc->session != s)
- tc->last_session = tc->session;
- tc->session = s;
+ server_client_set_session(tc, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(tc, NULL);
- tty_update_client_offset(tc);
- status_timer_start(tc);
- notify_client("client-session-changed", tc);
- session_update_activity(s, NULL);
- gettimeofday(&s->last_attached_time, NULL);
-
- server_check_unattached();
- server_redraw_client(tc);
- s->curw->flags &= ~WINLINK_ALERTFLAGS;
- s->curw->window->latest = tc;
- recalculate_sizes();
- alerts_check_session(s);
return (CMD_RETURN_NORMAL);
}
diff --git a/usr.bin/tmux/input.c b/usr.bin/tmux/input.c
index 162faf27747..44c9bff749c 100644
--- a/usr.bin/tmux/input.c
+++ b/usr.bin/tmux/input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: input.c,v 1.190 2021/08/11 20:49:55 nicm Exp $ */
+/* $OpenBSD: input.c,v 1.191 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1792,8 +1792,12 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
if (sctx->s->mode & MODE_FOCUSON)
break;
screen_write_mode_set(sctx, MODE_FOCUSON);
- if (wp != NULL)
- wp->flags |= PANE_FOCUSPUSH; /* force update */
+ if (wp == NULL)
+ break;
+ if (wp->flags & PANE_FOCUSED)
+ bufferevent_write(wp->event, "\033[I", 3);
+ else
+ bufferevent_write(wp->event, "\033[O", 3);
break;
case 1005:
screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c
index a087504f230..8626d3bee28 100644
--- a/usr.bin/tmux/server-client.c
+++ b/usr.bin/tmux/server-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.378 2021/08/05 09:43:51 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.379 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,7 +33,6 @@
#include "tmux.h"
static void server_client_free(int, short, void *);
-static void server_client_check_pane_focus(struct window_pane *);
static void server_client_check_pane_resize(struct window_pane *);
static void server_client_check_pane_buffer(struct window_pane *);
static void server_client_check_window_resize(struct window *);
@@ -301,9 +300,8 @@ server_client_attached_lost(struct client *c)
s = loop->session;
if (loop == c || s == NULL || s->curw->window != w)
continue;
- if (found == NULL ||
- timercmp(&loop->activity_time, &found->activity_time,
- >))
+ if (found == NULL || timercmp(&loop->activity_time,
+ &found->activity_time, >))
found = loop;
}
if (found != NULL)
@@ -311,6 +309,40 @@ server_client_attached_lost(struct client *c)
}
}
+
+/* Set client session. */
+void
+server_client_set_session(struct client *c, struct session *s)
+{
+ struct session *old = c->session;
+
+ if (s != NULL && c->session != NULL && c->session != s)
+ c->last_session = c->session;
+ else if (s == NULL)
+ c->last_session = NULL;
+ c->session = s;
+ c->flags |= CLIENT_FOCUSED;
+ recalculate_sizes();
+
+ if (old != NULL && old->curw != NULL)
+ window_update_focus(old->curw->window);
+ if (s != NULL) {
+ window_update_focus(s->curw->window);
+ session_update_activity(s, NULL);
+ gettimeofday(&s->last_attached_time, NULL);
+ s->curw->flags &= ~WINLINK_ALERTFLAGS;
+ s->curw->window->latest = c;
+ alerts_check_session(s);
+ tty_update_client_offset(c);
+ status_timer_start(c);
+ notify_client("client-session-changed", c);
+ server_redraw_client(c);
+ }
+
+ server_check_unattached();
+ server_update_socket();
+}
+
/* Lost a client. */
void
server_client_lost(struct client *c)
@@ -1389,7 +1421,6 @@ server_client_loop(void)
struct client *c;
struct window *w;
struct window_pane *wp;
- int focus;
/* Check for window resize. This is done before redrawing. */
RB_FOREACH(w, windows, &windows)
@@ -1407,14 +1438,11 @@ server_client_loop(void)
/*
* Any windows will have been redrawn as part of clients, so clear
- * their flags now. Also check pane focus and resize.
+ * their flags now.
*/
- focus = options_get_number(global_options, "focus-events");
RB_FOREACH(w, windows, &windows) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) {
- if (focus)
- server_client_check_pane_focus(wp);
server_client_check_pane_resize(wp);
server_client_check_pane_buffer(wp);
}
@@ -1615,54 +1643,6 @@ out:
bufferevent_enable(wp->event, EV_READ);
}
-/* Check whether pane should be focused. */
-static void
-server_client_check_pane_focus(struct window_pane *wp)
-{
- struct client *c;
- int push;
-
- /* Do we need to push the focus state? */
- push = wp->flags & PANE_FOCUSPUSH;
- wp->flags &= ~PANE_FOCUSPUSH;
-
- /* If we're not the active pane in our window, we're not focused. */
- if (wp->window->active != wp)
- goto not_focused;
-
- /*
- * If our window is the current window in any focused clients with an
- * attached session, we're focused.
- */
- TAILQ_FOREACH(c, &clients, entry) {
- if (c->session == NULL || !(c->flags & CLIENT_FOCUSED))
- continue;
- if (c->session->attached == 0)
- continue;
-
- if (c->session->curw->window == wp->window)
- goto focused;
- }
-
-not_focused:
- if (push || (wp->flags & PANE_FOCUSED)) {
- if (wp->base.mode & MODE_FOCUSON)
- bufferevent_write(wp->event, "\033[O", 3);
- notify_pane("pane-focus-out", wp);
- }
- wp->flags &= ~PANE_FOCUSED;
- return;
-
-focused:
- if (push || !(wp->flags & PANE_FOCUSED)) {
- if (wp->base.mode & MODE_FOCUSON)
- bufferevent_write(wp->event, "\033[I", 3);
- notify_pane("pane-focus-in", wp);
- session_update_activity(c->session, NULL);
- }
- wp->flags |= PANE_FOCUSED;
-}
-
/*
* 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
@@ -2078,7 +2058,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
- c->session = NULL;
+ server_client_set_session(c, NULL);
tty_close(&c->tty);
proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
break;
diff --git a/usr.bin/tmux/server-fn.c b/usr.bin/tmux/server-fn.c
index 4dce8243816..f9b51dcf697 100644
--- a/usr.bin/tmux/server-fn.c
+++ b/usr.bin/tmux/server-fn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-fn.c,v 1.130 2021/02/01 08:01:14 nicm Exp $ */
+/* $OpenBSD: server-fn.c,v 1.131 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -445,21 +445,9 @@ server_destroy_session(struct session *s)
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
- if (s_new == NULL) {
- c->session = NULL;
+ server_client_set_session(c, NULL);
+ if (s_new == NULL)
c->flags |= CLIENT_EXIT;
- } else {
- c->last_session = NULL;
- c->session = s_new;
- server_client_set_key_table(c, NULL);
- tty_update_client_offset(c);
- status_timer_start(c);
- notify_client("client-session-changed", c);
- session_update_activity(s_new, NULL);
- gettimeofday(&s_new->last_attached_time, NULL);
- server_redraw_client(c);
- alerts_check_session(s_new);
- }
}
recalculate_sizes();
}
diff --git a/usr.bin/tmux/session.c b/usr.bin/tmux/session.c
index 249d4293b28..2d06a64712c 100644
--- a/usr.bin/tmux/session.c
+++ b/usr.bin/tmux/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.88 2021/07/06 08:18:38 nicm Exp $ */
+/* $OpenBSD: session.c,v 1.89 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -489,6 +489,8 @@ session_last(struct session *s)
int
session_set_current(struct session *s, struct winlink *wl)
{
+ struct winlink *old = s->curw;
+
if (wl == NULL)
return (-1);
if (wl == s->curw)
@@ -497,6 +499,10 @@ session_set_current(struct session *s, struct winlink *wl)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
+ if (options_get_number(global_options, "focus-events")) {
+ window_update_focus(old->window);
+ window_update_focus(wl->window);
+ }
winlink_clear_flags(wl);
window_update_activity(wl->window);
tty_update_window_offset(wl->window);
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index 755c1c07e98..fe502e5c7ce 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1116 2021/08/12 08:05:11 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1117 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1004,7 +1004,7 @@ struct window_pane {
#define PANE_FOCUSED 0x4
/* 0x8 unused */
/* 0x10 unused */
-#define PANE_FOCUSPUSH 0x20
+/* 0x20 unused */
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
#define PANE_EXITED 0x100
@@ -2506,6 +2506,7 @@ int server_client_handle_key(struct client *, struct key_event *);
struct client *server_client_create(int);
int server_client_open(struct client *, char **);
void server_client_unref(struct client *);
+void server_client_set_session(struct client *, struct session *);
void server_client_lost(struct client *);
void server_client_suspend(struct client *);
void server_client_detach(struct client *, enum msgtype);
@@ -2826,6 +2827,8 @@ struct window_pane *window_find_string(struct window *, const char *);
int window_has_pane(struct window *, struct window_pane *);
int window_set_active_pane(struct window *, struct window_pane *,
int);
+void window_update_focus(struct window *);
+void window_pane_update_focus(struct window_pane *);
void window_redraw_active_switch(struct window *,
struct window_pane *);
struct window_pane *window_add_pane(struct window *, struct window_pane *,
diff --git a/usr.bin/tmux/tty-keys.c b/usr.bin/tmux/tty-keys.c
index 13f47f97746..e64f9b8e3f8 100644
--- a/usr.bin/tmux/tty-keys.c
+++ b/usr.bin/tmux/tty-keys.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty-keys.c,v 1.148 2021/08/06 09:19:02 nicm Exp $ */
+/* $OpenBSD: tty-keys.c,v 1.149 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -821,11 +821,13 @@ complete_key:
/* Check for focus events. */
if (key == KEYC_FOCUS_OUT) {
- tty->client->flags &= ~CLIENT_FOCUSED;
+ c->flags &= ~CLIENT_FOCUSED;
+ window_update_focus(c->session->curw->window);
notify_client("client-focus-out", c);
} else if (key == KEYC_FOCUS_IN) {
- tty->client->flags |= CLIENT_FOCUSED;
+ c->flags |= CLIENT_FOCUSED;
notify_client("client-focus-in", c);
+ window_update_focus(c->session->curw->window);
}
/* Fire the key. */
diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c
index fbf3da32fbe..69257a3ddff 100644
--- a/usr.bin/tmux/window.c
+++ b/usr.bin/tmux/window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.273 2021/08/11 20:49:55 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.274 2021/08/13 06:52:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -458,6 +458,52 @@ window_has_pane(struct window *w, struct window_pane *wp)
return (0);
}
+void
+window_update_focus(struct window *w)
+{
+ if (w != NULL) {
+ log_debug("%s: @%u", __func__, w->id);
+ window_pane_update_focus(w->active);
+ }
+}
+
+void
+window_pane_update_focus(struct window_pane *wp)
+{
+ struct client *c;
+ int focused = 0;
+
+ if (wp != NULL) {
+ if (wp != wp->window->active)
+ focused = 0;
+ else {
+ TAILQ_FOREACH(c, &clients, entry) {
+ if (c->session != NULL &&
+ c->session->attached != 0 &&
+ (c->flags & CLIENT_FOCUSED) &&
+ c->session->curw->window == wp->window) {
+ focused = 1;
+ break;
+ }
+ }
+ }
+ if (!focused && (wp->flags & PANE_FOCUSED)) {
+ log_debug("%s: %%%u focus out", __func__, wp->id);
+ if (wp->base.mode & MODE_FOCUSON)
+ bufferevent_write(wp->event, "\033[O", 3);
+ notify_pane("pane-focus-out", wp);
+ wp->flags &= ~PANE_FOCUSED;
+ } else if (focused && (~wp->flags & PANE_FOCUSED)) {
+ log_debug("%s: %%%u focus in", __func__, wp->id);
+ if (wp->base.mode & MODE_FOCUSON)
+ bufferevent_write(wp->event, "\033[I", 3);
+ notify_pane("pane-focus-in", wp);
+ wp->flags |= PANE_FOCUSED;
+ } else
+ log_debug("%s: %%%u focus unchanged", __func__, wp->id);
+ }
+}
+
int
window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
{
@@ -471,6 +517,11 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
+ if (options_get_number(global_options, "focus-events")) {
+ window_pane_update_focus(w->last);
+ window_pane_update_focus(w->active);
+ }
+
tty_update_window_offset(w);
if (notify)