Index: global.c
===================================================================
--- global.c	(revision ae11191e0e66b5c8191411715d1741b49c7f4c9d)
+++ global.c	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -492,7 +492,8 @@
   g->resizepending = 0;
 
-  g->lines = lines;
-  g->cols = cols;
-  owl_window_recompute_position(owl_window_get_screen());
+  owl_global_get_terminal_size(&lines, &cols);
+  if (lines) g->lines = lines;
+  if (cols)  g->cols  = cols;
+  owl_window_resize(owl_window_get_screen(), g->lines, g->cols);
 
   owl_function_debugmsg("New size is %i lines, %i cols.", g->lines, g->cols);
Index: owl.h
===================================================================
--- owl.h	(revision e96b4ce4f8c43943b7e7702f4f3f0dc0124bd970)
+++ owl.h	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -404,4 +404,5 @@
   int rightshift;
   owl_window *window;
+  gulong sig_redraw_id;
   void (*onclose_hook) (struct _owl_viewwin *vwin, void *data);
   void *onclose_hook_data;
@@ -409,4 +410,5 @@
   
 typedef struct _owl_popwin {
+  gulong screen_resize_id;
   owl_window *border;
   owl_window *content;
Index: popwin.c
===================================================================
--- popwin.c	(revision 053f7513f026946433a32a77faf45b9d085684e3)
+++ popwin.c	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -11,7 +11,11 @@
   pw->border = owl_window_new(NULL);
   pw->content = owl_window_new(pw->border);
-  owl_window_set_redraw_cb(pw->border, owl_popwin_draw_border, pw, 0);
-  owl_window_set_size_cb(pw->border, owl_popwin_size_border, 0, 0);
-  owl_window_set_size_cb(pw->content, owl_popwin_size_content, 0, 0);
+  g_signal_connect(pw->border, "redraw", G_CALLBACK(owl_popwin_draw_border), 0);
+  pw->screen_resize_id = g_signal_connect_object(owl_window_get_screen(), "resized", G_CALLBACK(owl_popwin_size_border), pw->border, 0);
+  g_signal_connect_object(pw->border, "resized", G_CALLBACK(owl_popwin_size_content), pw->content, 0);
+
+  /* bootstrap sizing */
+  owl_popwin_size_border(owl_window_get_screen(), pw->border);
+
   owl_window_show_all(pw->border);
 
@@ -20,9 +24,9 @@
 }
 
-void owl_popwin_size_border(owl_window *border, void *user_data)
+void owl_popwin_size_border(owl_window *parent, void *user_data)
 {
   int lines, cols, startline, startcol;
   int glines, gcols;
-  owl_window *parent = owl_window_get_parent(border);
+  owl_window *border = user_data;
 
   owl_window_get_position(parent, &glines, &gcols, 0, 0);
@@ -36,8 +40,8 @@
 }
 
-void owl_popwin_size_content(owl_window *content, void *user_data)
+void owl_popwin_size_content(owl_window *parent, void *user_data)
 {
   int lines, cols;
-  owl_window *parent = owl_window_get_parent(content);
+  owl_window *content = user_data;
   owl_window_get_position(parent, &lines, &cols, 0, 0);
   owl_window_set_position(content, lines-2, cols-2, 1, 1);
@@ -68,4 +72,11 @@
   g_object_unref(pw->border);
   g_object_unref(pw->content);
+
+  /* See comment on g_signal_connect_object; it only prevents the closure from
+   * being invoked. The signal handler itself still gets leaked. The other
+   * signal is okay, since we delete both at the same time. */
+  if (g_signal_handler_is_connected(owl_window_get_screen(), pw->screen_resize_id))
+      g_signal_handler_disconnect(owl_window_get_screen(), pw->screen_resize_id);
+
   pw->border = 0;
   pw->content = 0;
Index: viewwin.c
===================================================================
--- viewwin.c	(revision 5f7eadf7ee424394f46b02dbd815da4b42ef81bc)
+++ viewwin.c	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -53,9 +53,9 @@
 {
   if (v->window) {
-    owl_window_set_redraw_cb(v->window, 0, 0, 0);
+    g_signal_handler_disconnect(v->window, v->sig_redraw_id);
   }
   v->window = w;
   if (w) {
-    owl_window_set_redraw_cb(w, owl_viewwin_redisplay, v, 0);
+    v->sig_redraw_id = g_signal_connect(w, "redraw", G_CALLBACK(owl_viewwin_redisplay), v);
   }
 }
Index: window.c
===================================================================
--- window.c	(revision 7a70e265b1859095900a1efcdf565972aba6b8a7)
+++ window.c	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -19,13 +19,13 @@
   int nlines, ncols;
   int begin_y, begin_x;
-  /* hooks */
-  void (*redraw_cb)(owl_window *, WINDOW *, void *);
-  void  *redraw_cbdata;
-  void (*redraw_cbdata_destroy)(void *);
-
-  void (*size_cb)(owl_window *, void *);
-  void  *size_cbdata;
-  void (*size_cbdata_destroy)(void *);
 };
+
+enum {
+  REDRAW,
+  RESIZED,
+  LAST_SIGNAL
+};
+
+static guint window_signals[LAST_SIGNAL] = { 0 };
 
 static void owl_window_dispose(GObject *gobject);
@@ -42,12 +42,43 @@
 static void _owl_window_unrealize(owl_window *w);
 
