control-notify.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. * Copyright (c) 2012 George Nachman <tmux@georgester.com>
  5. *
  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.
  9. *
  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.
  17. */
  18. #include <sys/types.h>
  19. #include <stdlib.h>
  20. #include "tmux.h"
  21. #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
  22. ((c) != NULL && ((c)->flags & CLIENT_CONTROL))
  23. void
  24. control_notify_input(struct client *c, struct window_pane *wp,
  25. struct evbuffer *input)
  26. {
  27. u_char *buf;
  28. size_t len;
  29. struct evbuffer *message;
  30. u_int i;
  31. if (c->session == NULL)
  32. return;
  33. buf = EVBUFFER_DATA(input);
  34. len = EVBUFFER_LENGTH(input);
  35. /*
  36. * Only write input if the window pane is linked to a window belonging
  37. * to the client's session.
  38. */
  39. if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
  40. message = evbuffer_new();
  41. evbuffer_add_printf(message, "%%output %%%u ", wp->id);
  42. for (i = 0; i < len; i++) {
  43. if (buf[i] < ' ' || buf[i] == '\\')
  44. evbuffer_add_printf(message, "\\%03o", buf[i]);
  45. else
  46. evbuffer_add_printf(message, "%c", buf[i]);
  47. }
  48. control_write_buffer(c, message);
  49. evbuffer_free(message);
  50. }
  51. }
  52. void
  53. control_notify_window_layout_changed(struct window *w)
  54. {
  55. struct client *c;
  56. struct session *s;
  57. struct format_tree *ft;
  58. struct winlink *wl;
  59. const char *template;
  60. char *expanded;
  61. template = "%layout-change #{window_id} #{window_layout} "
  62. "#{window_visible_layout} #{window_flags}";
  63. TAILQ_FOREACH(c, &clients, entry) {
  64. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
  65. continue;
  66. s = c->session;
  67. if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
  68. continue;
  69. /*
  70. * When the last pane in a window is closed it won't have a
  71. * layout root and we don't need to inform the client about the
  72. * layout change because the whole window will go away soon.
  73. */
  74. if (w->layout_root == NULL)
  75. continue;
  76. ft = format_create(NULL, 0);
  77. wl = winlink_find_by_window(&s->windows, w);
  78. if (wl != NULL) {
  79. format_defaults(ft, c, NULL, wl, NULL);
  80. expanded = format_expand(ft, template);
  81. control_write(c, "%s", expanded);
  82. free(expanded);
  83. }
  84. format_free(ft);
  85. }
  86. }
  87. void
  88. control_notify_window_unlinked(__unused struct session *s, struct window *w)
  89. {
  90. struct client *c;
  91. struct session *cs;
  92. TAILQ_FOREACH(c, &clients, entry) {
  93. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
  94. continue;
  95. cs = c->session;
  96. if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
  97. control_write(c, "%%window-close @%u", w->id);
  98. else
  99. control_write(c, "%%unlinked-window-close @%u", w->id);
  100. }
  101. }
  102. void
  103. control_notify_window_linked(__unused struct session *s, struct window *w)
  104. {
  105. struct client *c;
  106. struct session *cs;
  107. TAILQ_FOREACH(c, &clients, entry) {
  108. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
  109. continue;
  110. cs = c->session;
  111. if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
  112. control_write(c, "%%window-add @%u", w->id);
  113. else
  114. control_write(c, "%%unlinked-window-add @%u", w->id);
  115. }
  116. }
  117. void
  118. control_notify_window_renamed(struct window *w)
  119. {
  120. struct client *c;
  121. struct session *cs;
  122. TAILQ_FOREACH(c, &clients, entry) {
  123. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
  124. continue;
  125. cs = c->session;
  126. if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
  127. control_write(c, "%%window-renamed @%u %s", w->id,
  128. w->name);
  129. } else {
  130. control_write(c, "%%unlinked-window-renamed @%u %s",
  131. w->id, w->name);
  132. }
  133. }
  134. }
  135. void
  136. control_notify_attached_session_changed(struct client *c)
  137. {
  138. struct session *s;
  139. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
  140. return;
  141. s = c->session;
  142. control_write(c, "%%session-changed $%u %s", s->id, s->name);
  143. }
  144. void
  145. control_notify_session_renamed(struct session *s)
  146. {
  147. struct client *c;
  148. TAILQ_FOREACH(c, &clients, entry) {
  149. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
  150. continue;
  151. control_write(c, "%%session-renamed $%u %s", s->id, s->name);
  152. }
  153. }
  154. void
  155. control_notify_session_created(__unused struct session *s)
  156. {
  157. struct client *c;
  158. TAILQ_FOREACH(c, &clients, entry) {
  159. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
  160. continue;
  161. control_write(c, "%%sessions-changed");
  162. }
  163. }
  164. void
  165. control_notify_session_close(__unused struct session *s)
  166. {
  167. struct client *c;
  168. TAILQ_FOREACH(c, &clients, entry) {
  169. if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
  170. continue;
  171. control_write(c, "%%sessions-changed");
  172. }
  173. }