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.
This commit is contained in:
nicm
2021-08-13 06:52:51 +00:00
parent a2b8506917
commit 2bb0b9d6c5
10 changed files with 115 additions and 122 deletions

View File

@ -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;