Annotation of src/usr.bin/tmux/notify.c, Revision 1.11
1.11 ! nicm 1: /* $OpenBSD: notify.c,v 1.10 2016/10/15 00:01:01 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2012 George Nachman <tmux@georgester.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
1.2 nicm 19: #include <sys/types.h>
20: #include <sys/queue.h>
21:
22: #include <stdlib.h>
23:
1.1 nicm 24: #include "tmux.h"
25:
1.2 nicm 26: enum notify_type {
27: NOTIFY_WINDOW_LAYOUT_CHANGED,
28: NOTIFY_WINDOW_UNLINKED,
29: NOTIFY_WINDOW_LINKED,
30: NOTIFY_WINDOW_RENAMED,
31: NOTIFY_ATTACHED_SESSION_CHANGED,
32: NOTIFY_SESSION_RENAMED,
33: NOTIFY_SESSION_CREATED,
34: NOTIFY_SESSION_CLOSED
35: };
36:
1.11 ! nicm 37: static const char *notify_hooks[] = {
! 38: "window-layout-changed",
! 39: NULL, /* "window-unlinked", */
! 40: NULL, /* "window-linked", */
! 41: "window-renamed",
! 42: NULL, /* "attached-session-changed", */
! 43: "session-renamed",
! 44: NULL, /* "session-created", */
! 45: NULL, /* "session-closed" */
! 46: };
! 47:
1.2 nicm 48: struct notify_entry {
49: enum notify_type type;
50:
51: struct client *client;
52: struct session *session;
53: struct window *window;
54:
55: TAILQ_ENTRY(notify_entry) entry;
56: };
1.9 nicm 57: TAILQ_HEAD(notify_queue, notify_entry);
58: static struct notify_queue notify_queue = TAILQ_HEAD_INITIALIZER(notify_queue);
59:
60: static void notify_add(enum notify_type, struct client *, struct session *,
61: struct window *);
1.2 nicm 62:
1.9 nicm 63: static void
1.11 ! nicm 64: notify_hook(struct notify_entry *ne)
! 65: {
! 66: const char *name;
! 67: struct cmd_find_state fs;
! 68: struct hook *hook;
! 69: struct cmd_q *hooks_cmdq;
! 70:
! 71: name = notify_hooks[ne->type];
! 72: if (name == NULL)
! 73: return;
! 74:
! 75: cmd_find_clear_state(&fs, NULL, 0);
! 76: if (ne->session != NULL && ne->window != NULL)
! 77: cmd_find_from_session_window(&fs, ne->session, ne->window);
! 78: else if (ne->window != NULL)
! 79: cmd_find_from_window(&fs, ne->window);
! 80: else if (ne->session != NULL)
! 81: cmd_find_from_session(&fs, ne->session);
! 82: if (cmd_find_empty_state(&fs) || !cmd_find_valid_state(&fs))
! 83: return;
! 84:
! 85: hook = hooks_find(fs.s->hooks, name);
! 86: if (hook == NULL)
! 87: return;
! 88: log_debug("notify hook %s", name);
! 89:
! 90: hooks_cmdq = cmdq_new(NULL);
! 91: hooks_cmdq->flags |= CMD_Q_NOHOOKS;
! 92:
! 93: cmd_find_copy_state(&hooks_cmdq->current, &fs);
! 94: hooks_cmdq->parent = NULL;
! 95:
! 96: cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
! 97: cmdq_free(hooks_cmdq);
! 98: }
! 99:
! 100: static void
1.2 nicm 101: notify_add(enum notify_type type, struct client *c, struct session *s,
102: struct window *w)
103: {
104: struct notify_entry *ne;
105:
106: ne = xcalloc(1, sizeof *ne);
107: ne->type = type;
108: ne->client = c;
109: ne->session = s;
110: ne->window = w;
111: TAILQ_INSERT_TAIL(¬ify_queue, ne, entry);
112:
113: if (c != NULL)
114: c->references++;
115: if (s != NULL)
116: s->references++;
117: if (w != NULL)
118: w->references++;
119: }
120:
1.10 nicm 121: void
1.2 nicm 122: notify_drain(void)
123: {
124: struct notify_entry *ne, *ne1;
125:
126: TAILQ_FOREACH_SAFE(ne, ¬ify_queue, entry, ne1) {
127: switch (ne->type) {
128: case NOTIFY_WINDOW_LAYOUT_CHANGED:
1.4 nicm 129: control_notify_window_layout_changed(ne->window);
1.2 nicm 130: break;
131: case NOTIFY_WINDOW_UNLINKED:
1.4 nicm 132: control_notify_window_unlinked(ne->session, ne->window);
1.2 nicm 133: break;
134: case NOTIFY_WINDOW_LINKED:
1.4 nicm 135: control_notify_window_linked(ne->session, ne->window);
1.2 nicm 136: break;
137: case NOTIFY_WINDOW_RENAMED:
1.4 nicm 138: control_notify_window_renamed(ne->window);
1.2 nicm 139: break;
140: case NOTIFY_ATTACHED_SESSION_CHANGED:
1.4 nicm 141: control_notify_attached_session_changed(ne->client);
1.2 nicm 142: break;
143: case NOTIFY_SESSION_RENAMED:
1.4 nicm 144: control_notify_session_renamed(ne->session);
1.2 nicm 145: break;
146: case NOTIFY_SESSION_CREATED:
1.4 nicm 147: control_notify_session_created(ne->session);
1.2 nicm 148: break;
149: case NOTIFY_SESSION_CLOSED:
1.4 nicm 150: control_notify_session_close(ne->session);
1.2 nicm 151: break;
152: }
1.11 ! nicm 153: TAILQ_REMOVE(¬ify_queue, ne, entry);
! 154: notify_hook(ne);
1.2 nicm 155:
156: if (ne->client != NULL)
1.7 nicm 157: server_client_unref(ne->client);
1.2 nicm 158: if (ne->session != NULL)
1.8 nicm 159: session_unref(ne->session);
1.2 nicm 160: if (ne->window != NULL)
1.3 nicm 161: window_remove_ref(ne->window);
1.2 nicm 162: free(ne);
1.5 nicm 163: }
164: }
165:
166: void
167: notify_input(struct window_pane *wp, struct evbuffer *input)
168: {
169: struct client *c;
170:
1.6 nicm 171: TAILQ_FOREACH(c, &clients, entry) {
172: if (c->flags & CLIENT_CONTROL)
1.5 nicm 173: control_notify_input(c, wp, input);
1.2 nicm 174: }
175: }
176:
1.1 nicm 177: void
1.2 nicm 178: notify_window_layout_changed(struct window *w)
1.1 nicm 179: {
1.2 nicm 180: notify_add(NOTIFY_WINDOW_LAYOUT_CHANGED, NULL, NULL, w);
181: notify_drain();
1.1 nicm 182: }
183:
184: void
1.2 nicm 185: notify_window_unlinked(struct session *s, struct window *w)
1.1 nicm 186: {
1.2 nicm 187: notify_add(NOTIFY_WINDOW_UNLINKED, NULL, s, w);
188: notify_drain();
1.1 nicm 189: }
190:
191: void
1.2 nicm 192: notify_window_linked(struct session *s, struct window *w)
1.1 nicm 193: {
1.2 nicm 194: notify_add(NOTIFY_WINDOW_LINKED, NULL, s, w);
195: notify_drain();
1.1 nicm 196: }
197:
198: void
1.2 nicm 199: notify_window_renamed(struct window *w)
1.1 nicm 200: {
1.2 nicm 201: notify_add(NOTIFY_WINDOW_RENAMED, NULL, NULL, w);
202: notify_drain();
1.1 nicm 203: }
204:
205: void
1.2 nicm 206: notify_attached_session_changed(struct client *c)
1.1 nicm 207: {
1.2 nicm 208: notify_add(NOTIFY_ATTACHED_SESSION_CHANGED, c, NULL, NULL);
209: notify_drain();
1.1 nicm 210: }
211:
212: void
1.2 nicm 213: notify_session_renamed(struct session *s)
1.1 nicm 214: {
1.2 nicm 215: notify_add(NOTIFY_SESSION_RENAMED, NULL, s, NULL);
216: notify_drain();
1.1 nicm 217: }
218:
219: void
1.2 nicm 220: notify_session_created(struct session *s)
1.1 nicm 221: {
1.2 nicm 222: notify_add(NOTIFY_SESSION_CREATED, NULL, s, NULL);
223: notify_drain();
1.1 nicm 224: }
225:
226: void
1.2 nicm 227: notify_session_closed(struct session *s)
1.1 nicm 228: {
1.2 nicm 229: notify_add(NOTIFY_SESSION_CLOSED, NULL, s, NULL);
230: notify_drain();
1.1 nicm 231: }