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>
30 * Block of data to output. Each client has one "all" queue of blocks and
31 * another queue for each pane (in struct client_offset). %output blocks are
32 * added to both queues and other output lines (notifications) added only to
35 * When a client becomes writeable, data from blocks on the pane queue are sent
36 * up to the maximum size (CLIENT_BUFFER_HIGH). If a block is entirely written,
37 * it is removed from both pane and client queues and if this means non-%output
38 * blocks are now at the head of the client queue, they are written.
40 * This means a %output block holds up any subsequent non-%output blocks until
41 * it is written which enforces ordering even if the client cannot accept the
42 * entire block in one go.
44 struct control_block
{
49 TAILQ_ENTRY(control_block
) entry
;
50 TAILQ_ENTRY(control_block
) all_entry
;
53 /* Control client pane. */
58 * Offsets into the pane data. The first (offset) is the data we have
59 * written; the second (queued) the data we have queued (pointed to by
62 struct window_pane_offset offset
;
63 struct window_pane_offset queued
;
66 #define CONTROL_PANE_OFF 0x1
67 #define CONTROL_PANE_PAUSED 0x2
70 TAILQ_ENTRY(control_pane
) pending_entry
;
72 TAILQ_HEAD(, control_block
) blocks
;
74 RB_ENTRY(control_pane
) entry
;
76 RB_HEAD(control_panes
, control_pane
);
78 /* Subscription pane. */
79 struct control_sub_pane
{
84 RB_ENTRY(control_sub_pane
) entry
;
86 RB_HEAD(control_sub_panes
, control_sub_pane
);
88 /* Subscription window. */
89 struct control_sub_window
{
94 RB_ENTRY(control_sub_window
) entry
;
96 RB_HEAD(control_sub_windows
, control_sub_window
);
98 /* Control client subscription. */
103 enum control_sub_type type
;
107 struct control_sub_panes panes
;
108 struct control_sub_windows windows
;
110 RB_ENTRY(control_sub
) entry
;
112 RB_HEAD(control_subs
, control_sub
);
114 /* Control client state. */
115 struct control_state
{
116 struct control_panes panes
;
118 TAILQ_HEAD(, control_pane
) pending_list
;
121 TAILQ_HEAD(, control_block
) all_blocks
;
123 struct bufferevent
*read_event
;
124 struct bufferevent
*write_event
;
126 struct control_subs subs
;
127 struct event subs_timer
;
130 /* Low and high watermarks. */
131 #define CONTROL_BUFFER_LOW 512
132 #define CONTROL_BUFFER_HIGH 8192
134 /* Minimum to write to each client. */
135 #define CONTROL_WRITE_MINIMUM 32
137 /* Maximum age for clients that are not using pause mode. */
138 #define CONTROL_MAXIMUM_AGE 300000
140 /* Flags to ignore client. */
141 #define CONTROL_IGNORE_FLAGS \
142 (CLIENT_CONTROL_NOOUTPUT| \
143 CLIENT_UNATTACHEDFLAGS)
145 /* Compare client panes. */
147 control_pane_cmp(struct control_pane
*cp1
, struct control_pane
*cp2
)
149 if (cp1
->pane
< cp2
->pane
)
151 if (cp1
->pane
> cp2
->pane
)
155 RB_GENERATE_STATIC(control_panes
, control_pane
, entry
, control_pane_cmp
);
157 /* Compare client subs. */
159 control_sub_cmp(struct control_sub
*csub1
, struct control_sub
*csub2
)
161 return (strcmp(csub1
->name
, csub2
->name
));
163 RB_GENERATE_STATIC(control_subs
, control_sub
, entry
, control_sub_cmp
);
165 /* Compare client subscription panes. */
167 control_sub_pane_cmp(struct control_sub_pane
*csp1
,
168 struct control_sub_pane
*csp2
)
170 if (csp1
->pane
< csp2
->pane
)
172 if (csp1
->pane
> csp2
->pane
)
174 if (csp1
->idx
< csp2
->idx
)
176 if (csp1
->idx
> csp2
->idx
)
180 RB_GENERATE_STATIC(control_sub_panes
, control_sub_pane
, entry
,
181 control_sub_pane_cmp
);
183 /* Compare client subscription windows. */
185 control_sub_window_cmp(struct control_sub_window
*csw1
,
186 struct control_sub_window
*csw2
)
188 if (csw1
->window
< csw2
->window
)
190 if (csw1
->window
> csw2
->window
)
192 if (csw1
->idx
< csw2
->idx
)
194 if (csw1
->idx
> csw2
->idx
)
198 RB_GENERATE_STATIC(control_sub_windows
, control_sub_window
, entry
,
199 control_sub_window_cmp
);
201 /* Free a subscription. */
203 control_free_sub(struct control_state
*cs
, struct control_sub
*csub
)
205 struct control_sub_pane
*csp
, *csp1
;
206 struct control_sub_window
*csw
, *csw1
;
208 RB_FOREACH_SAFE(csp
, control_sub_panes
, &csub
->panes
, csp1
) {
209 RB_REMOVE(control_sub_panes
, &csub
->panes
, csp
);
212 RB_FOREACH_SAFE(csw
, control_sub_windows
, &csub
->windows
, csw1
) {
213 RB_REMOVE(control_sub_windows
, &csub
->windows
, csw
);
218 RB_REMOVE(control_subs
, &cs
->subs
, csub
);
226 control_free_block(struct control_state
*cs
, struct control_block
*cb
)
229 TAILQ_REMOVE(&cs
->all_blocks
, cb
, all_entry
);
233 /* Get pane offsets for this client. */
234 static struct control_pane
*
235 control_get_pane(struct client
*c
, struct window_pane
*wp
)
237 struct control_state
*cs
= c
->control_state
;
238 struct control_pane cp
= { .pane
= wp
->id
};
240 return (RB_FIND(control_panes
, &cs
->panes
, &cp
));
243 /* Add pane offsets for this client. */
244 static struct control_pane
*
245 control_add_pane(struct client
*c
, struct window_pane
*wp
)
247 struct control_state
*cs
= c
->control_state
;
248 struct control_pane
*cp
;
250 cp
= control_get_pane(c
, wp
);
254 cp
= xcalloc(1, sizeof *cp
);
256 RB_INSERT(control_panes
, &cs
->panes
, cp
);
258 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
259 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
260 TAILQ_INIT(&cp
->blocks
);
265 /* Discard output for a pane. */
267 control_discard_pane(struct client
*c
, struct control_pane
*cp
)
269 struct control_state
*cs
= c
->control_state
;
270 struct control_block
*cb
, *cb1
;
272 TAILQ_FOREACH_SAFE(cb
, &cp
->blocks
, entry
, cb1
) {
273 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
274 control_free_block(cs
, cb
);
278 /* Get actual pane for this client. */
279 static struct window_pane
*
280 control_window_pane(struct client
*c
, u_int pane
)
282 struct window_pane
*wp
;
284 if (c
->session
== NULL
)
286 if ((wp
= window_pane_find_by_id(pane
)) == NULL
)
288 if (winlink_find_by_window(&c
->session
->windows
, wp
->window
) == NULL
)
293 /* Reset control offsets. */
295 control_reset_offsets(struct client
*c
)
297 struct control_state
*cs
= c
->control_state
;
298 struct control_pane
*cp
, *cp1
;
300 RB_FOREACH_SAFE(cp
, control_panes
, &cs
->panes
, cp1
) {
301 RB_REMOVE(control_panes
, &cs
->panes
, cp
);
305 TAILQ_INIT(&cs
->pending_list
);
306 cs
->pending_count
= 0;
309 /* Get offsets for client. */
310 struct window_pane_offset
*
311 control_pane_offset(struct client
*c
, struct window_pane
*wp
, int *off
)
313 struct control_state
*cs
= c
->control_state
;
314 struct control_pane
*cp
;
316 if (c
->flags
& CLIENT_CONTROL_NOOUTPUT
) {
321 cp
= control_get_pane(c
, wp
);
322 if (cp
== NULL
|| (cp
->flags
& CONTROL_PANE_PAUSED
)) {
326 if (cp
->flags
& CONTROL_PANE_OFF
) {
330 *off
= (EVBUFFER_LENGTH(cs
->write_event
->output
) >= CONTROL_BUFFER_LOW
);
331 return (&cp
->offset
);
334 /* Set pane as on. */
336 control_set_pane_on(struct client
*c
, struct window_pane
*wp
)
338 struct control_pane
*cp
;
340 cp
= control_get_pane(c
, wp
);
341 if (cp
!= NULL
&& (cp
->flags
& CONTROL_PANE_OFF
)) {
342 cp
->flags
&= ~CONTROL_PANE_OFF
;
343 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
344 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
348 /* Set pane as off. */
350 control_set_pane_off(struct client
*c
, struct window_pane
*wp
)
352 struct control_pane
*cp
;
354 cp
= control_add_pane(c
, wp
);
355 cp
->flags
|= CONTROL_PANE_OFF
;
358 /* Continue a paused pane. */
360 control_continue_pane(struct client
*c
, struct window_pane
*wp
)
362 struct control_pane
*cp
;
364 cp
= control_get_pane(c
, wp
);
365 if (cp
!= NULL
&& (cp
->flags
& CONTROL_PANE_PAUSED
)) {
366 cp
->flags
&= ~CONTROL_PANE_PAUSED
;
367 memcpy(&cp
->offset
, &wp
->offset
, sizeof cp
->offset
);
368 memcpy(&cp
->queued
, &wp
->offset
, sizeof cp
->queued
);
369 control_write(c
, "%%continue %%%u", wp
->id
);
375 control_pause_pane(struct client
*c
, struct window_pane
*wp
)
377 struct control_pane
*cp
;
379 cp
= control_add_pane(c
, wp
);
380 if (~cp
->flags
& CONTROL_PANE_PAUSED
) {
381 cp
->flags
|= CONTROL_PANE_PAUSED
;
382 control_discard_pane(c
, cp
);
383 control_write(c
, "%%pause %%%u", wp
->id
);
388 static void printflike(2, 0)
389 control_vwrite(struct client
*c
, const char *fmt
, va_list ap
)
391 struct control_state
*cs
= c
->control_state
;
394 xvasprintf(&s
, fmt
, ap
);
395 log_debug("%s: %s: writing line: %s", __func__
, c
->name
, s
);
397 bufferevent_write(cs
->write_event
, s
, strlen(s
));
398 bufferevent_write(cs
->write_event
, "\n", 1);
400 bufferevent_enable(cs
->write_event
, EV_WRITE
);
406 control_write(struct client
*c
, const char *fmt
, ...)
408 struct control_state
*cs
= c
->control_state
;
409 struct control_block
*cb
;
414 if (TAILQ_EMPTY(&cs
->all_blocks
)) {
415 control_vwrite(c
, fmt
, ap
);
420 cb
= xcalloc(1, sizeof *cb
);
421 xvasprintf(&cb
->line
, fmt
, ap
);
422 TAILQ_INSERT_TAIL(&cs
->all_blocks
, cb
, all_entry
);
425 log_debug("%s: %s: storing line: %s", __func__
, c
->name
, cb
->line
);
426 bufferevent_enable(cs
->write_event
, EV_WRITE
);
431 /* Check age for this pane. */
433 control_check_age(struct client
*c
, struct window_pane
*wp
,
434 struct control_pane
*cp
)
436 struct control_block
*cb
;
439 cb
= TAILQ_FIRST(&cp
->blocks
);
447 log_debug("%s: %s: %%%u is %llu behind", __func__
, c
->name
, wp
->id
,
448 (unsigned long long)age
);
450 if (c
->flags
& CLIENT_CONTROL_PAUSEAFTER
) {
451 if (age
< c
->pause_age
)
453 cp
->flags
|= CONTROL_PANE_PAUSED
;
454 control_discard_pane(c
, cp
);
455 control_write(c
, "%%pause %%%u", wp
->id
);
457 if (age
< CONTROL_MAXIMUM_AGE
)
459 c
->exit_message
= xstrdup("too far behind");
460 c
->flags
|= CLIENT_EXIT
;
466 /* Write output from a pane. */
468 control_write_output(struct client
*c
, struct window_pane
*wp
)
470 struct control_state
*cs
= c
->control_state
;
471 struct control_pane
*cp
;
472 struct control_block
*cb
;
475 if (winlink_find_by_window(&c
->session
->windows
, wp
->window
) == NULL
)
478 if (c
->flags
& CONTROL_IGNORE_FLAGS
) {
479 cp
= control_get_pane(c
, wp
);
484 cp
= control_add_pane(c
, wp
);
485 if (cp
->flags
& (CONTROL_PANE_OFF
|CONTROL_PANE_PAUSED
))
487 if (control_check_age(c
, wp
, cp
))
490 window_pane_get_new_data(wp
, &cp
->queued
, &new_size
);
493 window_pane_update_used_data(wp
, &cp
->queued
, new_size
);
495 cb
= xcalloc(1, sizeof *cb
);
497 TAILQ_INSERT_TAIL(&cs
->all_blocks
, cb
, all_entry
);
500 TAILQ_INSERT_TAIL(&cp
->blocks
, cb
, entry
);
501 log_debug("%s: %s: new output block of %zu for %%%u", __func__
, c
->name
,
504 if (!cp
->pending_flag
) {
505 log_debug("%s: %s: %%%u now pending", __func__
, c
->name
,
507 TAILQ_INSERT_TAIL(&cs
->pending_list
, cp
, pending_entry
);
508 cp
->pending_flag
= 1;
511 bufferevent_enable(cs
->write_event
, EV_WRITE
);
515 log_debug("%s: %s: ignoring pane %%%u", __func__
, c
->name
, wp
->id
);
516 window_pane_update_used_data(wp
, &cp
->offset
, SIZE_MAX
);
517 window_pane_update_used_data(wp
, &cp
->queued
, SIZE_MAX
);
520 /* Control client error callback. */
521 static enum cmd_retval
522 control_error(struct cmdq_item
*item
, void *data
)
524 struct client
*c
= cmdq_get_client(item
);
527 cmdq_guard(item
, "begin", 1);
528 control_write(c
, "parse error: %s", error
);
529 cmdq_guard(item
, "error", 1);
532 return (CMD_RETURN_NORMAL
);
535 /* Control client error callback. */
537 control_error_callback(__unused
struct bufferevent
*bufev
,
538 __unused
short what
, void *data
)
540 struct client
*c
= data
;
542 c
->flags
|= CLIENT_EXIT
;
545 /* Control client input callback. Read lines and fire commands. */
547 control_read_callback(__unused
struct bufferevent
*bufev
, void *data
)
549 struct client
*c
= data
;
550 struct control_state
*cs
= c
->control_state
;
551 struct evbuffer
*buffer
= cs
->read_event
->input
;
553 struct cmdq_state
*state
;
554 enum cmd_parse_status status
;
557 line
= evbuffer_readln(buffer
, NULL
, EVBUFFER_EOL_LF
);
560 log_debug("%s: %s: %s", __func__
, c
->name
, line
);
561 if (*line
== '\0') { /* empty line detach */
563 c
->flags
|= CLIENT_EXIT
;
567 state
= cmdq_new_state(NULL
, NULL
, CMDQ_STATE_CONTROL
);
568 status
= cmd_parse_and_append(line
, NULL
, c
, state
, &error
);
569 if (status
== CMD_PARSE_ERROR
)
570 cmdq_append(c
, cmdq_get_callback(control_error
, error
));
571 cmdq_free_state(state
);
577 /* Does this control client have outstanding data to write? */
579 control_all_done(struct client
*c
)
581 struct control_state
*cs
= c
->control_state
;
583 if (!TAILQ_EMPTY(&cs
->all_blocks
))
585 return (EVBUFFER_LENGTH(cs
->write_event
->output
) == 0);
588 /* Flush all blocks until output. */
590 control_flush_all_blocks(struct client
*c
)
592 struct control_state
*cs
= c
->control_state
;
593 struct control_block
*cb
, *cb1
;
595 TAILQ_FOREACH_SAFE(cb
, &cs
->all_blocks
, all_entry
, cb1
) {
598 log_debug("%s: %s: flushing line: %s", __func__
, c
->name
,
601 bufferevent_write(cs
->write_event
, cb
->line
, strlen(cb
->line
));
602 bufferevent_write(cs
->write_event
, "\n", 1);
603 control_free_block(cs
, cb
);
607 /* Append data to buffer. */
608 static struct evbuffer
*
609 control_append_data(struct client
*c
, struct control_pane
*cp
, uint64_t age
,
610 struct evbuffer
*message
, struct window_pane
*wp
, size_t size
)
616 if (message
== NULL
) {
617 message
= evbuffer_new();
619 fatalx("out of memory");
620 if (c
->flags
& CLIENT_CONTROL_PAUSEAFTER
) {
621 evbuffer_add_printf(message
,
622 "%%extended-output %%%u %llu : ", wp
->id
,
623 (unsigned long long)age
);
625 evbuffer_add_printf(message
, "%%output %%%u ", wp
->id
);
628 new_data
= window_pane_get_new_data(wp
, &cp
->offset
, &new_size
);
630 fatalx("not enough data: %zu < %zu", new_size
, size
);
631 for (i
= 0; i
< size
; i
++) {
632 if (new_data
[i
] < ' ' || new_data
[i
] == '\\')
633 evbuffer_add_printf(message
, "\\%03o", new_data
[i
]);
635 evbuffer_add_printf(message
, "%c", new_data
[i
]);
637 window_pane_update_used_data(wp
, &cp
->offset
, size
);
643 control_write_data(struct client
*c
, struct evbuffer
*message
)
645 struct control_state
*cs
= c
->control_state
;
647 log_debug("%s: %s: %.*s", __func__
, c
->name
,
648 (int)EVBUFFER_LENGTH(message
), EVBUFFER_DATA(message
));
650 evbuffer_add(message
, "\n", 1);
651 bufferevent_write_buffer(cs
->write_event
, message
);
652 evbuffer_free(message
);
655 /* Write output to client. */
657 control_write_pending(struct client
*c
, struct control_pane
*cp
, size_t limit
)
659 struct control_state
*cs
= c
->control_state
;
660 struct window_pane
*wp
= NULL
;
661 struct evbuffer
*message
= NULL
;
662 size_t used
= 0, size
;
663 struct control_block
*cb
, *cb1
;
664 uint64_t age
, t
= get_timer();
666 wp
= control_window_pane(c
, cp
->pane
);
667 if (wp
== NULL
|| wp
->fd
== -1) {
668 TAILQ_FOREACH_SAFE(cb
, &cp
->blocks
, entry
, cb1
) {
669 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
670 control_free_block(cs
, cb
);
672 control_flush_all_blocks(c
);
676 while (used
!= limit
&& !TAILQ_EMPTY(&cp
->blocks
)) {
677 if (control_check_age(c
, wp
, cp
)) {
679 evbuffer_free(message
);
684 cb
= TAILQ_FIRST(&cp
->blocks
);
689 log_debug("%s: %s: output block %zu (age %llu) for %%%u "
690 "(used %zu/%zu)", __func__
, c
->name
, cb
->size
,
691 (unsigned long long)age
, cp
->pane
, used
, limit
);
694 if (size
> limit
- used
)
698 message
= control_append_data(c
, cp
, age
, message
, wp
, size
);
702 TAILQ_REMOVE(&cp
->blocks
, cb
, entry
);
703 control_free_block(cs
, cb
);
705 cb
= TAILQ_FIRST(&cs
->all_blocks
);
706 if (cb
!= NULL
&& cb
->size
== 0) {
707 if (wp
!= NULL
&& message
!= NULL
) {
708 control_write_data(c
, message
);
711 control_flush_all_blocks(c
);
716 control_write_data(c
, message
);
717 return (!TAILQ_EMPTY(&cp
->blocks
));
720 /* Control client write callback. */
722 control_write_callback(__unused
struct bufferevent
*bufev
, void *data
)
724 struct client
*c
= data
;
725 struct control_state
*cs
= c
->control_state
;
726 struct control_pane
*cp
, *cp1
;
727 struct evbuffer
*evb
= cs
->write_event
->output
;
730 control_flush_all_blocks(c
);
732 while (EVBUFFER_LENGTH(evb
) < CONTROL_BUFFER_HIGH
) {
733 if (cs
->pending_count
== 0)
735 space
= CONTROL_BUFFER_HIGH
- EVBUFFER_LENGTH(evb
);
736 log_debug("%s: %s: %zu bytes available, %u panes", __func__
,
737 c
->name
, space
, cs
->pending_count
);
739 limit
= (space
/ cs
->pending_count
/ 3); /* 3 bytes for \xxx */
740 if (limit
< CONTROL_WRITE_MINIMUM
)
741 limit
= CONTROL_WRITE_MINIMUM
;
743 TAILQ_FOREACH_SAFE(cp
, &cs
->pending_list
, pending_entry
, cp1
) {
744 if (EVBUFFER_LENGTH(evb
) >= CONTROL_BUFFER_HIGH
)
746 if (control_write_pending(c
, cp
, limit
))
748 TAILQ_REMOVE(&cs
->pending_list
, cp
, pending_entry
);
749 cp
->pending_flag
= 0;
753 if (EVBUFFER_LENGTH(evb
) == 0)
754 bufferevent_disable(cs
->write_event
, EV_WRITE
);
757 /* Initialize for control mode. */
759 control_start(struct client
*c
)
761 struct control_state
*cs
;
763 if (c
->flags
& CLIENT_CONTROLCONTROL
) {
767 setblocking(c
->out_fd
, 0);
768 setblocking(c
->fd
, 0);
770 cs
= c
->control_state
= xcalloc(1, sizeof *cs
);
772 TAILQ_INIT(&cs
->pending_list
);
773 TAILQ_INIT(&cs
->all_blocks
);
776 cs
->read_event
= bufferevent_new(c
->fd
, control_read_callback
,
777 control_write_callback
, control_error_callback
, c
);
778 if (cs
->read_event
== NULL
)
779 fatalx("out of memory");
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
);
786 if (cs
->write_event
== NULL
)
787 fatalx("out of memory");
789 bufferevent_setwatermark(cs
->write_event
, EV_WRITE
, CONTROL_BUFFER_LOW
,
792 if (c
->flags
& CLIENT_CONTROLCONTROL
) {
793 bufferevent_write(cs
->write_event
, "\033P1000p", 7);
794 bufferevent_enable(cs
->write_event
, EV_WRITE
);
798 /* Control client ready. */
800 control_ready(struct client
*c
)
802 bufferevent_enable(c
->control_state
->read_event
, EV_READ
);
805 /* Discard all output for a client. */
807 control_discard(struct client
*c
)
809 struct control_state
*cs
= c
->control_state
;
810 struct control_pane
*cp
;
812 RB_FOREACH(cp
, control_panes
, &cs
->panes
)
813 control_discard_pane(c
, cp
);
814 bufferevent_disable(cs
->read_event
, EV_READ
);
817 /* Stop control mode. */
819 control_stop(struct client
*c
)
821 struct control_state
*cs
= c
->control_state
;
822 struct control_block
*cb
, *cb1
;
823 struct control_sub
*csub
, *csub1
;
825 if (~c
->flags
& CLIENT_CONTROLCONTROL
)
826 bufferevent_free(cs
->write_event
);
827 bufferevent_free(cs
->read_event
);
829 RB_FOREACH_SAFE(csub
, control_subs
, &cs
->subs
, csub1
)
830 control_free_sub(cs
, csub
);
831 if (evtimer_initialized(&cs
->subs_timer
))
832 evtimer_del(&cs
->subs_timer
);
834 TAILQ_FOREACH_SAFE(cb
, &cs
->all_blocks
, all_entry
, cb1
)
835 control_free_block(cs
, cb
);
836 control_reset_offsets(c
);
841 /* Check session subscription. */
843 control_check_subs_session(struct client
*c
, struct control_sub
*csub
)
845 struct session
*s
= c
->session
;
846 struct format_tree
*ft
;
849 ft
= format_create_defaults(NULL
, c
, s
, NULL
, NULL
);
850 value
= format_expand(ft
, csub
->format
);
853 if (csub
->last
!= NULL
&& strcmp(value
, csub
->last
) == 0) {
858 "%%subscription-changed %s $%u - - - : %s",
859 csub
->name
, s
->id
, value
);
864 /* Check pane subscription. */
866 control_check_subs_pane(struct client
*c
, struct control_sub
*csub
)
868 struct session
*s
= c
->session
;
869 struct window_pane
*wp
;
872 struct format_tree
*ft
;
874 struct control_sub_pane
*csp
, find
;
876 wp
= window_pane_find_by_id(csub
->id
);
877 if (wp
== NULL
|| wp
->fd
== -1)
881 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
882 if (wl
->session
!= s
)
885 ft
= format_create_defaults(NULL
, c
, s
, wl
, wp
);
886 value
= format_expand(ft
, csub
->format
);
892 csp
= RB_FIND(control_sub_panes
, &csub
->panes
, &find
);
894 csp
= xcalloc(1, sizeof *csp
);
897 RB_INSERT(control_sub_panes
, &csub
->panes
, csp
);
900 if (csp
->last
!= NULL
&& strcmp(value
, csp
->last
) == 0) {
905 "%%subscription-changed %s $%u @%u %u %%%u : %s",
906 csub
->name
, s
->id
, w
->id
, wl
->idx
, wp
->id
, value
);
912 /* Check all panes subscription. */
914 control_check_subs_all_panes(struct client
*c
, struct control_sub
*csub
)
916 struct session
*s
= c
->session
;
917 struct window_pane
*wp
;
920 struct format_tree
*ft
;
922 struct control_sub_pane
*csp
, find
;
924 RB_FOREACH(wl
, winlinks
, &s
->windows
) {
926 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
927 ft
= format_create_defaults(NULL
, c
, s
, wl
, wp
);
928 value
= format_expand(ft
, csub
->format
);
934 csp
= RB_FIND(control_sub_panes
, &csub
->panes
, &find
);
936 csp
= xcalloc(1, sizeof *csp
);
939 RB_INSERT(control_sub_panes
, &csub
->panes
, csp
);
942 if (csp
->last
!= NULL
&&
943 strcmp(value
, csp
->last
) == 0) {
948 "%%subscription-changed %s $%u @%u %u %%%u : %s",
949 csub
->name
, s
->id
, w
->id
, wl
->idx
, wp
->id
, value
);
956 /* Check window subscription. */
958 control_check_subs_window(struct client
*c
, struct control_sub
*csub
)
960 struct session
*s
= c
->session
;
963 struct format_tree
*ft
;
965 struct control_sub_window
*csw
, find
;
967 w
= window_find_by_id(csub
->id
);
971 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
972 if (wl
->session
!= s
)
975 ft
= format_create_defaults(NULL
, c
, s
, wl
, NULL
);
976 value
= format_expand(ft
, csub
->format
);
982 csw
= RB_FIND(control_sub_windows
, &csub
->windows
, &find
);
984 csw
= xcalloc(1, sizeof *csw
);
987 RB_INSERT(control_sub_windows
, &csub
->windows
, csw
);
990 if (csw
->last
!= NULL
&& strcmp(value
, csw
->last
) == 0) {
995 "%%subscription-changed %s $%u @%u %u - : %s",
996 csub
->name
, s
->id
, w
->id
, wl
->idx
, value
);
1002 /* Check all windows subscription. */
1004 control_check_subs_all_windows(struct client
*c
, struct control_sub
*csub
)
1006 struct session
*s
= c
->session
;
1009 struct format_tree
*ft
;
1011 struct control_sub_window
*csw
, find
;
1013 RB_FOREACH(wl
, winlinks
, &s
->windows
) {
1016 ft
= format_create_defaults(NULL
, c
, s
, wl
, NULL
);
1017 value
= format_expand(ft
, csub
->format
);
1020 find
.window
= w
->id
;
1023 csw
= RB_FIND(control_sub_windows
, &csub
->windows
, &find
);
1025 csw
= xcalloc(1, sizeof *csw
);
1026 csw
->window
= w
->id
;
1028 RB_INSERT(control_sub_windows
, &csub
->windows
, csw
);
1031 if (csw
->last
!= NULL
&& strcmp(value
, csw
->last
) == 0) {
1036 "%%subscription-changed %s $%u @%u %u - : %s",
1037 csub
->name
, s
->id
, w
->id
, wl
->idx
, value
);
1043 /* Check subscriptions timer. */
1045 control_check_subs_timer(__unused
int fd
, __unused
short events
, void *data
)
1047 struct client
*c
= data
;
1048 struct control_state
*cs
= c
->control_state
;
1049 struct control_sub
*csub
, *csub1
;
1050 struct timeval tv
= { .tv_sec
= 1 };
1052 log_debug("%s: timer fired", __func__
);
1053 evtimer_add(&cs
->subs_timer
, &tv
);
1055 RB_FOREACH_SAFE(csub
, control_subs
, &cs
->subs
, csub1
) {
1056 switch (csub
->type
) {
1057 case CONTROL_SUB_SESSION
:
1058 control_check_subs_session(c
, csub
);
1060 case CONTROL_SUB_PANE
:
1061 control_check_subs_pane(c
, csub
);
1063 case CONTROL_SUB_ALL_PANES
:
1064 control_check_subs_all_panes(c
, csub
);
1066 case CONTROL_SUB_WINDOW
:
1067 control_check_subs_window(c
, csub
);
1069 case CONTROL_SUB_ALL_WINDOWS
:
1070 control_check_subs_all_windows(c
, csub
);
1076 /* Add a subscription. */
1078 control_add_sub(struct client
*c
, const char *name
, enum control_sub_type type
,
1079 int id
, const char *format
)
1081 struct control_state
*cs
= c
->control_state
;
1082 struct control_sub
*csub
, find
;
1083 struct timeval tv
= { .tv_sec
= 1 };
1085 find
.name
= (char *)name
;
1086 if ((csub
= RB_FIND(control_subs
, &cs
->subs
, &find
)) != NULL
)
1087 control_free_sub(cs
, csub
);
1089 csub
= xcalloc(1, sizeof *csub
);
1090 csub
->name
= xstrdup(name
);
1093 csub
->format
= xstrdup(format
);
1094 RB_INSERT(control_subs
, &cs
->subs
, csub
);
1096 RB_INIT(&csub
->panes
);
1097 RB_INIT(&csub
->windows
);
1099 if (!evtimer_initialized(&cs
->subs_timer
))
1100 evtimer_set(&cs
->subs_timer
, control_check_subs_timer
, c
);
1101 if (!evtimer_pending(&cs
->subs_timer
, NULL
))
1102 evtimer_add(&cs
->subs_timer
, &tv
);
1105 /* Remove a subscription. */
1107 control_remove_sub(struct client
*c
, const char *name
)
1109 struct control_state
*cs
= c
->control_state
;
1110 struct control_sub
*csub
, find
;
1112 find
.name
= (char *)name
;
1113 if ((csub
= RB_FIND(control_subs
, &cs
->subs
, &find
)) != NULL
)
1114 control_free_sub(cs
, csub
);
1115 if (RB_EMPTY(&cs
->subs
))
1116 evtimer_del(&cs
->subs_timer
);