4 * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
5 * Copyright (c) 2012 George Nachman <tmux@georgester.com>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
31 * Block of data to output. Each client has one "all" queue of blocks and
32 * another queue for each pane (in struct client_offset). %output blocks are
33 * added to both queues and other output lines (notifications) added only to
36 * When a client becomes writeable, data from blocks on the pane queue are sent
37 * up to the maximum size (CLIENT_BUFFER_HIGH). If a block is entirely written,
38 * it is removed from both pane and client queues and if this means non-%output
39 * blocks are now at the head of the client queue, they are written.
41 * This means a %output block holds up any subsequent non-%output blocks until
42 * it is written which enforces ordering even if the client cannot accept the
43 * entire block in one go.
45 struct control_block
{
50 TAILQ_ENTRY(control_block
) entry
;
51 TAILQ_ENTRY(control_block
) all_entry
;
54 /* Control client pane. */
59 * Offsets into the pane data. The first (offset) is the data we have
60 * written; the second (queued) the data we have queued (pointed to by
63 struct window_pane_offset offset
;
64 struct window_pane_offset queued
;
67 #define CONTROL_PANE_OFF 0x1
68 #define CONTROL_PANE_PAUSED 0x2
71 TAILQ_ENTRY(control_pane
) pending_entry
;
73 TAILQ_HEAD(, control_block
) blocks
;
75 RB_ENTRY(control_pane
) entry
;
77 RB_HEAD(control_panes
, control_pane
);
79 /* Subscription pane. */
80 struct control_sub_pane
{
85 RB_ENTRY(control_sub_pane
) entry
;
87 RB_HEAD(control_sub_panes
, control_sub_pane
);
89 /* Subscription window. */
90 struct control_sub_window
{
95 RB_ENTRY(control_sub_window
) entry
;
97 RB_HEAD(control_sub_windows
, control_sub_window
);
99 /* Control client subscription. */
104 enum control_sub_type type
;
108 struct control_sub_panes panes
;
109 struct control_sub_windows windows
;
111 RB_ENTRY(control_sub
) entry
;
113 RB_HEAD(control_subs
, control_sub
);
115 /* Control client state. */
116 struct control_state
{
117 struct control_panes panes
;
119 TAILQ_HEAD(, control_pane
) pending_list
;
122 TAILQ_HEAD(, control_block
) all_blocks
;
124 struct bufferevent
*read_event
;
125 struct bufferevent
*write_event
;
127 struct control_subs subs
;
128 struct event subs_timer
;
131 /* Low and high watermarks. */
132 #define CONTROL_BUFFER_LOW 512
133 #define CONTROL_BUFFER_HIGH 8192
135 /* Minimum to write to each client. */
136 #define CONTROL_WRITE_MINIMUM 32
138 /* Maximum age for clients that are not using pause mode. */
139 #define CONTROL_MAXIMUM_AGE 300000
141 /* Flags to ignore client. */
142 #define CONTROL_IGNORE_FLAGS \
143 (CLIENT_CONTROL_NOOUTPUT| \
144 CLIENT_UNATTACHEDFLAGS)
146 /* Compare client panes. */
148 control_pane_cmp(struct control_pane
*cp1
, struct control_pane
*cp2
)
150 if (cp1
->pane
< cp2
->pane
)
152 if (cp1
->pane
> cp2
->pane
)
156 RB_GENERATE_STATIC(control_panes
, control_pane
, entry
, control_pane_cmp
);
158 /* Compare client subs. */
160 control_sub_cmp(struct control_sub
*csub1
, struct control_sub
*csub2
)
162 return (strcmp(csub1
->name
, csub2
->name
));
164 RB_GENERATE_STATIC(control_subs
, control_sub
, entry
, control_sub_cmp
);
166 /* Compare client subscription panes. */
168 control_sub_pane_cmp(struct control_sub_pane
*csp1
,
169 struct control_sub_pane
*csp2
)
171 if (csp1
->pane
< csp2
->pane
)
173 if (csp1
->pane
> csp2
->pane
)
175 if (csp1
->idx
< csp2
->idx
)
177 if (csp1
->idx
> csp2
->idx
)
181 RB_GENERATE_STATIC(control_sub_panes
, control_sub_pane
, entry
,
182 control_sub_pane_cmp
);
184 /* Compare client subscription windows. */
186 control_sub_window_cmp(struct control_sub_window
*csw1
,
187 struct control_sub_window
*csw2
)
189 if (csw1
->window
< csw2
->window
)
191 if (csw1
->window
> csw2
->window
)
193 if (csw1
->idx
< csw2
->idx
)
195 if (csw1
->idx
> csw2
->idx
)
199 RB_GENERATE_STATIC(control_sub_windows
, control_sub_window
, entry
,
200 control_sub_window_cmp
);
202 /* Free a subscription. */
204 control_free_sub(struct control_state
*cs
, struct control_sub
*csub
)
206 struct control_sub_pane
*csp
, *csp1
;
207 struct control_sub_window
*csw
, *csw1
;
209 RB_FOREACH_SAFE(csp
, control_sub_panes
, &csub
->panes
, csp1
) {
210 RB_REMOVE(control_sub_panes
, &csub
->panes
, csp
);
213 RB_FOREACH_SAFE(csw
, control_sub_windows
, &csub
->windows
, csw1
) {
214 RB_REMOVE(control_sub_windows
, &csub
->windows
, csw
);
219 RB_REMOVE(control_subs
, &cs
->subs
, csub
);
227 control_free_block(struct control_state
*cs
, struct control_block
*cb
)
230 TAILQ_REMOVE(&cs
->all_blocks
, cb
, all_entry
);
234 /* Get pane offsets for this client. */
235 static struct control_pane
*
236 control_get_pane(struct client
*c
, struct window_pane
*wp
)
238 struct control_state
*cs
= c
->control_state
;
239 struct control_pane cp
= { .pane
= wp
->id
};
241 return (RB_FIND(control_panes
, &cs
->panes
, &cp
));
244 /* Add pane offsets for this client. */
245 static struct control_pane
*
246 control_add_pane(struct client
*c
, struct window_pane
*wp
)
248 struct control_state
*cs
= c
->control_state
;
249 struct control_pane
*cp
;
251 cp
= control_get_pane(c
, wp
);
255 cp
= xcalloc(1, sizeof *cp
);
257 RB_INSERT(control_panes
, &cs
->panes
, cp
);
259 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
260 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
261 TAILQ_INIT(&cp
->blocks
);
266 /* Discard output for a pane. */
268 control_discard_pane(struct client
*c
, struct control_pane
*cp
)
270 struct control_state
*cs
= c
->control_state
;
271 struct control_block
*cb
, *cb1
;
273 TAILQ_FOREACH_SAFE(cb
, &cp
->blocks
, entry
, cb1
) {
274 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
275 control_free_block(cs
, cb
);
279 /* Get actual pane for this client. */
280 static struct window_pane
*
281 control_window_pane(struct client
*c
, u_int pane
)
283 struct window_pane
*wp
;
285 if (c
->session
== NULL
)
287 if ((wp
= window_pane_find_by_id(pane
)) == NULL
)
289 if (winlink_find_by_window(&c
->session
->windows
, wp
->window
) == NULL
)
294 /* Reset control offsets. */
296 control_reset_offsets(struct client
*c
)
298 struct control_state
*cs
= c
->control_state
;
299 struct control_pane
*cp
, *cp1
;
301 RB_FOREACH_SAFE(cp
, control_panes
, &cs
->panes
, cp1
) {
302 RB_REMOVE(control_panes
, &cs
->panes
, cp
);
306 TAILQ_INIT(&cs
->pending_list
);
307 cs
->pending_count
= 0;
310 /* Get offsets for client. */
311 struct window_pane_offset
*
312 control_pane_offset(struct client
*c
, struct window_pane
*wp
, int *off
)
314 struct control_state
*cs
= c
->control_state
;
315 struct control_pane
*cp
;
317 if (c
->flags
& CLIENT_CONTROL_NOOUTPUT
) {
322 cp
= control_get_pane(c
, wp
);
323 if (cp
== NULL
|| (cp
->flags
& CONTROL_PANE_PAUSED
)) {
327 if (cp
->flags
& CONTROL_PANE_OFF
) {
331 *off
= (EVBUFFER_LENGTH(cs
->write_event
->output
) >= CONTROL_BUFFER_LOW
);
332 return (&cp
->offset
);
335 /* Set pane as on. */
337 control_set_pane_on(struct client
*c
, struct window_pane
*wp
)
339 struct control_pane
*cp
;
341 cp
= control_get_pane(c
, wp
);
342 if (cp
!= NULL
&& (cp
->flags
& CONTROL_PANE_OFF
)) {
343 cp
->flags
&= ~CONTROL_PANE_OFF
;
344 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
345 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
349 /* Set pane as off. */
351 control_set_pane_off(struct client
*c
, struct window_pane
*wp
)
353 struct control_pane
*cp
;
355 cp
= control_add_pane(c
, wp
);
356 cp
->flags
|= CONTROL_PANE_OFF
;
359 /* Continue a paused pane. */
361 control_continue_pane(struct client
*c
, struct window_pane
*wp
)
363 struct control_pane
*cp
;
365 cp
= control_get_pane(c
, wp
);
366 if (cp
!= NULL
&& (cp
->flags
& CONTROL_PANE_PAUSED
)) {
367 cp
->flags
&= ~CONTROL_PANE_PAUSED
;
368 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
369 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
370 control_write(c
, "%%continue %%%u", wp
->id
);
376 control_pause_pane(struct client
*c
, struct window_pane
*wp
)
378 struct control_pane
*cp
;
380 cp
= control_add_pane(c
, wp
);
381 if (~cp
->flags
& CONTROL_PANE_PAUSED
) {
382 cp
->flags
|= CONTROL_PANE_PAUSED
;
383 control_discard_pane(c
, cp
);
384 control_write(c
, "%%pause %%%u", wp
->id
);
389 static void printflike(2, 0)
390 control_vwrite(struct client
*c
, const char *fmt
, va_list ap
)
392 struct control_state
*cs
= c
->control_state
;
395 xvasprintf(&s
, fmt
, ap
);
396 log_debug("%s: %s: writing line: %s", __func__
, c
->name
, s
);
398 bufferevent_write(cs
->write_event
, s
, strlen(s
));
399 bufferevent_write(cs
->write_event
, "\n", 1);
401 bufferevent_enable(cs
->write_event
, EV_WRITE
);
407 control_write(struct client
*c
, const char *fmt
, ...)
409 struct control_state
*cs
= c
->control_state
;
410 struct control_block
*cb
;
415 if (TAILQ_EMPTY(&cs
->all_blocks
)) {
416 control_vwrite(c
, fmt
, ap
);
421 cb
= xcalloc(1, sizeof *cb
);
422 xvasprintf(&cb
->line
, fmt
, ap
);
423 TAILQ_INSERT_TAIL(&cs
->all_blocks
, cb
, all_entry
);
426 log_debug("%s: %s: storing line: %s", __func__
, c
->name
, cb
->line
);
427 bufferevent_enable(cs
->write_event
, EV_WRITE
);
432 /* Check age for this pane. */
434 control_check_age(struct client
*c
, struct window_pane
*wp
,
435 struct control_pane
*cp
)
437 struct control_block
*cb
;
440 cb
= TAILQ_FIRST(&cp
->blocks
);
448 log_debug("%s: %s: %%%u is %llu behind", __func__
, c
->name
, wp
->id
,
449 (unsigned long long)age
);
451 if (c
->flags
& CLIENT_CONTROL_PAUSEAFTER
) {
452 if (age
< c
->pause_age
)
454 cp
->flags
|= CONTROL_PANE_PAUSED
;
455 control_discard_pane(c
, cp
);
456 control_write(c
, "%%pause %%%u", wp
->id
);
458 if (age
< CONTROL_MAXIMUM_AGE
)
460 c
->exit_message
= xstrdup("too far behind");
461 c
->flags
|= CLIENT_EXIT
;
467 /* Write output from a pane. */
469 control_write_output(struct client
*c
, struct window_pane
*wp
)
471 struct control_state
*cs
= c
->control_state
;
472 struct control_pane
*cp
;
473 struct control_block
*cb
;
476 if (winlink_find_by_window(&c
->session
->windows
, wp
->window
) == NULL
)
479 if (c
->flags
& CONTROL_IGNORE_FLAGS
) {
480 cp
= control_get_pane(c
, wp
);
485 cp
= control_add_pane(c
, wp
);
486 if (cp
->flags
& (CONTROL_PANE_OFF
|CONTROL_PANE_PAUSED
))
488 if (control_check_age(c
, wp
, cp
))
491 window_pane_get_new_data(wp
, &cp
->queued
, &new_size
);
494 window_pane_update_used_data(wp
, &cp
->queued
, new_size
);
496 cb
= xcalloc(1, sizeof *cb
);
498 TAILQ_INSERT_TAIL(&cs
->all_blocks
, cb
, all_entry
);
501 TAILQ_INSERT_TAIL(&cp
->blocks
, cb
, entry
);
502 log_debug("%s: %s: new output block of %zu for %%%u", __func__
, c
->name
,
505 if (!cp
->pending_flag
) {
506 log_debug("%s: %s: %%%u now pending", __func__
, c
->name
,
508 TAILQ_INSERT_TAIL(&cs
->pending_list
, cp
, pending_entry
);
509 cp
->pending_flag
= 1;
512 bufferevent_enable(cs
->write_event
, EV_WRITE
);
516 log_debug("%s: %s: ignoring pane %%%u", __func__
, c
->name
, wp
->id
);
517 window_pane_update_used_data(wp
, &cp
->offset
, SIZE_MAX
);
518 window_pane_update_used_data(wp
, &cp
->queued
, SIZE_MAX
);
521 /* Control client error callback. */
522 static enum cmd_retval
523 control_error(struct cmdq_item
*item
, void *data
)
525 struct client
*c
= cmdq_get_client(item
);
528 cmdq_guard(item
, "begin", 1);
529 control_write(c
, "parse error: %s", error
);
530 cmdq_guard(item
, "error", 1);
533 return (CMD_RETURN_NORMAL
);
536 /* Control client error callback. */
538 control_error_callback(__unused
struct bufferevent
*bufev
,
539 __unused
short what
, void *data
)
541 struct client
*c
= data
;
543 c
->flags
|= CLIENT_EXIT
;
546 /* Control client input callback. Read lines and fire commands. */
548 control_read_callback(__unused
struct bufferevent
*bufev
, void *data
)
550 struct client
*c
= data
;
551 struct control_state
*cs
= c
->control_state
;
552 struct evbuffer
*buffer
= cs
->read_event
->input
;
554 struct cmdq_state
*state
;
555 enum cmd_parse_status status
;
558 line
= evbuffer_readln(buffer
, NULL
, EVBUFFER_EOL_LF
);
561 log_debug("%s: %s: %s", __func__
, c
->name
, line
);
562 if (*line
== '\0') { /* empty line detach */
564 c
->flags
|= CLIENT_EXIT
;
568 state
= cmdq_new_state(NULL
, NULL
, CMDQ_STATE_CONTROL
);
569 status
= cmd_parse_and_append(line
, NULL
, c
, state
, &error
);
570 if (status
== CMD_PARSE_ERROR
)
571 cmdq_append(c
, cmdq_get_callback(control_error
, error
));
572 cmdq_free_state(state
);
578 /* Does this control client have outstanding data to write? */
580 control_all_done(struct client
*c
)
582 struct control_state
*cs
= c
->control_state
;
584 if (!TAILQ_EMPTY(&cs
->all_blocks
))
586 return (EVBUFFER_LENGTH(cs
->write_event
->output
) == 0);
589 /* Flush all blocks until output. */
591 control_flush_all_blocks(struct client
*c
)
593 struct control_state
*cs
= c
->control_state
;
594 struct control_block
*cb
, *cb1
;
596 TAILQ_FOREACH_SAFE(cb
, &cs
->all_blocks
, all_entry
, cb1
) {
599 log_debug("%s: %s: flushing line: %s", __func__
, c
->name
,
602 bufferevent_write(cs
->write_event
, cb
->line
, strlen(cb
->line
));
603 bufferevent_write(cs
->write_event
, "\n", 1);
604 control_free_block(cs
, cb
);
608 /* Append data to buffer. */
609 static struct evbuffer
*
610 control_append_data(struct client
*c
, struct control_pane
*cp
, uint64_t age
,
611 struct evbuffer
*message
, struct window_pane
*wp
, size_t size
)
617 if (message
== NULL
) {
618 message
= evbuffer_new();
620 fatalx("out of memory");
621 if (c
->flags
& CLIENT_CONTROL_PAUSEAFTER
) {
622 evbuffer_add_printf(message
,
623 "%%extended-output %%%u %llu : ", wp
->id
,
624 (unsigned long long)age
);
626 evbuffer_add_printf(message
, "%%output %%%u ", wp
->id
);
629 new_data
= window_pane_get_new_data(wp
, &cp
->offset
, &new_size
);
631 fatalx("not enough data: %zu < %zu", new_size
, size
);
632 for (i
= 0; i
< size
; i
++) {
633 if (new_data
[i
] < ' ' || new_data
[i
] == '\\')
634 evbuffer_add_printf(message
, "\\%03o", new_data
[i
]);
636 evbuffer_add_printf(message
, "%c", new_data
[i
]);
638 window_pane_update_used_data(wp
, &cp
->offset
, size
);
644 control_write_data(struct client
*c
, struct evbuffer
*message
)
646 struct control_state
*cs
= c
->control_state
;
648 log_debug("%s: %s: %.*s", __func__
, c
->name
,
649 (int)EVBUFFER_LENGTH(message
), EVBUFFER_DATA(message
));
651 evbuffer_add(message
, "\n", 1);
652 bufferevent_write_buffer(cs
->write_event
, message
);
653 evbuffer_free(message
);
656 /* Write output to client. */
658 control_write_pending(struct client
*c
, struct control_pane
*cp
, size_t limit
)
660 struct control_state
*cs
= c
->control_state
;
661 struct window_pane
*wp
= NULL
;
662 struct evbuffer
*message
= NULL
;
663 size_t used
= 0, size
;
664 struct control_block
*cb
, *cb1
;
665 uint64_t age
, t
= get_timer();
667 wp
= control_window_pane(c
, cp
->pane
);
668 if (wp
== NULL
|| wp
->fd
== -1) {
669 TAILQ_FOREACH_SAFE(cb
, &cp
->blocks
, entry
, cb1
) {
670 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
671 control_free_block(cs
, cb
);
673 control_flush_all_blocks(c
);
677 while (used
!= limit
&& !TAILQ_EMPTY(&cp
->blocks
)) {
678 if (control_check_age(c
, wp
, cp
)) {
680 evbuffer_free(message
);
685 cb
= TAILQ_FIRST(&cp
->blocks
);
690 log_debug("%s: %s: output block %zu (age %llu) for %%%u "
691 "(used %zu/%zu)", __func__
, c
->name
, cb
->size
,
692 (unsigned long long)age
, cp
->pane
, used
, limit
);
695 if (size
> limit
- used
)
699 message
= control_append_data(c
, cp
, age
, message
, wp
, size
);
703 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
704 control_free_block(cs
, cb
);
706 cb
= TAILQ_FIRST(&cs
->all_blocks
);
707 if (cb
!= NULL
&& cb
->size
== 0) {
708 if (wp
!= NULL
&& message
!= NULL
) {
709 control_write_data(c
, message
);
712 control_flush_all_blocks(c
);
717 control_write_data(c
, message
);
718 return (!TAILQ_EMPTY(&cp
->blocks
));
721 /* Control client write callback. */
723 control_write_callback(__unused
struct bufferevent
*bufev
, void *data
)
725 struct client
*c
= data
;
726 struct control_state
*cs
= c
->control_state
;
727 struct control_pane
*cp
, *cp1
;
728 struct evbuffer
*evb
= cs
->write_event
->output
;
731 control_flush_all_blocks(c
);
733 while (EVBUFFER_LENGTH(evb
) < CONTROL_BUFFER_HIGH
) {
734 if (cs
->pending_count
== 0)
736 space
= CONTROL_BUFFER_HIGH
- EVBUFFER_LENGTH(evb
);
737 log_debug("%s: %s: %zu bytes available, %u panes", __func__
,
738 c
->name
, space
, cs
->pending_count
);
740 limit
= (space
/ cs
->pending_count
/ 3); /* 3 bytes for \xxx */
741 if (limit
< CONTROL_WRITE_MINIMUM
)
742 limit
= CONTROL_WRITE_MINIMUM
;
744 TAILQ_FOREACH_SAFE(cp
, &cs
->pending_list
, pending_entry
, cp1
) {
745 if (EVBUFFER_LENGTH(evb
) >= CONTROL_BUFFER_HIGH
)
747 if (control_write_pending(c
, cp
, limit
))
749 TAILQ_REMOVE(&cs
->pending_list
, cp
, pending_entry
);
750 cp
->pending_flag
= 0;
754 if (EVBUFFER_LENGTH(evb
) == 0)
755 bufferevent_disable(cs
->write_event
, EV_WRITE
);
758 /* Initialize for control mode. */
760 control_start(struct client
*c
)
762 struct control_state
*cs
;
764 if (c
->flags
& CLIENT_CONTROLCONTROL
) {
768 setblocking(c
->out_fd
, 0);
769 setblocking(c
->fd
, 0);
771 cs
= c
->control_state
= xcalloc(1, sizeof *cs
);
773 TAILQ_INIT(&cs
->pending_list
);
774 TAILQ_INIT(&cs
->all_blocks
);
777 cs
->read_event
= bufferevent_new(c
->fd
, control_read_callback
,
778 control_write_callback
, control_error_callback
, c
);
779 bufferevent_enable(cs
->read_event
, EV_READ
);
781 if (c
->flags
& CLIENT_CONTROLCONTROL
)
782 cs
->write_event
= cs
->read_event
;
784 cs
->write_event
= bufferevent_new(c
->out_fd
, NULL
,
785 control_write_callback
, control_error_callback
, c
);
787 bufferevent_setwatermark(cs
->write_event
, EV_WRITE
, CONTROL_BUFFER_LOW
,
790 if (c
->flags
& CLIENT_CONTROLCONTROL
) {
791 bufferevent_write(cs
->write_event
, "\033P1000p", 7);
792 bufferevent_enable(cs
->write_event
, EV_WRITE
);
796 /* Discard all output for a client. */
798 control_discard(struct client
*c
)
800 struct control_state
*cs
= c
->control_state
;
801 struct control_pane
*cp
;
803 RB_FOREACH(cp
, control_panes
, &cs
->panes
)
804 control_discard_pane(c
, cp
);
805 bufferevent_disable(cs
->read_event
, EV_READ
);
808 /* Stop control mode. */
810 control_stop(struct client
*c
)
812 struct control_state
*cs
= c
->control_state
;
813 struct control_block
*cb
, *cb1
;
814 struct control_sub
*csub
, *csub1
;
816 if (~c
->flags
& CLIENT_CONTROLCONTROL
)
817 bufferevent_free(cs
->write_event
);
818 bufferevent_free(cs
->read_event
);
820 RB_FOREACH_SAFE(csub
, control_subs
, &cs
->subs
, csub1
)
821 control_free_sub(cs
, csub
);
822 if (evtimer_initialized(&cs
->subs_timer
))
823 evtimer_del(&cs
->subs_timer
);
825 TAILQ_FOREACH_SAFE(cb
, &cs
->all_blocks
, all_entry
, cb1
)
826 control_free_block(cs
, cb
);
827 control_reset_offsets(c
);
832 /* Check session subscription. */
834 control_check_subs_session(struct client
*c
, struct control_sub
*csub
)
836 struct session
*s
= c
->session
;
837 struct format_tree
*ft
;
840 ft
= format_create_defaults(NULL
, c
, s
, NULL
, NULL
);
841 value
= format_expand(ft
, csub
->format
);
844 if (csub
->last
!= NULL
&& strcmp(value
, csub
->last
) == 0) {
849 "%%subscription-changed %s $%u - - - : %s",
850 csub
->name
, s
->id
, value
);
855 /* Check pane subscription. */
857 control_check_subs_pane(struct client
*c
, struct control_sub
*csub
)
859 struct session
*s
= c
->session
;
860 struct window_pane
*wp
;
863 struct format_tree
*ft
;
865 struct control_sub_pane
*csp
, find
;
867 wp
= window_pane_find_by_id(csub
->id
);
868 if (wp
== NULL
|| wp
->fd
== -1)
872 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
873 if (wl
->session
!= s
)
876 ft
= format_create_defaults(NULL
, c
, s
, wl
, wp
);
877 value
= format_expand(ft
, csub
->format
);
883 csp
= RB_FIND(control_sub_panes
, &csub
->panes
, &find
);
885 csp
= xcalloc(1, sizeof *csp
);
888 RB_INSERT(control_sub_panes
, &csub
->panes
, csp
);
891 if (csp
->last
!= NULL
&& strcmp(value
, csp
->last
) == 0) {
896 "%%subscription-changed %s $%u @%u %u %%%u : %s",
897 csub
->name
, s
->id
, w
->id
, wl
->idx
, wp
->id
, value
);
903 /* Check all panes subscription. */
905 control_check_subs_all_panes(struct client
*c
, struct control_sub
*csub
)
907 struct session
*s
= c
->session
;
908 struct window_pane
*wp
;
911 struct format_tree
*ft
;
913 struct control_sub_pane
*csp
, find
;
915 RB_FOREACH(wl
, winlinks
, &s
->windows
) {
917 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
918 ft
= format_create_defaults(NULL
, c
, s
, wl
, wp
);
919 value
= format_expand(ft
, csub
->format
);
925 csp
= RB_FIND(control_sub_panes
, &csub
->panes
, &find
);
927 csp
= xcalloc(1, sizeof *csp
);
930 RB_INSERT(control_sub_panes
, &csub
->panes
, csp
);
933 if (csp
->last
!= NULL
&&
934 strcmp(value
, csp
->last
) == 0) {
939 "%%subscription-changed %s $%u @%u %u %%%u : %s",
940 csub
->name
, s
->id
, w
->id
, wl
->idx
, wp
->id
, value
);
947 /* Check window subscription. */
949 control_check_subs_window(struct client
*c
, struct control_sub
*csub
)
951 struct session
*s
= c
->session
;
954 struct format_tree
*ft
;
956 struct control_sub_window
*csw
, find
;
958 w
= window_find_by_id(csub
->id
);
962 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
963 if (wl
->session
!= s
)
966 ft
= format_create_defaults(NULL
, c
, s
, wl
, NULL
);
967 value
= format_expand(ft
, csub
->format
);
973 csw
= RB_FIND(control_sub_windows
, &csub
->windows
, &find
);
975 csw
= xcalloc(1, sizeof *csw
);
978 RB_INSERT(control_sub_windows
, &csub
->windows
, csw
);
981 if (csw
->last
!= NULL
&& strcmp(value
, csw
->last
) == 0) {
986 "%%subscription-changed %s $%u @%u %u - : %s",
987 csub
->name
, s
->id
, w
->id
, wl
->idx
, value
);
993 /* Check all windows subscription. */
995 control_check_subs_all_windows(struct client
*c
, struct control_sub
*csub
)
997 struct session
*s
= c
->session
;
1000 struct format_tree
*ft
;
1002 struct control_sub_window
*csw
, find
;
1004 RB_FOREACH(wl
, winlinks
, &s
->windows
) {
1007 ft
= format_create_defaults(NULL
, c
, s
, wl
, NULL
);
1008 value
= format_expand(ft
, csub
->format
);
1011 find
.window
= w
->id
;
1014 csw
= RB_FIND(control_sub_windows
, &csub
->windows
, &find
);
1016 csw
= xcalloc(1, sizeof *csw
);
1017 csw
->window
= w
->id
;
1019 RB_INSERT(control_sub_windows
, &csub
->windows
, csw
);
1022 if (csw
->last
!= NULL
&& strcmp(value
, csw
->last
) == 0) {
1027 "%%subscription-changed %s $%u @%u %u - : %s",
1028 csub
->name
, s
->id
, w
->id
, wl
->idx
, value
);
1034 /* Check subscriptions timer. */
1036 control_check_subs_timer(__unused
int fd
, __unused
short events
, void *data
)
1038 struct client
*c
= data
;
1039 struct control_state
*cs
= c
->control_state
;
1040 struct control_sub
*csub
, *csub1
;
1041 struct timeval tv
= { .tv_sec
= 1 };
1043 log_debug("%s: timer fired", __func__
);
1044 evtimer_add(&cs
->subs_timer
, &tv
);
1046 RB_FOREACH_SAFE(csub
, control_subs
, &cs
->subs
, csub1
) {
1047 switch (csub
->type
) {
1048 case CONTROL_SUB_SESSION
:
1049 control_check_subs_session(c
, csub
);
1051 case CONTROL_SUB_PANE
:
1052 control_check_subs_pane(c
, csub
);
1054 case CONTROL_SUB_ALL_PANES
:
1055 control_check_subs_all_panes(c
, csub
);
1057 case CONTROL_SUB_WINDOW
:
1058 control_check_subs_window(c
, csub
);
1060 case CONTROL_SUB_ALL_WINDOWS
:
1061 control_check_subs_all_windows(c
, csub
);
1067 /* Add a subscription. */
1069 control_add_sub(struct client
*c
, const char *name
, enum control_sub_type type
,
1070 int id
, const char *format
)
1072 struct control_state
*cs
= c
->control_state
;
1073 struct control_sub
*csub
, find
;
1074 struct timeval tv
= { .tv_sec
= 1 };
1076 find
.name
= (char *)name
;
1077 if ((csub
= RB_FIND(control_subs
, &cs
->subs
, &find
)) != NULL
)
1078 control_free_sub(cs
, csub
);
1080 csub
= xcalloc(1, sizeof *csub
);
1081 csub
->name
= xstrdup(name
);
1084 csub
->format
= xstrdup(format
);
1085 RB_INSERT(control_subs
, &cs
->subs
, csub
);
1087 RB_INIT(&csub
->panes
);
1088 RB_INIT(&csub
->windows
);
1090 if (!evtimer_initialized(&cs
->subs_timer
))
1091 evtimer_set(&cs
->subs_timer
, control_check_subs_timer
, c
);
1092 if (!evtimer_pending(&cs
->subs_timer
, NULL
))
1093 evtimer_add(&cs
->subs_timer
, &tv
);
1096 /* Remove a subscription. */
1098 control_remove_sub(struct client
*c
, const char *name
)
1100 struct control_state
*cs
= c
->control_state
;
1101 struct control_sub
*csub
, find
;
1103 find
.name
= (char *)name
;
1104 if ((csub
= RB_FIND(control_subs
, &cs
->subs
, &find
)) != NULL
)
1105 control_free_sub(cs
, csub
);
1106 if (RB_EMPTY(&cs
->subs
))
1107 evtimer_del(&cs
->subs_timer
);