Index: tmux.h
===================================================================
--- tmux.h	(revision 2721)
+++ tmux.h	(working copy)
@@ -1395,6 +1395,16 @@
 void	mode_key_init(struct mode_key_data *, struct mode_key_tree *);
 enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int);
 
+/* notify.c */
+void	notify_window_layout_changed(struct window *w);
+void	notify_window_unlinked(struct session *s, struct window *w);
+void	notify_window_linked(struct session *s, struct window *w);
+void	notify_window_renamed(struct window *w);
+void	notify_attached_session_changed(struct client *c);
+void	notify_session_renamed(struct session *s);
+void	notify_session_created(unused struct session *s);
+void	notify_session_closed(unused struct session *s);
+
 /* options.c */
 int	options_cmp(struct options_entry *, struct options_entry *);
 RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp);
Index: cmd-new-session.c
===================================================================
--- cmd-new-session.c	(revision 2721)
+++ cmd-new-session.c	(working copy)
@@ -244,6 +244,7 @@
 			if (old_s != NULL)
 				ctx->cmdclient->last_session = old_s;
 			ctx->cmdclient->session = s;
+			notify_attached_session_changed(ctx->cmdclient);
 			session_update_activity(s);
 			server_redraw_client(ctx->cmdclient);
 		} else {
@@ -251,6 +252,7 @@
 			if (old_s != NULL)
 				ctx->curclient->last_session = old_s;
 			ctx->curclient->session = s;
+			notify_attached_session_changed(ctx->curclient);
 			session_update_activity(s);
 			server_redraw_client(ctx->curclient);
 		}
Index: layout.c
===================================================================
--- layout.c	(revision 2721)
+++ layout.c	(working copy)
@@ -483,6 +483,7 @@
 	/* Fix cell offsets. */
 	layout_fix_offsets(wp->window->layout_root);
 	layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
+	notify_window_layout_changed(wp->window);
 }
 
 void
@@ -742,4 +743,5 @@
 		layout_fix_offsets(wp->window->layout_root);
 		layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
 	}
+	notify_window_layout_changed(wp->window);
 }
Index: layout-custom.c
===================================================================
--- layout-custom.c	(revision 2721)
+++ layout-custom.c	(working copy)
@@ -172,6 +172,8 @@
 
 	layout_print_cell(lc, __func__, 0);
 
+	notify_window_layout_changed(w);
+
 	return (0);
 
 fail:
Index: cmd-split-window.c
===================================================================
--- cmd-split-window.c	(revision 2721)
+++ cmd-split-window.c	(working copy)
@@ -155,6 +155,7 @@
 
 		format_free(ft);
 	}
+	notify_window_layout_changed(w);
 	return (0);
 
 error:
Index: session.c
===================================================================
--- session.c	(revision 2721)
+++ session.c	(working copy)
@@ -141,6 +141,7 @@
 	}
 
 	log_debug("session %s created", s->name);
+	notify_session_created(s);
 
 	return (s);
 }
@@ -149,9 +150,11 @@
 void
 session_destroy(struct session *s)
 {
+	struct winlink	*wl;
 	log_debug("session %s destroyed", s->name);
 
 	RB_REMOVE(sessions, &sessions, s);
+	notify_session_closed(s);
 
 	if (s->tio != NULL)
 		xfree(s->tio);
@@ -162,8 +165,11 @@
 
 	while (!TAILQ_EMPTY(&s->lastw))
 		winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw));
-	while (!RB_EMPTY(&s->windows))
-		winlink_remove(&s->windows, RB_ROOT(&s->windows));
+	while (!RB_EMPTY(&s->windows)) {
+		wl = RB_ROOT(&s->windows);
+		notify_window_unlinked(s, wl->window);
+		winlink_remove(&s->windows, wl);
+	}
 
 	xfree(s->cwd);
 
@@ -253,6 +259,7 @@
 		return (NULL);
 	}
 	winlink_set_window(wl, w);
+	notify_window_linked(s, w);
 	environ_free(&env);
 
 	if (options_get_number(&s->options, "set-remain-on-exit"))
@@ -273,6 +280,7 @@
 		return (NULL);
 	}
 	winlink_set_window(wl, w);
+	notify_window_linked(s, w);
 
 	session_group_synchronize_from(s);
 	return (wl);
@@ -287,6 +295,7 @@
 		session_next(s, 0);
 
 	wl->flags &= ~WINLINK_ALERTFLAGS;
+	notify_window_unlinked(s, wl->window);
 	winlink_stack_remove(&s->lastw, wl);
 	winlink_remove(&s->windows, wl);
 	session_group_synchronize_from(s);
@@ -554,6 +563,7 @@
 	RB_FOREACH(wl, winlinks, ww) {
 		wl2 = winlink_add(&s->windows, wl->idx);
 		winlink_set_window(wl2, wl->window);
+		notify_window_linked(s, wl2->window);
 		wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
 	}
 
