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>
20 #include <sys/queue.h>
29 struct cmd_find_state fs
;
30 struct format_tree
*formats
;
32 struct client
*client
;
33 struct session
*session
;
34 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
);
154 notify_insert_hook(item
, ne
);
156 if (ne
->client
!= NULL
)
157 server_client_unref(ne
->client
);
158 if (ne
->session
!= NULL
)
159 session_remove_ref(ne
->session
, __func__
);
160 if (ne
->window
!= NULL
)
161 window_remove_ref(ne
->window
, __func__
);
163 if (ne
->fs
.s
!= NULL
)
164 session_remove_ref(ne
->fs
.s
, __func__
);
166 format_free(ne
->formats
);
167 free((void *)ne
->name
);
170 return (CMD_RETURN_NORMAL
);
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
)
177 struct notify_entry
*ne
;
178 struct cmdq_item
*item
;
180 item
= cmdq_running(NULL
);
181 if (item
!= NULL
&& (cmdq_get_flags(item
) & CMDQ_STATE_NOHOOKS
))
184 ne
= xcalloc(1, sizeof *ne
);
185 ne
->name
= xstrdup(name
);
190 ne
->pane
= (wp
!= NULL
? wp
->id
: -1);
192 ne
->formats
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
193 format_add(ne
->formats
, "hook", "%s", name
);
195 format_add(ne
->formats
, "hook_client", "%s", c
->name
);
197 format_add(ne
->formats
, "hook_session", "$%u", s
->id
);
198 format_add(ne
->formats
, "hook_session_name", "%s", s
->name
);
201 format_add(ne
->formats
, "hook_window", "@%u", w
->id
);
202 format_add(ne
->formats
, "hook_window_name", "%s", w
->name
);
205 format_add(ne
->formats
, "hook_pane", "%%%d", wp
->id
);
206 format_log_debug(ne
->formats
, __func__
);
211 session_add_ref(s
, __func__
);
213 window_add_ref(w
, __func__
);
215 cmd_find_copy_state(&ne
->fs
, fs
);
216 if (ne
->fs
.s
!= NULL
) /* cmd_find_valid_state needs session */
217 session_add_ref(ne
->fs
.s
, __func__
);
219 cmdq_append(NULL
, cmdq_get_callback(notify_callback
, ne
));
223 notify_hook(struct cmdq_item
*item
, const char *name
)
225 struct cmd_find_state
*target
= cmdq_get_target(item
);
226 struct notify_entry ne
;
228 memset(&ne
, 0, sizeof ne
);
231 cmd_find_copy_state(&ne
.fs
, target
);
233 ne
.client
= cmdq_get_client(item
);
234 ne
.session
= target
->s
;
235 ne
.window
= target
->w
;
236 ne
.pane
= (target
->wp
!= NULL
? target
->wp
->id
: -1);
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__
);
242 notify_insert_hook(item
, &ne
);
243 format_free(ne
.formats
);
247 notify_client(const char *name
, struct client
*c
)
249 struct cmd_find_state fs
;
251 cmd_find_from_client(&fs
, c
, 0);
252 notify_add(name
, &fs
, c
, NULL
, NULL
, NULL
);
256 notify_session(const char *name
, struct session
*s
)
258 struct cmd_find_state fs
;
260 if (session_alive(s
))
261 cmd_find_from_session(&fs
, s
, 0);
263 cmd_find_from_nothing(&fs
, 0);
264 notify_add(name
, &fs
, NULL
, s
, NULL
, NULL
);
268 notify_winlink(const char *name
, struct winlink
*wl
)
270 struct cmd_find_state fs
;
272 cmd_find_from_winlink(&fs
, wl
, 0);
273 notify_add(name
, &fs
, NULL
, wl
->session
, wl
->window
, NULL
);
277 notify_session_window(const char *name
, struct session
*s
, struct window
*w
)
279 struct cmd_find_state fs
;
281 cmd_find_from_session_window(&fs
, s
, w
, 0);
282 notify_add(name
, &fs
, NULL
, s
, w
, NULL
);
286 notify_window(const char *name
, struct window
*w
)
288 struct cmd_find_state fs
;
290 cmd_find_from_window(&fs
, w
, 0);
291 notify_add(name
, &fs
, NULL
, NULL
, w
, NULL
);
295 notify_pane(const char *name
, struct window_pane
*wp
)
297 struct cmd_find_state fs
;
299 cmd_find_from_pane(&fs
, wp
, 0);
300 notify_add(name
, &fs
, NULL
, NULL
, NULL
, wp
);