Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  * Copyright (c) 2012 George Nachman <tmux (at) georgester.com>
      6  *
      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.
     10  *
     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.
     18  */
     19 
     20 #include <sys/types.h>
     21 
     22 #include <stdlib.h>
     23 
     24 #include "tmux.h"
     25 
     26 #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
     27 	((c) != NULL && ((c)->flags & CLIENT_CONTROL))
     28 
     29 void
     30 control_notify_pane_mode_changed(int pane)
     31 {
     32 	struct client	*c;
     33 
     34 	TAILQ_FOREACH(c, &clients, entry) {
     35 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
     36 			continue;
     37 
     38 		control_write(c, "%%pane-mode-changed %%%u", pane);
     39 	}
     40 }
     41 
     42 void
     43 control_notify_window_layout_changed(struct window *w)
     44 {
     45 	struct client	*c;
     46 	struct session	*s;
     47 	struct winlink	*wl;
     48 	const char	*template;
     49 	char		*cp;
     50 
     51 	template = "%layout-change #{window_id} #{window_layout} "
     52 	    "#{window_visible_layout} #{window_raw_flags}";
     53 
     54 	TAILQ_FOREACH(c, &clients, entry) {
     55 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
     56 			continue;
     57 		s = c->session;
     58 
     59 		if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
     60 			continue;
     61 
     62 		/*
     63 		 * When the last pane in a window is closed it won't have a
     64 		 * layout root and we don't need to inform the client about the
     65 		 * layout change because the whole window will go away soon.
     66 		 */
     67 		if (w->layout_root == NULL)
     68 			continue;
     69 
     70 		wl = winlink_find_by_window(&s->windows, w);
     71 		if (wl != NULL) {
     72 			cp = format_single(NULL, template, c, NULL, wl, NULL);
     73 			control_write(c, "%s", cp);
     74 			free(cp);
     75 		}
     76 	}
     77 }
     78 
     79 void
     80 control_notify_window_pane_changed(struct window *w)
     81 {
     82 	struct client	*c;
     83 
     84 	TAILQ_FOREACH(c, &clients, entry) {
     85 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
     86 			continue;
     87 
     88 		control_write(c, "%%window-pane-changed @%u %%%u", w->id,
     89 		    w->active->id);
     90 	}
     91 }
     92 
     93 void
     94 control_notify_window_unlinked(__unused struct session *s, struct window *w)
     95 {
     96 	struct client	*c;
     97 	struct session	*cs;
     98 
     99 	TAILQ_FOREACH(c, &clients, entry) {
    100 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
    101 			continue;
    102 		cs = c->session;
    103 
    104 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
    105 			control_write(c, "%%window-close @%u", w->id);
    106 		else
    107 			control_write(c, "%%unlinked-window-close @%u", w->id);
    108 	}
    109 }
    110 
    111 void
    112 control_notify_window_linked(__unused struct session *s, struct window *w)
    113 {
    114 	struct client	*c;
    115 	struct session	*cs;
    116 
    117 	TAILQ_FOREACH(c, &clients, entry) {
    118 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
    119 			continue;
    120 		cs = c->session;
    121 
    122 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
    123 			control_write(c, "%%window-add @%u", w->id);
    124 		else
    125 			control_write(c, "%%unlinked-window-add @%u", w->id);
    126 	}
    127 }
    128 
    129 void
    130 control_notify_window_renamed(struct window *w)
    131 {
    132 	struct client	*c;
    133 	struct session	*cs;
    134 
    135 	TAILQ_FOREACH(c, &clients, entry) {
    136 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
    137 			continue;
    138 		cs = c->session;
    139 
    140 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
    141 			control_write(c, "%%window-renamed @%u %s", w->id,
    142 			    w->name);
    143 		} else {
    144 			control_write(c, "%%unlinked-window-renamed @%u %s",
    145 			    w->id, w->name);
    146 		}
    147 	}
    148 }
    149 
    150 void
    151 control_notify_client_session_changed(struct client *cc)
    152 {
    153 	struct client	*c;
    154 	struct session	*s;
    155 
    156 	if (cc->session == NULL)
    157 		return;
    158 	s = cc->session;
    159 
    160 	TAILQ_FOREACH(c, &clients, entry) {
    161 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
    162 			continue;
    163 
    164 		if (cc == c) {
    165 			control_write(c, "%%session-changed $%u %s", s->id,
    166 			    s->name);
    167 		} else {
    168 			control_write(c, "%%client-session-changed %s $%u %s",
    169 			    cc->name, s->id, s->name);
    170 		}
    171 	}
    172 }
    173 
    174 void
    175 control_notify_client_detached(struct client *cc)
    176 {
    177 	struct client	*c;
    178 
    179 	TAILQ_FOREACH(c, &clients, entry) {
    180 		if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
    181 			control_write(c, "%%client-detached %s", cc->name);
    182 	}
    183 }
    184 
    185 void
    186 control_notify_session_renamed(struct session *s)
    187 {
    188 	struct client	*c;
    189 
    190 	TAILQ_FOREACH(c, &clients, entry) {
    191 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    192 			continue;
    193 
    194 		control_write(c, "%%session-renamed $%u %s", s->id, s->name);
    195 	}
    196 }
    197 
    198 void
    199 control_notify_session_created(__unused struct session *s)
    200 {
    201 	struct client	*c;
    202 
    203 	TAILQ_FOREACH(c, &clients, entry) {
    204 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    205 			continue;
    206 
    207 		control_write(c, "%%sessions-changed");
    208 	}
    209 }
    210 
    211 void
    212 control_notify_session_closed(__unused struct session *s)
    213 {
    214 	struct client	*c;
    215 
    216 	TAILQ_FOREACH(c, &clients, entry) {
    217 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    218 			continue;
    219 
    220 		control_write(c, "%%sessions-changed");
    221 	}
    222 }
    223 
    224 void
    225 control_notify_session_window_changed(struct session *s)
    226 {
    227 	struct client	*c;
    228 
    229 	TAILQ_FOREACH(c, &clients, entry) {
    230 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    231 			continue;
    232 
    233 		control_write(c, "%%session-window-changed $%u @%u", s->id,
    234 		    s->curw->window->id);
    235 	}
    236 }
    237 
    238 void
    239 control_notify_paste_buffer_changed(const char *name)
    240 {
    241 	struct client	*c;
    242 
    243 	TAILQ_FOREACH(c, &clients, entry) {
    244 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    245 			continue;
    246 
    247 		control_write(c, "%%paste-buffer-changed %s", name);
    248 	}
    249 }
    250 
    251 void
    252 control_notify_paste_buffer_deleted(const char *name)
    253 {
    254 	struct client	*c;
    255 
    256 	TAILQ_FOREACH(c, &clients, entry) {
    257 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
    258 			continue;
    259 
    260 		control_write(c, "%%paste-buffer-deleted %s", name);
    261 	}
    262 }
    263