+static void _owl_window_redraw_cleanup(owl_window *w, WINDOW *win);
+
 G_DEFINE_TYPE (OwlWindow, owl_window, G_TYPE_OBJECT)
 
 static void owl_window_class_init (OwlWindowClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = owl_window_dispose;
-  object_class->finalize = owl_window_finalize;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  /* Set up the vtabl */
+  gobject_class->dispose = owl_window_dispose;
+  gobject_class->finalize = owl_window_finalize;
+
+  klass->redraw = _owl_window_redraw_cleanup;
+  klass->resized = NULL;
+
+  /* Create the signals, remember IDs */
+  window_signals[REDRAW] =
+    g_signal_new("redraw",
+                 G_TYPE_FROM_CLASS(gobject_class),
+                 G_SIGNAL_RUN_CLEANUP,
+                 G_STRUCT_OFFSET(OwlWindowClass, redraw),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__POINTER,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_POINTER, NULL);
+
+  /* TODO: maybe type should be VOID__INT_INT_INT_INT; will need to generate a
+   * marshaller */
+  window_signals[RESIZED] =
+    g_signal_new("resized",
+                 G_TYPE_FROM_CLASS(gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET(OwlWindowClass, resized),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0,
+                 NULL);
 }
 
@@ -65,8 +96,4 @@
   }
 
-  /* Clear all cbs */
-  owl_window_set_redraw_cb (w, 0, 0, 0);
-  owl_window_set_size_cb (w, 0, 0, 0);
-
   /* Remove from hierarchy */
   owl_window_unlink (w);
@@ -100,14 +127,4 @@
   }
   return dummy;
-}
-
-static void _screen_calculate_size(owl_window *screen, void *user_data)
-{
-  owl_global *g = user_data;
-  int lines, cols;
-  owl_global_get_terminal_size(&lines, &cols);
-  if (!g->lines) g->lines = lines;
-  if (!g->cols) g->cols = cols;
-  owl_window_resize(screen, g->lines, g->cols);
 }
 
@@ -120,5 +137,4 @@
     screen = _owl_window_new(NULL, g.lines, g.cols, 0, 0);
     screen->is_screen = 1;
-    owl_window_set_size_cb(screen, _screen_calculate_size, &g, 0);
     owl_window_show(screen);
   }
@@ -154,37 +170,4 @@
 
   return w;
-}
-
-/** Callbacks **/
-
-void owl_window_set_redraw_cb(owl_window *w, void (*cb)(owl_window*, WINDOW*, void*), void *cbdata, void (*cbdata_destroy)(void*))
-{
-  if (w->redraw_cbdata_destroy) {
-    w->redraw_cbdata_destroy(w->redraw_cbdata);
-    w->redraw_cbdata = 0;
-    w->redraw_cbdata_destroy = 0;
-  }
-
-  w->redraw_cb = cb;
-  w->redraw_cbdata = cbdata;
-  w->redraw_cbdata_destroy = cbdata_destroy;
-
-  /* mark the window as dirty, to take new cb in account */
-  owl_window_dirty(w);
-}
-
-void owl_window_set_size_cb(owl_window *w, void (*cb)(owl_window*, void*), void *cbdata, void (*cbdata_destroy)(void*))
-{
-  if (w->size_cbdata_destroy) {
-    w->size_cbdata_destroy(w->size_cbdata);
-    w->size_cbdata = 0;
-    w->size_cbdata_destroy = 0;
-  }
-
-  w->size_cb = cb;
-  w->size_cbdata = cbdata;
-  w->size_cbdata_destroy = cbdata_destroy;
-
-  owl_window_recompute_position(w);
 }
 
@@ -368,7 +351,6 @@
 {
   if (!w->dirty) return;
-  if (w->win && w->redraw_cb) {
-    w->redraw_cb(w, w->win, w->redraw_cbdata);
-    wsyncup(w->win);
+  if (w->win) {
+    g_signal_emit(w, window_signals[REDRAW], 0, w->win);
   }
   w->dirty = 0;
@@ -390,4 +372,9 @@
 {
   _owl_window_redraw_subtree(owl_window_get_screen());
+}
+
+static void _owl_window_redraw_cleanup(owl_window *w, WINDOW *win)
+{
+  wsyncup(win);
 }
 
@@ -459,6 +446,5 @@
     _owl_window_unrealize(w);
   }
-  /* recalculate children sizes BEFORE remapping, so that everything can resize */
-  owl_window_children_foreach(w, (GFunc)owl_window_recompute_position, 0);
+  g_signal_emit(w, window_signals[RESIZED], 0);
   if (w->shown) {
     _owl_window_realize(w);
@@ -470,13 +456,4 @@
   owl_window_set_position(w, nlines, ncols, w->begin_y, w->begin_x);
 }
-
-void owl_window_recompute_position(owl_window *w)
-{
-  if (w->size_cb) {
-    /* TODO: size_cb probably wants to actually take four int*s */
-    w->size_cb(w, w->size_cbdata);
-  }
-}
-
 
 /** Stacking order **/
Index: window.h
===================================================================
--- window.h	(revision 7a70e265b1859095900a1efcdf565972aba6b8a7)
+++ window.h	(revision 7a6e6c79c9b37f504bb014887ac9aa103bac4338)
@@ -21,4 +21,7 @@
 {
   GObjectClass parent_class;
+  /* default implementations for signals */
+  void (*redraw)(owl_window *, WINDOW *);
+  void (*resized)(owl_window *);
 };
 
@@ -29,7 +32,4 @@
 owl_window *owl_window_new(owl_window *parent);
 void owl_window_unlink(owl_window *w);
-
-void owl_window_set_redraw_cb(owl_window *w, void (*cb)(owl_window*, WINDOW*, void*), void *cbdata, void (*cbdata_destroy)(void*));
-void owl_window_set_size_cb(owl_window *w, void (*cb)(owl_window*, void*), void *cbdata, void (*cbdata_destroy)(void*));
 
 void owl_window_children_foreach(owl_window *parent, GFunc func, gpointer user_data);