@@ -575,6 +585,8 @@
 	/* Then free the old winlinks list. */
 	while (!RB_EMPTY(&old_windows)) {
 		wl = RB_ROOT(&old_windows);
+		if (winlink_find_by_window_id(&s->windows, wl->window->id) == NULL)
+		    notify_window_unlinked(s, wl->window);
 		winlink_remove(&old_windows, wl);
 	}
 }
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 2721)
+++ Makefile.am	(working copy)
@@ -151,6 +151,7 @@
 	log.c \
 	mode-key.c \
 	names.c \
+	notify.c \
 	options-table.c \
 	options.c \
 	paste.c \
Index: cmd-new-window.c
===================================================================
--- cmd-new-window.c	(revision 2721)
+++ cmd-new-window.c	(working copy)
@@ -89,6 +89,7 @@
 		 * Can't use session_detach as it will destroy session if this
 		 * makes it empty.
 		 */
+		notify_window_unlinked(s, wl->window);
 		wl->flags &= ~WINLINK_ALERTFLAGS;
 		winlink_stack_remove(&s->lastw, wl);
 		winlink_remove(&s->windows, wl);
Index: resize.c
===================================================================
--- resize.c	(revision 2721)
+++ resize.c	(working copy)
@@ -141,5 +141,6 @@
 		}
 
 		server_redraw_window(w);
+		notify_window_layout_changed(w);
 	}
 }
Index: server-fn.c
===================================================================
--- server-fn.c	(revision 2721)
+++ server-fn.c	(working copy)
@@ -293,6 +293,7 @@
 			 * Can't use session_detach as it will destroy session
 			 * if this makes it empty.
 			 */
+			notify_window_unlinked(dst, dstwl->window);
 			dstwl->flags &= ~WINLINK_ALERTFLAGS;
 			winlink_stack_remove(&dst->lastw, dstwl);
 			winlink_remove(&dst->windows, dstwl);
@@ -419,6 +420,7 @@
 		} else {
 			c->last_session = NULL;
 			c->session = s_new;
+			notify_attached_session_changed(c);
 			session_update_activity(s_new);
 			server_redraw_client(c);
 		}
Index: cmd-join-pane.c
===================================================================
--- cmd-join-pane.c	(revision 2721)
+++ cmd-join-pane.c	(working copy)
@@ -147,6 +147,8 @@
 
 	if (window_count_panes(src_w) == 0)
 		server_kill_window(src_w);
+	else
+		notify_window_layout_changed(src_w);
 
 	src_wp->window = dst_w;
 	TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
@@ -164,5 +166,6 @@
 	} else
 		server_status_session(dst_s);
 
+	notify_window_layout_changed(dst_w);
 	return (0);
 }
Index: cmd-rename-session.c
===================================================================
--- cmd-rename-session.c	(revision 2721)
+++ cmd-rename-session.c	(working copy)
@@ -64,6 +64,7 @@
 	RB_INSERT(sessions, &sessions, s);
 
 	server_status_session(s);
+	notify_session_renamed(s);
 
 	return (0);
 }
Index: window.c
===================================================================
--- window.c	(revision 2721)
+++ window.c	(working copy)
@@ -364,6 +364,7 @@
 	if (w->name != NULL)
 		xfree(w->name);
 	w->name = xstrdup(new_name);
+	notify_window_renamed(w);
 }
 
 void
Index: notify.c
===================================================================
--- notify.c	(revision 0)
+++ notify.c	(revision 0)
@@ -0,0 +1,59 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 George Nachman <tmux@georgester.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"
+
+void
+notify_window_layout_changed(struct window *w)
+{
+}
+
+void
+notify_window_unlinked(struct session *s, struct window *w)
+{
+}
+
+void
+notify_window_linked(struct session *s, struct window *w)
+{
+}
+
+void
+notify_window_renamed(struct window *w)
+{
+}
+
+void
+notify_attached_session_changed(struct client *c)
+{
+}
+
+void
+notify_session_renamed(struct session *s)
+{
+}
+
+void
+notify_session_created(unused struct session *s)
+{
+}
+
+void
+notify_session_closed(unused struct session *s)
+{
+}
Index: cmd-attach-session.c
===================================================================
--- cmd-attach-session.c	(revision 2721)
+++ cmd-attach-session.c	(working copy)
@@ -74,6 +74,7 @@
 		}
 
 		ctx->curclient->session = s;
+		notify_attached_session_changed(ctx->curclient);
 		session_update_activity(s);
 		server_redraw_client(ctx->curclient);
 		s->curw->flags &= ~WINLINK_ALERTFLAGS;
@@ -98,6 +99,7 @@
 			server_write_session(s, MSG_DETACH, NULL, 0);
 
 		ctx->cmdclient->session = s;
+		notify_attached_session_changed(ctx->cmdclient);
 		session_update_activity(s);
 		server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
 
