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
;
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
)
43 struct cmdq_item
*new_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
);
53 new_item
= cmdq_get_command(cmdlist
, state
);
54 return (cmdq_insert_after(item
, new_item
));
58 notify_insert_hook(struct cmdq_item
*item
, struct notify_entry
*ne
)
60 struct cmd_find_state fs
;
62 struct cmdq_state
*state
;
63 struct options_entry
*o
;
64 struct options_array_item
*a
;
65 struct cmd_list
*cmdlist
;
67 struct cmd_parse_result
*pr
;
69 log_debug("%s: inserting hook %s", __func__
, ne
->name
);
71 cmd_find_clear_state(&fs
, 0);
72 if (cmd_find_empty_state(&ne
->fs
) || !cmd_find_valid_state(&ne
->fs
))
73 cmd_find_from_nothing(&fs
, 0);
75 cmd_find_copy_state(&fs
, &ne
->fs
);
78 oo
= global_s_options
;
81 o
= options_get(oo
, ne
->name
);
82 if (o
== NULL
&& fs
.wp
!= NULL
) {
84 o
= options_get(oo
, ne
->name
);
86 if (o
== NULL
&& fs
.wl
!= NULL
) {
87 oo
= fs
.wl
->window
->options
;
88 o
= options_get(oo
, ne
->name
);
91 log_debug("%s: hook %s not found", __func__
, ne
->name
);
95 state
= cmdq_new_state(&fs
, NULL
, CMDQ_STATE_NOHOOKS
);
96 cmdq_add_formats(state
, ne
->formats
);
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
);
107 case CMD_PARSE_SUCCESS
:
108 notify_insert_one_hook(item
, ne
, pr
->cmdlist
, state
);
112 a
= options_array_first(o
);
114 cmdlist
= options_array_item_value(a
)->cmdlist
;
115 item
= notify_insert_one_hook(item
, ne
, cmdlist
, state
);
116 a
= options_array_next(a
);
120 cmdq_free_state(state
);
123 static enum cmd_retval
124 notify_callback(struct cmdq_item
*item
, void *data
)
126 struct notify_entry
*ne
= data
;
128 log_debug("%s: %s", __func__
, ne
->name
);
130 if (strcmp(ne
->name
, "pane-mode-changed") == 0)
131 control_notify_pane_mode_changed(ne
->pane
);
132 if (strcmp(ne
->name
, "window-layout-changed") == 0)
133 control_notify_window_layout_changed(ne
->window
);
134 if (strcmp(ne
->name
, "window-pane-changed") == 0)
135 control_notify_window_pane_changed(ne
->window
);
136 if (strcmp(ne
->name
, "window-unlinked") == 0)
137 control_notify_window_unlinked(ne
->session
, ne
->window
);
138 if (strcmp(ne
->name
, "window-linked") == 0)
139 control_notify_window_linked(ne
->session
, ne
->window
);
140 if (strcmp(ne
->name
, "window-renamed") == 0)
141 control_notify_window_renamed(ne
->window
);
142 if (strcmp(ne
->name
, "client-session-changed") == 0)
143 control_notify_client_session_changed(ne
->client
);
144 if (strcmp(ne
->name
, "client-detached") == 0)
145 control_notify_client_detached(ne
->client
);
146 if (strcmp(ne
->name
, "session-renamed") == 0)
147 control_notify_session_renamed(ne
->session
);
148 if (strcmp(ne
->name
, "session-created") == 0)
149 control_notify_session_created(ne
->session
);
150 if (strcmp(ne
->name
, "session-closed") == 0)
151 control_notify_session_closed(ne
->session
);
152 if (strcmp(ne
->name
, "session-window-changed") == 0)
153 control_notify_session_window_changed(ne
->session
);
154 if (strcmp(ne
->name
, "paste-buffer-changed") == 0)
155 control_notify_paste_buffer_changed(ne
->pbname
);
156 if (strcmp(ne
->name
, "paste-buffer-deleted") == 0)
157 control_notify_paste_buffer_deleted(ne
->pbname
);
159 notify_insert_hook(item
, ne
);
161 if (ne
->client
!= NULL
)
162 server_client_unref(ne
->client
);
163 if (ne
->session
!= NULL
)
164 session_remove_ref(ne
->session
, __func__
);
165 if (ne
->window
!= NULL
)
166 window_remove_ref(ne
->window
, __func__
);
168 if (ne
->fs
.s
!= NULL
)
169 session_remove_ref(ne
->fs
.s
, __func__
);
171 format_free(ne
->formats
);
172 free((void *)ne
->name
);
173 free((void *)ne
->pbname
);
176 return (CMD_RETURN_NORMAL
);
180 notify_add(const char *name
, struct cmd_find_state
*fs
, struct client
*c
,
181 struct session
*s
, struct window
*w
, struct window_pane
*wp
,
184 struct notify_entry
*ne
;
185 struct cmdq_item
*item
;
187 item
= cmdq_running(NULL
);
188 if (item
!= NULL
&& (cmdq_get_flags(item
) & CMDQ_STATE_NOHOOKS
))
191 ne
= xcalloc(1, sizeof *ne
);
192 ne
->name
= xstrdup(name
);
197 ne
->pane
= (wp
!= NULL
? (int)wp
->id
: -1);
198 ne
->pbname
= (pbname
!= NULL
? xstrdup(pbname
) : NULL
);
200 ne
->formats
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
201 format_add(ne
->formats
, "hook", "%s", name
);
203 format_add(ne
->formats
, "hook_client", "%s", c
->name
);
205 format_add(ne
->formats
, "hook_session", "$%u", s
->id
);
206 format_add(ne
->formats
, "hook_session_name", "%s", s
->name
);
209 format_add(ne
->formats
, "hook_window", "@%u", w
->id
);
210 format_add(ne
->formats
, "hook_window_name", "%s", w
->name
);
213 format_add(ne
->formats
, "hook_pane", "%%%d", wp
->id
);
214 format_log_debug(ne
->formats
, __func__
);
219 session_add_ref(s
, __func__
);
221 window_add_ref(w
, __func__
);
223 cmd_find_copy_state(&ne
->fs
, fs
);
224 if (ne
->fs
.s
!= NULL
) /* cmd_find_valid_state needs session */
225 session_add_ref(ne
->fs
.s
, __func__
);
227 cmdq_append(NULL
, cmdq_get_callback(notify_callback
, ne
));
231 notify_hook(struct cmdq_item
*item
, const char *name
)
233 struct cmd_find_state
*target
= cmdq_get_target(item
);
234 struct notify_entry ne
;
236 memset(&ne
, 0, sizeof ne
);
239 cmd_find_copy_state(&ne
.fs
, target
);
241 ne
.client
= cmdq_get_client(item
);
242 ne
.session
= target
->s
;
243 ne
.window
= target
->w
;
244 ne
.pane
= (target
->wp
!= NULL
? (int)target
->wp
->id
: -1);
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__
);
250 notify_insert_hook(item
, &ne
);
251 format_free(ne
.formats
);
255 notify_client(const char *name
, struct client
*c
)
257 struct cmd_find_state fs
;
259 cmd_find_from_client(&fs
, c
, 0);
260 notify_add(name
, &fs
, c
, NULL
, NULL
, NULL
, NULL
);
264 notify_session(const char *name
, struct session
*s
)
266 struct cmd_find_state fs
;
268 if (session_alive(s
))
269 cmd_find_from_session(&fs
, s
, 0);
271 cmd_find_from_nothing(&fs
, 0);
272 notify_add(name
, &fs
, NULL
, s
, NULL
, NULL
, NULL
);
276 notify_winlink(const char *name
, struct winlink
*wl
)
278 struct cmd_find_state fs
;
280 cmd_find_from_winlink(&fs
, wl
, 0);
281 notify_add(name
, &fs
, NULL
, wl
->session
, wl
->window
, NULL
, NULL
);
285 notify_session_window(const char *name
, struct session
*s
, struct window
*w
)
287 struct cmd_find_state fs
;
289 cmd_find_from_session_window(&fs
, s
, w
, 0);
290 notify_add(name
, &fs
, NULL
, s
, w
, NULL
, NULL
);
294 notify_window(const char *name
, struct window
*w
)
296 struct cmd_find_state fs
;
298 cmd_find_from_window(&fs
, w
, 0);
299 notify_add(name
, &fs
, NULL
, NULL
, w
, NULL
, NULL
);
303 notify_pane(const char *name
, struct window_pane
*wp
)
305 struct cmd_find_state fs
;
307 cmd_find_from_pane(&fs
, wp
, 0);
308 notify_add(name
, &fs
, NULL
, NULL
, NULL
, wp
, NULL
);
312 notify_paste_buffer(const char *pbname
, int deleted
)
314 struct cmd_find_state fs
;
316 cmd_find_clear_state(&fs
, 0);
318 notify_add("paste-buffer-deleted", &fs
, NULL
, NULL
, NULL
, NULL
,
321 notify_add("paste-buffer-changed", &fs
, NULL
, NULL
, NULL
, NULL
,