4 * Copyright (c) 2012 George Nachman <tmux@georgester.com>
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.
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.
19 #include <sys/types.h>
28 struct cmd_find_state fs
;
29 struct format_tree
*formats
;
31 struct client
*client
;
32 struct session
*session
;
33 struct window
*window
;
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
)
42 struct cmdq_item
*new_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
);
52 new_item
= cmdq_get_command(cmdlist
, state
);
53 return (cmdq_insert_after(item
, new_item
));
57 notify_insert_hook(struct cmdq_item
*item
, struct notify_entry
*ne
)
59 struct cmd_find_state fs
;
61 struct cmdq_state
*state
;
62 struct options_entry
*o
;
63 struct options_array_item
*a
;
64 struct cmd_list
*cmdlist
;
66 struct cmd_parse_result
*pr
;
68 log_debug("%s: inserting hook %s", __func__
, ne
->name
);
70 cmd_find_clear_state(&fs
, 0);
71 if (cmd_find_empty_state(&ne
->fs
) || !cmd_find_valid_state(&ne
->fs
))
72 cmd_find_from_nothing(&fs
, 0);
74 cmd_find_copy_state(&fs
, &ne
->fs
);
77 oo
= global_s_options
;
80 o
= options_get(oo
, ne
->name
);
81 if (o
== NULL
&& fs
.wp
!= NULL
) {
83 o
= options_get(oo
, ne
->name
);
85 if (o
== NULL
&& fs
.wl
!= NULL
) {
86 oo
= fs
.wl
->window
->options
;
87 o
= options_get(oo
, ne
->name
);
90 log_debug("%s: hook %s not found", __func__
, ne
->name
);
94 state
= cmdq_new_state(&fs
, NULL
, CMDQ_STATE_NOHOOKS
);
95 cmdq_add_formats(state
, ne
->formats
);
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
);
106 case CMD_PARSE_SUCCESS
:
107 notify_insert_one_hook(item
, ne
, pr
->cmdlist
, state
);
111 a
= options_array_first(o
);
113 cmdlist
= options_array_item_value(a
)->cmdlist
;
114 item
= notify_insert_one_hook(item
, ne
, cmdlist
, state
);
115 a
= options_array_next(a
);
119 cmdq_free_state(state
);
122 static enum cmd_retval
123 notify_callback(struct cmdq_item
*item
, void *data
)
125 struct notify_entry
*ne
= data
;
127 log_debug("%s: %s", __func__
, ne
->name
);
129 if (strcmp(ne
->name
, "pane-mode-changed") == 0)
130 control_notify_pane_mode_changed(ne
->pane
);
131 if (strcmp(ne
->name
, "window-layout-changed") == 0)
132 control_notify_window_layout_changed(ne
->window
);
133 if (strcmp(ne
->name
, "window-pane-changed") == 0)
134 control_notify_window_pane_changed(ne
->window
);
135 if (strcmp(ne
->name
, "window-unlinked") == 0)
136 control_notify_window_unlinked(ne
->session
, ne
->window
);
137 if (strcmp(ne
->name
, "window-linked") == 0)
138 control_notify_window_linked(ne
->session
, ne
->window
);
139 if (strcmp(ne
->name
, "window-renamed") == 0)
140 control_notify_window_renamed(ne
->window
);
141 if (strcmp(ne
->name
, "client-session-changed") == 0)
142 control_notify_client_session_changed(ne
->client
);
143 if (strcmp(ne
->name
, "client-detached") == 0)
144 control_notify_client_detached(ne
->client
);
145 if (strcmp(ne
->name
, "session-renamed") == 0)
146 control_notify_session_renamed(ne
->session
);
147 if (strcmp(ne
->name
, "session-created") == 0)
148 control_notify_session_created(ne
->session
);
149 if (strcmp(ne
->name
, "session-closed") == 0)
150 control_notify_session_closed(ne
->session
);
151 if (strcmp(ne
->name
, "session-window-changed") == 0)
152 control_notify_session_window_changed(ne
->session
);
153 if (strcmp(ne
->name
, "paste-buffer-changed") == 0)
154 control_notify_paste_buffer_changed(ne
->pbname
);
155 if (strcmp(ne
->name
, "paste-buffer-deleted") == 0)
156 control_notify_paste_buffer_deleted(ne
->pbname
);
158 notify_insert_hook(item
, ne
);
160 if (ne
->client
!= NULL
)
161 server_client_unref(ne
->client
);
162 if (ne
->session
!= NULL
)
163 session_remove_ref(ne
->session
, __func__
);
164 if (ne
->window
!= NULL
)
165 window_remove_ref(ne
->window
, __func__
);
167 if (ne
->fs
.s
!= NULL
)
168 session_remove_ref(ne
->fs
.s
, __func__
);
170 format_free(ne
->formats
);
171 free((void *)ne
->name
);
172 free((void *)ne
->pbname
);
175 return (CMD_RETURN_NORMAL
);
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
,
183 struct notify_entry
*ne
;
184 struct cmdq_item
*item
;
186 item
= cmdq_running(NULL
);
187 if (item
!= NULL
&& (cmdq_get_flags(item
) & CMDQ_STATE_NOHOOKS
))
190 ne
= xcalloc(1, sizeof *ne
);
191 ne
->name
= xstrdup(name
);
196 ne
->pane
= (wp
!= NULL
? (int)wp
->id
: -1);
197 ne
->pbname
= (pbname
!= NULL
? xstrdup(pbname
) : NULL
);
199 ne
->formats
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
200 format_add(ne
->formats
, "hook", "%s", name
);
202 format_add(ne
->formats
, "hook_client", "%s", c
->name
);
204 format_add(ne
->formats
, "hook_session", "$%u", s
->id
);
205 format_add(ne
->formats
, "hook_session_name", "%s", s
->name
);
208 format_add(ne
->formats
, "hook_window", "@%u", w
->id
);
209 format_add(ne
->formats
, "hook_window_name", "%s", w
->name
);
212 format_add(ne
->formats
, "hook_pane", "%%%d", wp
->id
);
213 format_log_debug(ne
->formats
, __func__
);
218 session_add_ref(s
, __func__
);
220 window_add_ref(w
, __func__
);
222 cmd_find_copy_state(&ne
->fs
, fs
);
223 if (ne
->fs
.s
!= NULL
) /* cmd_find_valid_state needs session */
224 session_add_ref(ne
->fs
.s
, __func__
);
226 cmdq_append(NULL
, cmdq_get_callback(notify_callback
, ne
));
230 notify_hook(struct cmdq_item
*item
, const char *name
)
232 struct cmd_find_state
*target
= cmdq_get_target(item
);
233 struct notify_entry ne
;
235 memset(&ne
, 0, sizeof ne
);
238 cmd_find_copy_state(&ne
.fs
, target
);
240 ne
.client
= cmdq_get_client(item
);
241 ne
.session
= target
->s
;
242 ne
.window
= target
->w
;
243 ne
.pane
= (target
->wp
!= NULL
? (int)target
->wp
->id
: -1);
245 ne
.formats
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
246 format_add(ne
.formats
, "hook", "%s", name
);
247 format_log_debug(ne
.formats
, __func__
);
249 notify_insert_hook(item
, &ne
);
250 format_free(ne
.formats
);
254 notify_client(const char *name
, struct client
*c
)
256 struct cmd_find_state fs
;
258 cmd_find_from_client(&fs
, c
, 0);
259 notify_add(name
, &fs
, c
, NULL
, NULL
, NULL
, NULL
);
263 notify_session(const char *name
, struct session
*s
)
265 struct cmd_find_state fs
;
267 if (session_alive(s
))
268 cmd_find_from_session(&fs
, s
, 0);
270 cmd_find_from_nothing(&fs
, 0);
271 notify_add(name
, &fs
, NULL
, s
, NULL
, NULL
, NULL
);
275 notify_winlink(const char *name
, struct winlink
*wl
)
277 struct cmd_find_state fs
;
279 cmd_find_from_winlink(&fs
, wl
, 0);
280 notify_add(name
, &fs
, NULL
, wl
->session
, wl
->window
, NULL
, NULL
);
284 notify_session_window(const char *name
, struct session
*s
, struct window
*w
)
286 struct cmd_find_state fs
;
288 cmd_find_from_session_window(&fs
, s
, w
, 0);
289 notify_add(name
, &fs
, NULL
, s
, w
, NULL
, NULL
);
293 notify_window(const char *name
, struct window
*w
)
295 struct cmd_find_state fs
;
297 cmd_find_from_window(&fs
, w
, 0);
298 notify_add(name
, &fs
, NULL
, NULL
, w
, NULL
, NULL
);
302 notify_pane(const char *name
, struct window_pane
*wp
)
304 struct cmd_find_state fs
;
306 cmd_find_from_pane(&fs
, wp
, 0);
307 notify_add(name
, &fs
, NULL
, NULL
, NULL
, wp
, NULL
);
311 notify_paste_buffer(const char *pbname
, int deleted
)
313 struct cmd_find_state fs
;
315 cmd_find_clear_state(&fs
, 0);
317 notify_add("paste-buffer-deleted", &fs
, NULL
, NULL
, NULL
, NULL
,
320 notify_add("paste-buffer-changed", &fs
, NULL
, NULL
, NULL
, NULL
,