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