Annotation of src/usr.bin/tmux/notify.c, Revision 1.41
1.41 ! nicm 1: /* $OpenBSD: notify.c,v 1.40 2022/03/08 21:58:37 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>
1.18 nicm 23: #include <string.h>
1.2 nicm 24:
1.1 nicm 25: #include "tmux.h"
26:
1.2 nicm 27: struct notify_entry {
1.18 nicm 28: const char *name;
1.38 nicm 29: struct cmd_find_state fs;
30: struct format_tree *formats;
1.2 nicm 31:
32: struct client *client;
33: struct session *session;
34: struct window *window;
1.18 nicm 35: int pane;
1.2 nicm 36: };
37:
1.40 nicm 38: static struct cmdq_item *
39: notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne,
40: struct cmd_list *cmdlist, struct cmdq_state *state)
41: {
42: struct cmdq_item *new_item;
43: char *s;
44:
45: if (cmdlist == NULL)
46: return (item);
47: if (log_get_level() != 0) {
48: s = cmd_list_print(cmdlist, 0);
49: log_debug("%s: hook %s is: %s", __func__, ne->name, s);
1.41 ! nicm 50: free(s);
1.40 nicm 51: }
52: new_item = cmdq_get_command(cmdlist, state);
53: return (cmdq_insert_after(item, new_item));
54: }
55:
1.9 nicm 56: static void
1.27 nicm 57: notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
58: {
59: struct cmd_find_state fs;
60: struct options *oo;
1.40 nicm 61: struct cmdq_state *state;
1.27 nicm 62: struct options_entry *o;
63: struct options_array_item *a;
64: struct cmd_list *cmdlist;
1.40 nicm 65: const char *value;
66: struct cmd_parse_result *pr;
1.27 nicm 67:
1.40 nicm 68: log_debug("%s: inserting hook %s", __func__, ne->name);
1.11 nicm 69:
1.22 nicm 70: cmd_find_clear_state(&fs, 0);
1.18 nicm 71: if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
1.25 nicm 72: cmd_find_from_nothing(&fs, 0);
1.15 nicm 73: else
1.18 nicm 74: cmd_find_copy_state(&fs, &ne->fs);
1.11 nicm 75:
1.27 nicm 76: if (fs.s == NULL)
77: oo = global_s_options;
78: else
79: oo = fs.s->options;
80: o = options_get(oo, ne->name);
1.30 nicm 81: if (o == NULL && fs.wp != NULL) {
82: oo = fs.wp->options;
83: o = options_get(oo, ne->name);
84: }
85: if (o == NULL && fs.wl != NULL) {
86: oo = fs.wl->window->options;
87: o = options_get(oo, ne->name);
88: }
1.40 nicm 89: if (o == NULL) {
90: log_debug("%s: hook %s not found", __func__, ne->name);
1.11 nicm 91: return;
1.40 nicm 92: }
1.11 nicm 93:
1.40 nicm 94: state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
95: cmdq_add_formats(state, ne->formats);
1.34 nicm 96:
1.40 nicm 97: if (*ne->name == '@') {
98: value = options_get_string(oo, ne->name);
99: pr = cmd_parse_from_string(value, NULL);
100: switch (pr->status) {
101: case CMD_PARSE_ERROR:
102: log_debug("%s: can't parse hook %s: %s", __func__,
103: ne->name, pr->error);
104: free(pr->error);
105: break;
106: case CMD_PARSE_SUCCESS:
107: notify_insert_one_hook(item, ne, pr->cmdlist, state);
108: break;
109: }
110: } else {
111: a = options_array_first(o);
112: while (a != NULL) {
113: cmdlist = options_array_item_value(a)->cmdlist;
114: item = notify_insert_one_hook(item, ne, cmdlist, state);
115: a = options_array_next(a);
1.27 nicm 116: }
1.17 nicm 117: }
1.34 nicm 118:
1.40 nicm 119: cmdq_free_state(state);
1.15 nicm 120: }
121:
122: static enum cmd_retval
123: notify_callback(struct cmdq_item *item, void *data)
124: {
125: struct notify_entry *ne = data;
1.20 nicm 126:
127: log_debug("%s: %s", __func__, ne->name);
1.15 nicm 128:
1.24 nicm 129: if (strcmp(ne->name, "pane-mode-changed") == 0)
130: control_notify_pane_mode_changed(ne->pane);
1.18 nicm 131: if (strcmp(ne->name, "window-layout-changed") == 0)
1.15 nicm 132: control_notify_window_layout_changed(ne->window);
1.24 nicm 133: if (strcmp(ne->name, "window-pane-changed") == 0)
134: control_notify_window_pane_changed(ne->window);
1.18 nicm 135: if (strcmp(ne->name, "window-unlinked") == 0)
1.15 nicm 136: control_notify_window_unlinked(ne->session, ne->window);
1.18 nicm 137: if (strcmp(ne->name, "window-linked") == 0)
1.15 nicm 138: control_notify_window_linked(ne->session, ne->window);
1.18 nicm 139: if (strcmp(ne->name, "window-renamed") == 0)
1.15 nicm 140: control_notify_window_renamed(ne->window);
1.18 nicm 141: if (strcmp(ne->name, "client-session-changed") == 0)
142: control_notify_client_session_changed(ne->client);
1.37 nicm 143: if (strcmp(ne->name, "client-detached") == 0)
144: control_notify_client_detached(ne->client);
1.18 nicm 145: if (strcmp(ne->name, "session-renamed") == 0)
1.15 nicm 146: control_notify_session_renamed(ne->session);
1.18 nicm 147: if (strcmp(ne->name, "session-created") == 0)
1.15 nicm 148: control_notify_session_created(ne->session);
1.18 nicm 149: if (strcmp(ne->name, "session-closed") == 0)
1.15 nicm 150: control_notify_session_closed(ne->session);
1.24 nicm 151: if (strcmp(ne->name, "session-window-changed") == 0)
152: control_notify_session_window_changed(ne->session);
1.18 nicm 153:
1.27 nicm 154: notify_insert_hook(item, ne);
1.15 nicm 155:
156: if (ne->client != NULL)
157: server_client_unref(ne->client);
158: if (ne->session != NULL)
1.23 nicm 159: session_remove_ref(ne->session, __func__);
1.15 nicm 160: if (ne->window != NULL)
1.23 nicm 161: window_remove_ref(ne->window, __func__);
1.18 nicm 162:
163: if (ne->fs.s != NULL)
1.23 nicm 164: session_remove_ref(ne->fs.s, __func__);
1.18 nicm 165:
1.38 nicm 166: format_free(ne->formats);
1.18 nicm 167: free((void *)ne->name);
1.15 nicm 168: free(ne);
169:
170: return (CMD_RETURN_NORMAL);
1.11 nicm 171: }
172:
173: static void
1.19 nicm 174: notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
175: struct session *s, struct window *w, struct window_pane *wp)
1.2 nicm 176: {
177: struct notify_entry *ne;
1.35 nicm 178: struct cmdq_item *item;
179:
180: item = cmdq_running(NULL);
181: if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
182: return;
1.2 nicm 183:
184: ne = xcalloc(1, sizeof *ne);
1.18 nicm 185: ne->name = xstrdup(name);
186:
1.2 nicm 187: ne->client = c;
188: ne->session = s;
189: ne->window = w;
1.38 nicm 190: ne->pane = (wp != NULL ? wp->id : -1);
1.2 nicm 191:
1.38 nicm 192: ne->formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
193: format_add(ne->formats, "hook", "%s", name);
194: if (c != NULL)
195: format_add(ne->formats, "hook_client", "%s", c->name);
196: if (s != NULL) {
197: format_add(ne->formats, "hook_session", "$%u", s->id);
198: format_add(ne->formats, "hook_session_name", "%s", s->name);
199: }
200: if (w != NULL) {
201: format_add(ne->formats, "hook_window", "@%u", w->id);
202: format_add(ne->formats, "hook_window_name", "%s", w->name);
203: }
1.18 nicm 204: if (wp != NULL)
1.38 nicm 205: format_add(ne->formats, "hook_pane", "%%%d", wp->id);
206: format_log_debug(ne->formats, __func__);
1.18 nicm 207:
1.2 nicm 208: if (c != NULL)
209: c->references++;
210: if (s != NULL)
1.23 nicm 211: session_add_ref(s, __func__);
1.2 nicm 212: if (w != NULL)
1.23 nicm 213: window_add_ref(w, __func__);
1.2 nicm 214:
1.19 nicm 215: cmd_find_copy_state(&ne->fs, fs);
1.23 nicm 216: if (ne->fs.s != NULL) /* cmd_find_valid_state needs session */
217: session_add_ref(ne->fs.s, __func__);
1.18 nicm 218:
1.35 nicm 219: cmdq_append(NULL, cmdq_get_callback(notify_callback, ne));
1.26 nicm 220: }
221:
222: void
223: notify_hook(struct cmdq_item *item, const char *name)
224: {
1.31 nicm 225: struct cmd_find_state *target = cmdq_get_target(item);
226: struct notify_entry ne;
1.26 nicm 227:
228: memset(&ne, 0, sizeof ne);
229:
230: ne.name = name;
1.31 nicm 231: cmd_find_copy_state(&ne.fs, target);
1.26 nicm 232:
1.31 nicm 233: ne.client = cmdq_get_client(item);
234: ne.session = target->s;
235: ne.window = target->w;
1.39 nicm 236: ne.pane = (target->wp != NULL ? target->wp->id : -1);
1.26 nicm 237:
1.38 nicm 238: ne.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
239: format_add(ne.formats, "hook", "%s", name);
240: format_log_debug(ne.formats, __func__);
241:
1.27 nicm 242: notify_insert_hook(item, &ne);
1.38 nicm 243: format_free(ne.formats);
1.2 nicm 244: }
245:
1.1 nicm 246: void
1.18 nicm 247: notify_client(const char *name, struct client *c)
1.1 nicm 248: {
1.19 nicm 249: struct cmd_find_state fs;
250:
1.25 nicm 251: cmd_find_from_client(&fs, c, 0);
1.19 nicm 252: notify_add(name, &fs, c, NULL, NULL, NULL);
1.1 nicm 253: }
254:
255: void
1.18 nicm 256: notify_session(const char *name, struct session *s)
1.1 nicm 257: {
1.19 nicm 258: struct cmd_find_state fs;
259:
260: if (session_alive(s))
1.25 nicm 261: cmd_find_from_session(&fs, s, 0);
1.19 nicm 262: else
1.25 nicm 263: cmd_find_from_nothing(&fs, 0);
1.19 nicm 264: notify_add(name, &fs, NULL, s, NULL, NULL);
265: }
266:
267: void
1.21 nicm 268: notify_winlink(const char *name, struct winlink *wl)
1.19 nicm 269: {
270: struct cmd_find_state fs;
271:
1.25 nicm 272: cmd_find_from_winlink(&fs, wl, 0);
1.21 nicm 273: notify_add(name, &fs, NULL, wl->session, wl->window, NULL);
1.1 nicm 274: }
275:
276: void
1.18 nicm 277: notify_session_window(const char *name, struct session *s, struct window *w)
1.1 nicm 278: {
1.19 nicm 279: struct cmd_find_state fs;
280:
1.25 nicm 281: cmd_find_from_session_window(&fs, s, w, 0);
1.19 nicm 282: notify_add(name, &fs, NULL, s, w, NULL);
1.1 nicm 283: }
284:
285: void
1.18 nicm 286: notify_window(const char *name, struct window *w)
1.1 nicm 287: {
1.19 nicm 288: struct cmd_find_state fs;
289:
1.25 nicm 290: cmd_find_from_window(&fs, w, 0);
1.19 nicm 291: notify_add(name, &fs, NULL, NULL, w, NULL);
1.1 nicm 292: }
293:
294: void
1.18 nicm 295: notify_pane(const char *name, struct window_pane *wp)
1.1 nicm 296: {
1.19 nicm 297: struct cmd_find_state fs;
298:
1.25 nicm 299: cmd_find_from_pane(&fs, wp, 0);
1.19 nicm 300: notify_add(name, &fs, NULL, NULL, NULL, wp);
1.1 nicm 301: }