Here is TAILQ version of the patch, along with the event loop diff(which
randomly crashes the server for me again)
---
 Makefile.am         |   2 +
 cmd-monitor.c       | 110 ++++++++++++++++++++++++++++
 cmd.c               |   1 +
 examples/monitor.sh | 120 ++++++++++++++++++++++++++++++
 monitor.c           | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tmux.c              |   3 +
 tmux.h              |  71 ++++++++++++++++++
 7 files changed, 513 insertions(+)
 create mode 100644 cmd-monitor.c
 create mode 100755 examples/monitor.sh
 create mode 100644 monitor.c
diff --git a/Makefile.am b/Makefile.am
index 5caa498..af0b35d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -100,6 +100,7 @@ dist_tmux_SOURCES = \
        cmd-load-buffer.c \
        cmd-lock-server.c \
        cmd-move-window.c \
+       cmd-monitor.c \
        cmd-new-session.c \
        cmd-new-window.c \
        cmd-paste-buffer.c \
@@ -154,6 +155,7 @@ dist_tmux_SOURCES = \
        layout.c \
        log.c \
        mode-key.c \
+       monitor.c \
        names.c \
        notify.c \
        options-table.c \
diff --git a/cmd-monitor.c b/cmd-monitor.c
new file mode 100644
index 0000000..9fcbba7
--- /dev/null
+++ b/cmd-monitor.c
@@ -0,0 +1,110 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2013 Thiago de Arruda<tpadilh...@gmail.com>
+ *
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "tmux.h"
+
+enum cmd_retval cmd_monitor_exec(struct cmd *, struct cmd_q *);
+enum cmd_retval monitor_lock(struct monitors *, const char *, struct cmd_q *);
+enum cmd_retval monitor_unlock(struct monitors *, const char *, struct cmd_q *);
+enum cmd_retval monitor_wait(struct monitors *, const char *, struct cmd_q *);
+enum cmd_retval monitor_signal(struct monitors *, const char *, struct cmd_q *);
+
+const struct cmd_entry cmd_monitor_entry = {
+       "monitor", NULL,
+       "luws", 1, 1,
+       "[-l | -u | -w | -s] name",
+       0,
+       NULL,
+       NULL,
+       cmd_monitor_exec
+};
+
+enum cmd_retval
+cmd_monitor_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+       struct args     *args = self->args;
+       const char *name = args->argv[0];
+       struct monitors *head = &global_monitors;
+
+       if (args_has(args, 'l'))
+               return monitor_lock(head, name, cmdq);
+       else if (args_has(args, 'u'))
+               return monitor_unlock(head, name, cmdq);
+       else if (args_has(args, 'w'))
+               return monitor_wait(head, name, cmdq);
+       else if (args_has(args, 's'))
+               return monitor_signal(head, name, cmdq);
+
+       cmdq_error(cmdq, "Must specify an action to be executed on the monitor");
+
+       return (CMD_RETURN_ERROR);
+}
+
+enum cmd_retval
+monitor_lock(struct monitors *head, const char *name, struct cmd_q *cmdq)
+{
+       if (monitor_enter(head, monitor_find_or_create(head, name), cmdq, MONITOR_ENQUEUE))
+               return (CMD_RETURN_NORMAL);
+
+       return (CMD_RETURN_WAIT);
+}
+
+enum cmd_retval
+monitor_unlock(struct monitors *head, const char *name, struct cmd_q *cmdq)
+{
+       struct window_pane *pane;
+       struct monitor_node *m;
+
+       m = monitor_find(head, name);
+       cmd_find_pane(cmdq, NULL, NULL, &pane);
+
+       if (m == NULL || m->pane != pane) {
+               cmdq_error(cmdq, "Not holding the lock to '%s'", name);
+               return (CMD_RETURN_ERROR);
+       }
+
+       m->count--;
+
+       if (m->count == 0)
+               monitor_shift(head, m);
+
+       return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+monitor_wait(struct monitors *head, const char *name, struct cmd_q *cmdq)
+{
+       monitor_enter(head, monitor_find_or_create(head, name), cmdq, MONITOR_ENQUEUE | MONITOR_WAIT);
+       return (CMD_RETURN_WAIT);
+}
+
+enum cmd_retval
+monitor_signal(struct monitors *head, const char *name, struct cmd_q *cmdq)
+{
+       struct monitor_node *m;
+
+       m = monitor_find(head, name);
+
+       if (m != NULL)
+               if (!monitor_enter(head, m, cmdq, MONITOR_ENQUEUE | MONITOR_SIGNAL))
+                       return (CMD_RETURN_WAIT);
+
+       return (CMD_RETURN_NORMAL);
+}
+
diff --git a/cmd.c b/cmd.c
index f3326df..c4386dc 100644
--- a/cmd.c
+++ b/cmd.c
@@ -71,6 +71,7 @@ const struct cmd_entry *cmd_table[] = {
        &cmd_lock_session_entry,
        &cmd_move_pane_entry,
        &cmd_move_window_entry,
+       &cmd_monitor_entry,
        &cmd_new_session_entry,
        &cmd_new_window_entry,
        &cmd_next_layout_entry,
diff --git a/examples/monitor.sh b/examples/monitor.sh
new file mode 100755
index 0000000..9157e45
--- /dev/null
+++ b/examples/monitor.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+
+# Shows how one can make panes synchronize work using the 'monitor' command
+#
+# The monitor object allows four basic operations which are executed
+# with mutual exclusion(meaning the monitor lock needs to be acquired
+# before executing)
+#
+#   l:  lock the monitor (primitive operation indirectly called by others)
+#              u:  releases the monitor lock
+#   w:  enter the monitor 'wait stack' and blocks until a signal is received
+#   s:  signal all panes waiting in the monitor stack. if the monitor
+#                              is locked, then it will block
+
+if [ -z $TMUX ]; then
+       echo "Start tmux first" >&2
+       exit 1
+fi
+
+kill_child_panes() {
+       tmux kill-pane -t $pane1
+       tmux kill-pane -t $pane2
+       tmux kill-pane -t $pane3
+       exit
+}
+abspath=$(cd ${0%/*} && echo $PWD/${0##*/})
+
+case $1 in
+       pane1)
+               tmux setw -q @pane1id $TMUX_PANE
+               tmux monitor -s pane1
+               tmux monitor -w pane1
+               tmux split-window -d -h "$abspath pane3"
+               tmux split-window -d -h "$abspath pane2"
+               tmux monitor -w pane1
+               columns=$(tput cols)
+               n=1
+               while true; do
+                       for i in $(seq 1 $columns); do
+                               sleep "0.1"
+                               echo -n $n
+                       done
+                       echo
+                       tmux monitor -s pane2
+                       tmux monitor -w pane1
+                       n=$(( ($n + 3) % 9 ))
+               done
+               ;;
+       pane2)
+               tmux setw -q @pane2id $TMUX_PANE
+               tmux monitor -s pane2
+               tmux monitor -w pane2
+               columns=$(tput cols)
+               n=2
+               while true; do
+                       for i in $(seq 1 $columns); do
+                               sleep "0.1"
+                               echo -n $n
+                       done
+                       echo
+                       tmux monitor -s pane3
+                       tmux monitor -w pane2
+                       n=$(( ($n + 3) % 9 ))
+               done
+               ;;
+       pane3)
+               tmux setw -q @pane3id $TMUX_PANE
+               tmux monitor -s pane3
+               tmux monitor -w pane3
+               columns=$(tput cols)
+               n=3
+               while true; do
+                       for i in $(seq 1 $columns); do
+                               sleep "0.1"
+                               echo -n $n
+                       done
+                       echo
+                       tmux monitor -s pane1
+                       tmux monitor -w pane3
+                       n=$(( ($n + 3) % 9 ))
+               done
+               ;;
+       *)
+               columns=$(tput cols)
+               trap kill_child_panes SIGINT SIGTERM
+               clear
+               echo "This is a simple script that shows how tmux can synchronize"
+         echo "code running in different panes."
+               echo
+               echo "Besides recursively spliting panes, it will run a simple animation"
+               echo "demonstrating the coordination between panes"
+               echo
+               sleep 1
+               echo "First split horizontally"
+               tmux split-window "$abspath pane1"
+               tmux monitor -w pane1
+               pane1=`tmux showw -v @pane1id`
+               sleep 1
+               echo "Now we split the child pane 2 times"
+               tmux monitor -s pane1
+               tmux monitor -w pane3
+               tmux monitor -w pane2
+               pane2=`tmux showw -v @pane2id`
+               pane3=`tmux showw -v @pane3id`
+               column_width=$(($columns / 3))
+               sleep 1
+               echo "Resize equally"
+               tmux resize-pane -t $pane1 -x $column_width
+               tmux resize-pane -t $pane2 -x $column_width
+               tmux resize-pane -t $pane3 -x $column_width
+               sleep 1
+               echo "Start animation"
+               tmux monitor -s pane1
+               tmux select-pane -t $TMUX_PANE
+               while true; do
+                       sleep 1000
+               done
+               ;;
+esac
+
diff --git a/monitor.c b/monitor.c
new file mode 100644
index 0000000..34c15dc
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2013 Thiago de Arruda<tpadilh...@gmail.com>
+ *
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * This module adds features that allow scripts running in different panes
+ * to easily synchronize tasks. It exposes 'monitor' objects to tmux panes,
+ * which are similar to the monitor concept used in concurrent programming.
+ *
+ * The major difference is that this one manages/synchronizes tmux panes
+ * instead of threads.
+ *
+ * See http://en.wikipedia.org/wiki/Monitor_(synchronization) for more
+ * information about monitors
+*/
+
+RB_GENERATE(monitors, monitor_node, node, monitors_cmp);
+
+int
+monitors_cmp(struct monitor_node *m1, struct monitor_node *m2)
+{
+       return (strcmp(m1->name, m2->name));
+}
+
+void
+monitor_init(struct monitors *head)
+{
+       RB_INIT(head);
+}
+
+struct monitor_node *
+monitor_find(struct monitors *head, const char *name)
+{
+       struct monitor_node m_name;
+       m_name.name = (char *)name;
+       return RB_FIND(monitors, head, &m_name);
+}
+
+struct monitor_node *
+monitor_find_or_create(struct monitors *head, const char *name)
+{
+       struct monitor_node *m;
+
+       m = monitor_find(head, name);
+
+       if (m == NULL) {
+               /* Creates/insert a node for representing the monitor state. */
+               m = xmalloc(sizeof *m);
+               m->name = xstrdup(name);
+               m->count = 0;
+               m->pane = NULL;
+               TAILQ_INIT(&m->lock_queue);
+               TAILQ_INIT(&m->wait_stack);
+               RB_INSERT(monitors, head, m);
+       }
+
+       return m;
+}
+
+void
+monitor_signal_move_cmdq(struct monitors *head, struct monitor_node *m)
+{
+       struct cmdq_node *q;
+       /*
+        * Move all cmdq objects from the wait stack to the
+        * front of the lock queue in a way that the object
+        * in the bottom of the stack will be in the head
+        * of the queue(in other words, the first pane to
+        * enter the wait stack will be the first to awake).
+        */
+       while ((q = TAILQ_FIRST(&m->wait_stack)) != NULL) {
+               TAILQ_REMOVE(&m->wait_stack, q, node);
+               TAILQ_INSERT_HEAD(&m->lock_queue, q, node);
+       }
+       if (m->pane == NULL)
+               /* The monitor is unlocked, so start shifting. */
+               monitor_shift(head, m);
+}
+
+/*
+ * Entry point to the monitor which enforces the mutual exclusion property.
+ * All monitor actions have to go through here, the only exeception is
+ * monitor_unlock since the pane needs to already be occupying the monitor
+ * to use it.
+ */
+int
+monitor_enter(struct monitors *head, struct monitor_node *m, struct cmd_q *cmdq,
+              enum monitor_options options)
+{
+       struct window_pane *pane;
+       struct cmdq_node *q;
+
+       cmd_find_pane(cmdq, NULL, NULL, &pane);
+
+       if (m->pane == NULL || m->pane == pane) {
+               if (options & MONITOR_WAIT) {
+                       cmdq->references++;
+                       q = xmalloc(sizeof *q);
+                       q->cmdq = cmdq;
+                       /*
+                        * Since this pane will enter the wait stack,
+                        * we can remove the wait flag now.
+                        */
+                       q->options = options & ~MONITOR_WAIT;
+                       /*
+                        * If the lock was acquired as result of a wait command(meaning the pane
+                        * wasn't holding the lock), then release as soon as it receives signal
+                        */
+                       if (m->pane != pane)
+                               q->options |= MONITOR_RELEASE;
+                       TAILQ_INSERT_HEAD(&m->wait_stack, q, node);
+                       /* Release the pane lock. */
+                       m->pane = NULL;
+                       /* Waiting resets the number of locks acquired on the monitor. */
+                       m->count = 0;
+                       if (!TAILQ_EMPTY(&m->wait_stack))
+                               monitor_shift(head, m);
+               } else if (options & MONITOR_SIGNAL) {
+                       monitor_signal_move_cmdq(head, m);
+               } else {
+                       /* Lock the monitor. */
+                       m->pane = pane;
+                       /*
+                        * This implementation is reentrant, so the pane can lock the monitor
+                        * multiple times, as long as it also releases it the same number of
+                        * times.
+                        */
+                       m->count++;
+               }
+               return 1;
+       }
+
+       if (options & MONITOR_ENQUEUE) {
+               /* Push to the lock queue. */
+               cmdq->references++;
+               q = xmalloc(sizeof *q);
+               q->cmdq = cmdq;
+               /*
+                * If the monitor is already locked, and this came from a wait/signal
+                * command, then also release the lock as soon as it is acquired.
+                */
+               if ((options & MONITOR_WAIT) || (options & MONITOR_SIGNAL))
+                       options |= MONITOR_RELEASE;
+               q->options = options;
+               TAILQ_INSERT_TAIL(&m->lock_queue, q, node);
+       }
+
+       return 0;
+}
+
+void
+monitor_shift(struct monitors *head, struct monitor_node *m)
+{
+       struct cmdq_node *q;
+
+       /* Release the lock. */
+       m->pane = NULL;
+
+       /* Process all panes that don't need to hold the lock(signaling/waiting panes). */
+       while ((q = TAILQ_FIRST(&m->lock_queue)) != NULL && (q->options & MONITOR_RELEASE)) {
+               TAILQ_REMOVE(&m->lock_queue, q, node);
+               if (q->options & MONITOR_SIGNAL)
+                       monitor_signal_move_cmdq(head, m);
+               if (!cmdq_free(q->cmdq))
+                       cmdq_continue(q->cmdq);
+               free(q);
+       }
+
+       /* Process a pane waiting to acquire the monitor lock. */
+       if (q != NULL) {
+               TAILQ_REMOVE(&m->lock_queue, q, node);
+               if (!monitor_enter(head, m, q->cmdq, (q->options & ~MONITOR_ENQUEUE)))
+                       fatal("Failed to pass the monitor lock to the next pane");
+               if (!cmdq_free(q->cmdq))
+                       cmdq_continue(q->cmdq);
+               free(q);
+       } else if (TAILQ_EMPTY(&m->wait_stack)) {
+         /*
+                * Monitor is unlocked and no pane is in the wait stack
+                * so now remove and free the monitor node.
+                */
+               RB_REMOVE(monitors, head, m);
+               free(m->name);
+               free(m);
+       }
+}
+
+
diff --git a/tmux.c b/tmux.c
index f685660..42900cc 100644
--- a/tmux.c
+++ b/tmux.c
@@ -37,6 +37,7 @@ struct options         global_options;        /* server options */
 struct options  global_s_options;      /* session options */
 struct options  global_w_options;      /* window options */
 struct environ  global_environ;
