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