diff --git a/Makefile b/Makefile index efad64a0..bfd5d7e3 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,7 @@ SRCS= arguments.c \ cmd.c \ colour.c \ control.c \ + control-notify.c \ environ.c \ format.c \ grid-utf8.c \ diff --git a/control-notify.c b/control-notify.c new file mode 100644 index 00000000..254f1f58 --- /dev/null +++ b/control-notify.c @@ -0,0 +1,183 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Nicholas Marriott + * Copyright (c) 2012 George Nachman + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "tmux.h" + +#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \ + ((c) != NULL && ((c)->flags & CLIENT_CONTROL)) + +void +control_notify_window_layout_changed(struct window *w) +{ + struct client *c; + struct session *s; + struct format_tree *ft; + struct winlink *wl; + u_int i; + const char *template; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + s = c->session; + + if (winlink_find_by_window_id(&s->windows, w->id) == NULL) + continue; + + /* + * When the last pane in a window is closed it won't have a + * layout root and we don't need to inform the client about the + * layout change because the whole window will go away soon. + */ + if (w->layout_root == NULL) + continue; + template = "%layout-change #{window_id} #{window_layout}"; + + ft = format_create(); + wl = winlink_find_by_window(&s->windows, w); + if (wl != NULL) { + format_winlink(ft, c->session, wl); + control_write(c, "%s", format_expand(ft, template)); + } + format_free(ft); + } +} + +void +control_notify_window_unlinked(unused struct session *s, struct window *w) +{ + struct client *c; + struct session *cs; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + cs = c->session; + + if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) + control_write(c, "%%window-close %u", w->id); + else + control_write(c, "%%unlinked-window-close %u", w->id); + } +} + +void +control_notify_window_linked(unused struct session *s, struct window *w) +{ + struct client *c; + struct session *cs; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + cs = c->session; + + if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) + control_write(c, "%%window-add %u", w->id); + else + control_write(c, "%%unlinked-window-add %u", w->id); + } +} + +void +control_notify_window_renamed(struct window *w) +{ + struct client *c; + struct session *s; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + s = c->session; + + if (winlink_find_by_window_id(&s->windows, w->id) != NULL) { + control_write(c, "%%window-renamed %u %s", + w->id, w->name); + } else { + control_write(c, "%%unlinked-window-renamed %u %s", + w->id, w->name); + } + } +} + +void +control_notify_attached_session_changed(struct client *c) +{ + struct session *s; + + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + return; + s = c->session; + + control_write(c, "%%session-changed %d %s", s->idx, s->name); +} + +void +control_notify_session_renamed(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session != s) + continue; + + control_write(c, "%%session-renamed %s", s->name); + } +} + +void +control_notify_session_created(unused struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + + control_write(c, "%%sessions-changed"); + } +} + +void +control_notify_session_close(unused struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + + control_write(c, "%%sessions-changed"); + } +} diff --git a/control.c b/control.c index 3dc7bc2a..c0d9e812 100644 --- a/control.c +++ b/control.c @@ -28,7 +28,6 @@ void printflike2 control_msg_error(struct cmd_ctx *, const char *, ...); void printflike2 control_msg_print(struct cmd_ctx *, const char *, ...); void printflike2 control_msg_info(struct cmd_ctx *, const char *, ...); -void printflike2 control_write(struct client *, const char *, ...); /* Command error callback. */ void printflike2 diff --git a/notify.c b/notify.c index 33fea56c..8fe792c1 100644 --- a/notify.c +++ b/notify.c @@ -95,28 +95,28 @@ notify_drain(void) TAILQ_FOREACH_SAFE(ne, ¬ify_queue, entry, ne1) { switch (ne->type) { case NOTIFY_WINDOW_LAYOUT_CHANGED: - /* control_notify_window_layout_changed(ne->window); */ + control_notify_window_layout_changed(ne->window); break; case NOTIFY_WINDOW_UNLINKED: - /* control_notify_window_unlinked(ne->session, ne->window); */ + control_notify_window_unlinked(ne->session, ne->window); break; case NOTIFY_WINDOW_LINKED: - /* control_notify_window_linked(ne->session, ne->window); */ + control_notify_window_linked(ne->session, ne->window); break; case NOTIFY_WINDOW_RENAMED: - /* control_notify_window_renamed(ne->window); */ + control_notify_window_renamed(ne->window); break; case NOTIFY_ATTACHED_SESSION_CHANGED: - /* control_notify_attached_session_changed(ne->client, ne->session); */ + control_notify_attached_session_changed(ne->client); break; case NOTIFY_SESSION_RENAMED: - /* control_notify_session_renamed(ne->session); */ + control_notify_session_renamed(ne->session); break; case NOTIFY_SESSION_CREATED: - /* control_notify_session_created(ne->session); */ + control_notify_session_created(ne->session); break; case NOTIFY_SESSION_CLOSED: - /* control_notify_session_close(ne->session); */ + control_notify_session_close(ne->session); break; } diff --git a/server-client.c b/server-client.c index 8ad996b0..7b7a3e4a 100644 --- a/server-client.c +++ b/server-client.c @@ -603,6 +603,9 @@ server_client_check_redraw(struct client *c) struct window_pane *wp; int flags, redraw; + if (c->flags & CLIENT_SUSPENDED) + return; + flags = c->tty.flags & TTY_FREEZE; c->tty.flags &= ~TTY_FREEZE; @@ -900,6 +903,7 @@ server_client_msg_identify( if (data->flags & IDENTIFY_CONTROL) { c->stdin_callback = control_callback; c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED); + server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; c->tty.log_fd = -1; diff --git a/tmux.h b/tmux.h index 449f0676..85f5fb68 100644 --- a/tmux.h +++ b/tmux.h @@ -2215,6 +2215,17 @@ void clear_signals(int); /* control.c */ void control_callback(struct client *, int, void*); +void printflike2 control_write(struct client *, const char *, ...); + +/* control-notify.c */ +void control_notify_window_layout_changed(struct window *); +void control_notify_window_unlinked(struct session *, struct window *); +void control_notify_window_linked(struct session *, struct window *); +void control_notify_window_renamed(struct window *); +void control_notify_attached_session_changed(struct client *); +void control_notify_session_renamed(struct session *); +void control_notify_session_created(struct session *); +void control_notify_session_close(struct session *); /* session.c */ extern struct sessions sessions;