+struct monitors  global_monitors;

 struct event_base *ev_base;

@@ -336,6 +337,8 @@ main(int argc, char **argv)
        options_init(&global_w_options, NULL);
        options_table_populate_tree(window_options_table, &global_w_options);

+       monitor_init(&global_monitors);
+
        /* Enable UTF-8 if the first client is on UTF-8 terminal. */
        if (flags & IDENTIFY_UTF8) {
                options_set_number(&global_s_options, "status-utf8", 1);
diff --git a/tmux.h b/tmux.h
index 0df1f4d..45cd876 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1486,6 +1486,64 @@ struct format_entry {
 };
 RB_HEAD(format_tree, format_entry);

+/* Monitor enter flags */
+
+enum monitor_options {
+       MONITOR_ENQUEUE = 1,
+       /*
+        * If this is set, as soon as the pane acquires the lock it will
+        * temporarily give up the lock rights and be put on the wait stack until
+        * a signal is received, at which point it will be put back in front
+        * of the lock queue again
+        */
+       MONITOR_WAIT = 2,
+       MONITOR_SIGNAL = 4,
+       /*
+        * If the pane is not holding the lock when it starts waiting for a signal,
+        * then this flag is set, which means that as soon as the the signal
+        * arrives, it will leave the wait stack and release the lock
+        */
+       MONITOR_RELEASE = 8
+};
+
+/*
+ * Queue of panes, used for tracking panes waiting to lock the monitor, or to
+ * receive a signal from another pane
+ */
+struct cmdq_node {
+
+       struct cmd_q *cmdq;
+
+       enum monitor_options options;
+
+       TAILQ_ENTRY(cmdq_node) node;
+};
+
+/*
+ * Tree that keeps track of monitors. Each monitor is identified by a
+ * name, and the monitor node only exists while there's some pane using it
+ */
+struct monitor_node {
+
+       /* Monitor name. */
+       char *name;
+
+       /* Pane locking the monitor. */
+       struct window_pane *pane;
+
+       /* Number of times the pane has locked the monitor. */
+       int count;
+
+       /* Panes waiting to lock the monitor. */
+       TAILQ_HEAD(, cmdq_node) lock_queue;
+
+       /* Panes waiting for signal. */
+       TAILQ_HEAD(, cmdq_node) wait_stack;
+
+       RB_ENTRY(monitor_node) node;
+};
+RB_HEAD(monitors, monitor_node);
+
 /* Common command usages. */
 #define CMD_TARGET_PANE_USAGE "[-t target-pane]"
 #define CMD_TARGET_WINDOW_USAGE "[-t target-window]"
@@ -1502,6 +1560,7 @@ extern struct options global_options;
 extern struct options global_s_options;
 extern struct options global_w_options;
 extern struct environ global_environ;
+extern struct monitors global_monitors;
 extern struct event_base *ev_base;
 extern char    *cfg_file;
 extern char    *shell_cmd;
@@ -1793,6 +1852,7 @@ extern const struct cmd_entry cmd_lock_server_entry;
 extern const struct cmd_entry cmd_lock_session_entry;
 extern const struct cmd_entry cmd_move_pane_entry;
 extern const struct cmd_entry cmd_move_window_entry;
+extern const struct cmd_entry cmd_monitor_entry;
 extern const struct cmd_entry cmd_new_session_entry;
 extern const struct cmd_entry cmd_new_window_entry;
 extern const struct cmd_entry cmd_next_layout_entry;
@@ -2346,4 +2406,15 @@ int               xvasprintf(char **, const char *, va_list);
 int printflike3         xsnprintf(char *, size_t, const char *, ...);
 int             xvsnprintf(char *, size_t, const char *, va_list);

+/* monitor.c */
+int monitors_cmp(struct monitor_node *, struct monitor_node *);
+RB_PROTOTYPE(monitors, monitor_node, node, monitors_cmp);
+void monitor_init(struct monitors *);
+struct monitor_node    *monitor_find(struct monitors *, const char *);
+struct monitor_node *monitor_find_or_create(struct monitors *, const char *);
+void monitor_signal_move_cmdq(struct monitors *, struct monitor_node *);
+int monitor_enter(struct monitors *, struct monitor_node *, struct cmd_q *cmdq,
+                  enum monitor_options);
+void monitor_shift(struct monitors *, struct monitor_node *);
+
 #endif /* TMUX_H */
diff --git a/monitor.c b/monitor.c
index 34c15dc..35a57a5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -166,11 +166,41 @@ monitor_enter(struct monitors *head, struct monitor_node *m, struct cmd_q *cmdq,
        return 0;
 }

+struct shift_evdata {
+       struct monitors *head;
+       char *name;
+};
+
 void
 monitor_shift(struct monitors *head, struct monitor_node *m)
 {
+       struct shift_evdata *evdata;
+       struct event ev;
+       struct timeval tv = {0, 0};
+
+       evdata = xmalloc(sizeof *evdata);
+       evdata->head = head;
+       evdata->name = xstrdup(m->name);
+       evtimer_set(&ev, monitor_shift_handler, evdata);
+       evtimer_add(&ev, &tv);
+}
+
+void monitor_shift_handler(int fd, short ev, void *data)
+{
+       struct shift_evdata *evdata = (struct shift_evdata *)data;
+       struct monitors *head = evdata->head;
+       struct monitor_node *m = monitor_find(head, evdata->name);
        struct cmdq_node *q;

+       (void)fd;
+       (void)ev;
+
+       free(evdata->name);
+       free(evdata);
+
+       if (m == NULL)
+               return;
+
        /* Release the lock. */
        m->pane = NULL;

@@ -202,5 +232,3 @@ monitor_shift(struct monitors *head, struct monitor_node *m)
                free(m);
        }
 }
-
-
diff --git a/tmux.h b/tmux.h
index 45cd876..50a85c6 100644
--- a/tmux.h
+++ b/tmux.h
@@ -2416,5 +2416,6 @@ void monitor_signal_move_cmdq(struct monitors *, struct monitor_node *);
 int monitor_enter(struct monitors *, struct monitor_node *, struct cmd_q *cmdq,
                   enum monitor_options);
 void monitor_shift(struct monitors *, struct monitor_node *);
+void monitor_shift_handler(int, short, void *);

 #endif /* TMUX_H */
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_feb
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to