window: Make resize and redraw handlers widget vfuncs
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index ad1318d..7d8f526 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -42,7 +42,6 @@
 struct desktop {
 	struct display *display;
 	struct desktop_shell *shell;
-	const char *background_path;
 	struct unlock_dialog *unlock_dialog;
 	struct task unlock_task;
 	struct wl_list outputs;
@@ -67,6 +66,7 @@
 struct background {
 	struct surface base;
 	struct window *window;
+	struct widget *widget;
 };
 
 struct output {
@@ -168,36 +168,34 @@
 }
 
 static void
-panel_draw_launcher(struct panel_launcher *launcher, void *data)
+panel_launcher_redraw_handler(struct widget *widget, void *data)
 {
-	cairo_t *cr = data;
-	int x, y, width, height;
-	double dx, dy;
+	struct panel_launcher *launcher = data;
+	cairo_surface_t *surface;
+	struct rectangle allocation;
+	cairo_t *cr;
 
-	width = cairo_image_surface_get_width(launcher->icon);
-	height = cairo_image_surface_get_height(launcher->icon);
-	x = 0;
-	y = -height / 2;
+	surface = window_get_surface(launcher->panel->window);
+	cr = cairo_create(surface);
+
+	widget_get_allocation(widget, &allocation);
 	if (launcher->pressed) {
-		x++;
-		y++;
+		allocation.x++;
+		allocation.y++;
 	}
 
-	dx = x;
-	dy = y;
-	cairo_user_to_device(cr, &dx, &dy);
-	widget_set_allocation(launcher->widget, dx, dy, width, height);
-
-	cairo_set_source_surface(cr, launcher->icon, x, y);
+	cairo_set_source_surface(cr, launcher->icon,
+				 allocation.x, allocation.y);
 	cairo_paint(cr);
 
 	if (window_get_focus_widget(launcher->panel->window) ==
 	    launcher->widget) {
 		cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
-		cairo_mask_surface(cr, launcher->icon, x, y);
+		cairo_mask_surface(cr, launcher->icon,
+				   allocation.x, allocation.y);
 	}
 
-	cairo_translate(cr, width + 10, 0);
+	cairo_destroy(cr);
 }
 
 static void
@@ -211,24 +209,18 @@
 }
 
 static void
-panel_redraw_handler(struct window *window, void *data)
+panel_redraw_handler(struct widget *widget, void *data)
 {
 	cairo_surface_t *surface;
 	cairo_t *cr;
-	struct panel_launcher *launcher;
-	struct panel *panel = window_get_user_data(window);
+	struct panel *panel = data;
 
-	surface = window_get_surface(window);
+	surface = window_get_surface(panel->window);
 	cr = cairo_create(surface);
 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 	set_hex_color(cr, key_panel_color);
 	cairo_paint(cr);
 
-	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-	cairo_translate(cr, 10, 32 / 2);
-	wl_list_for_each(launcher, &panel->launcher_list, link)
-		panel_draw_launcher(launcher, cr);
-
 	cairo_destroy(cr);
 	cairo_surface_destroy(surface);
 }
@@ -267,22 +259,42 @@
 		     struct input *input, uint32_t time,
 		     int button, int state, void *data)
 {
-	struct window *window = data;
-	struct panel *panel = window_get_user_data(window);
+	struct panel *panel = data;
 
 	if (button == BTN_RIGHT && state)
 		show_menu(panel, input, time);
 }
 
 static void
+panel_resize_handler(struct widget *widget,
+		     int32_t width, int32_t height, void *data)
+{
+	struct panel_launcher *launcher;
+	struct panel *panel = data;
+	int x, y, w, h;
+	
+	x = 10;
+	y = 16;
+	wl_list_for_each(launcher, &panel->launcher_list, link) {
+		w = cairo_image_surface_get_width(launcher->icon);
+		h = cairo_image_surface_get_height(launcher->icon);
+		widget_set_allocation(launcher->widget,
+				      x, y - h / 2, w + 1, h + 1);
+		x += w + 10;
+	}
+}
+
+static void
 panel_configure(void *data,
 		struct desktop_shell *desktop_shell,
 		uint32_t time, uint32_t edges,
 		struct window *window,
 		int32_t width, int32_t height)
 {
-	window_set_child_size(window, width, 32);
-	window_schedule_redraw(window);
+	struct surface *surface = window_get_user_data(window);
+	struct panel *panel = container_of(surface, struct panel, base);
+
+	window_schedule_resize(panel->window, width, 32);
 }
 
 static struct panel *
@@ -296,15 +308,16 @@
 	panel->base.configure = panel_configure;
 	panel->window = window_create(display, 0, 0);
 	panel->widget = window_add_widget(panel->window, panel);
+	wl_list_init(&panel->launcher_list);
 
 	window_set_title(panel->window, "panel");
 	window_set_decoration(panel->window, 0);
-	window_set_redraw_handler(panel->window, panel_redraw_handler);
 	window_set_custom(panel->window);
 	window_set_user_data(panel->window, panel);
 
+	widget_set_redraw_handler(panel->widget, panel_redraw_handler);
+	widget_set_resize_handler(panel->widget, panel_resize_handler);
 	widget_set_button_handler(panel->widget, panel_button_handler);
-	wl_list_init(&panel->launcher_list);
 
 	return panel;
 }
@@ -319,7 +332,6 @@
 	launcher->icon = cairo_image_surface_create_from_png(icon);
 	launcher->path = strdup(path);
 	launcher->panel = panel;
-
 	wl_list_insert(panel->launcher_list.prev, &launcher->link);
 
 	launcher->widget = window_add_widget(panel->window, launcher);
@@ -329,31 +341,36 @@
 				   panel_launcher_leave_handler);
 	widget_set_button_handler(launcher->widget,
 				    panel_launcher_button_handler);
+	widget_set_redraw_handler(launcher->widget,
+				  panel_launcher_redraw_handler);
 }
 
 static void
-background_draw(struct window *window, int width, int height, const char *path)
+background_draw(struct widget *widget, void *data)
 {
+	struct background *background = data;
 	cairo_surface_t *surface, *image;
 	cairo_pattern_t *pattern;
 	cairo_matrix_t matrix;
 	cairo_t *cr;
 	double sx, sy;
+	struct rectangle allocation;
 
-	window_set_child_size(window, width, height);
-	window_create_surface(window);
-	surface = window_get_surface(window);
+	surface = window_get_surface(background->window);
 
 	cr = cairo_create(surface);
 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 	cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
 	cairo_paint(cr);
 
-	if (path) {
-		image = load_jpeg(path);
+	widget_get_allocation(widget, &allocation);
+	if (key_background_image) {
+		image = load_jpeg(key_background_image);
 		pattern = cairo_pattern_create_for_surface(image);
-		sx = (double) cairo_image_surface_get_width(image) / width;
-		sy = (double) cairo_image_surface_get_height(image) / height;
+		sx = (double) cairo_image_surface_get_width(image) /
+			allocation.width;
+		sy = (double) cairo_image_surface_get_height(image) /
+			allocation.height;
 		cairo_matrix_init_scale(&matrix, sx, sy);
 		cairo_pattern_set_matrix(pattern, &matrix);
 		cairo_set_source(cr, pattern);
@@ -364,7 +381,6 @@
 
 	cairo_destroy(cr);
 	cairo_surface_destroy(surface);
-	window_flush(window);
 }
 
 static void
@@ -374,14 +390,18 @@
 		     struct window *window,
 		     int32_t width, int32_t height)
 {
-	struct desktop *desktop = data;
+	struct background *background =
+		(struct background *) window_get_user_data(window);
 
-	background_draw(window, width, height, desktop->background_path);
+	window_set_child_size(background->window, width, height);
+	widget_set_allocation(background->widget, 0, 0, width, height);
+	window_schedule_redraw(background->window);
 }
 
 static void
-unlock_dialog_draw(struct unlock_dialog *dialog)
+unlock_dialog_redraw_handler(struct widget *widget, void *data)
 {
+	struct unlock_dialog *dialog = data;
 	struct rectangle allocation;
 	cairo_t *cr;
 	cairo_surface_t *surface;
@@ -446,14 +466,6 @@
 }
 
 static void
-unlock_dialog_redraw_handler(struct window *window, void *data)
-{
-	struct unlock_dialog *dialog = data;
-
-	unlock_dialog_draw(dialog);
-}
-
-static void
 unlock_dialog_keyboard_focus_handler(struct window *window,
 				     struct input *device, void *data)
 {
@@ -494,10 +506,11 @@
 	window_set_custom(dialog->window);
 
 	window_set_user_data(dialog->window, dialog);
-	window_set_redraw_handler(dialog->window, unlock_dialog_redraw_handler);
 	window_set_keyboard_focus_handler(dialog->window,
 					  unlock_dialog_keyboard_focus_handler);
 	dialog->button = window_add_widget(dialog->window, NULL);
+	widget_set_redraw_handler(dialog->widget,
+				  unlock_dialog_redraw_handler);
 	widget_set_enter_handler(dialog->button,
 				 unlock_dialog_widget_enter_handler);
 	widget_set_leave_handler(dialog->button,
@@ -508,7 +521,7 @@
 	desktop_shell_set_lock_surface(desktop->shell,
 	       window_get_wl_shell_surface(dialog->window));
 
-	unlock_dialog_draw(dialog);
+	window_schedule_redraw(dialog->window);
 
 	return dialog;
 }
@@ -576,9 +589,11 @@
 
 	background->base.configure = background_configure;
 	background->window = window_create(desktop->display, 0, 0);
+	background->widget = window_add_widget(background->window, background);
 	window_set_decoration(background->window, 0);
 	window_set_custom(background->window);
 	window_set_user_data(background->window, background);
+	widget_set_redraw_handler(background->widget, background_draw);
 
 	return background;
 }
@@ -670,8 +685,6 @@
 			  &desktop);
 	free(config_file);
 
-	desktop.background_path = key_background_image;
-
 	signal(SIGCHLD, sigchild_handler);
 
 	display_run(desktop.display);
diff --git a/clients/dnd.c b/clients/dnd.c
index cd03b1f..0498c5d 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -160,8 +160,9 @@
 }
 
 static void
-dnd_draw(struct dnd *dnd)
+dnd_redraw_handler(struct widget *widget, void *data)
 {
+	struct dnd *dnd = data;
 	struct rectangle allocation;
 	cairo_t *cr;
 	cairo_surface_t *surface;
@@ -192,14 +193,6 @@
 }
 
 static void
-redraw_handler(struct window *window, void *data)
-{
-	struct dnd *dnd = data;
-
-	dnd_draw(dnd);
-}
-
-static void
 keyboard_focus_handler(struct window *window,
 		       struct input *device, void *data)
 {
@@ -530,12 +523,12 @@
 	}
 
 	window_set_user_data(dnd->window, dnd);
-	window_set_redraw_handler(dnd->window, redraw_handler);
 	window_set_keyboard_focus_handler(dnd->window,
 					  keyboard_focus_handler);
 	window_set_data_handler(dnd->window, dnd_data_handler);
 	window_set_drop_handler(dnd->window, dnd_drop_handler);
 
+	widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
 	widget_set_enter_handler(dnd->widget, dnd_enter_handler);
 	widget_set_motion_handler(dnd->widget, dnd_motion_handler);
 	widget_set_button_handler(dnd->widget, dnd_button_handler);
@@ -544,7 +537,7 @@
 	height = 4 * (item_height + item_padding) + item_padding;
 	window_set_child_size(dnd->window, width, height);
 
-	dnd_draw(dnd);
+	window_schedule_redraw(dnd->window);
 
 	return dnd;
 }
diff --git a/clients/eventdemo.c b/clients/eventdemo.c
index 5ea6831..5f70bc1 100644
--- a/clients/eventdemo.c
+++ b/clients/eventdemo.c
@@ -90,19 +90,23 @@
 };
 
 /**
- * \brief Redraws the window
+ * \brief CALLBACK function, Wayland requests the window to redraw.
+ * \param window window to be redrawn
+ * \param data user data associated to the window
  *
  * Draws a red rectangle as demonstration of per-window data.
  */
 static void
-eventdemo_draw(struct eventdemo *e) {
-	if (log_redraw)
-		printf("redraw\n");
-
+redraw_handler(struct widget *widget, void *data)
+{
+	struct eventdemo *e = data;
 	cairo_surface_t *surface;
 	cairo_t *cr;
 	struct rectangle rect;
 
+	if (log_redraw)
+		printf("redraw\n");
+
 	window_get_child_allocation(e->window, &rect);
 	surface = window_get_surface(e->window);
 
@@ -122,18 +126,6 @@
 }
 
 /**
- * \brief CALLBACK function, Wayland requests the window to redraw.
- * \param window window to be redrawn
- * \param data user data associated to the window
- */
-static void
-redraw_handler(struct window *window, void *data)
-{
-	struct eventdemo *e = data;
-	eventdemo_draw(e);
-}
-
-/**
  * \brief CALLBACK function, Wayland requests the window to resize.
  * \param window window to be resized
  * \param width desired width
@@ -142,7 +134,7 @@
  */
 
 static void
-resize_handler(struct window *window,
+resize_handler(struct widget *widget,
 	       int32_t width, int32_t height, void *data)
 {
 	struct eventdemo *e = data;
@@ -159,9 +151,6 @@
 
 	/* set the new window dimensions */
 	window_set_child_size(e->window, width, height);
-
-	/* inform Wayland that the window needs to be redrawn */
-	window_schedule_redraw(e->window);
 }
 
 /**
@@ -301,10 +290,10 @@
 	window_set_user_data(e->window, e);
 
 	/* Set the callback redraw handler for the window */
-	window_set_redraw_handler(e->window, redraw_handler);
+	widget_set_redraw_handler(e->widget, redraw_handler);
 
 	/* Set the callback resize handler for the window */
-	window_set_resize_handler(e->window, resize_handler);
+	widget_set_resize_handler(e->widget, resize_handler);
 
 	/* Set the callback focus handler for the window */
 	window_set_keyboard_focus_handler(e->window,
diff --git a/clients/flower.c b/clients/flower.c
index 42028f0..9cbc424 100644
--- a/clients/flower.c
+++ b/clients/flower.c
@@ -104,6 +104,23 @@
 	cairo_destroy(cr);
 }
 
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+	struct flower *flower = data;
+	cairo_surface_t *surface;
+
+	surface = window_get_surface(flower->window);
+	if (surface == NULL ||
+	    cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+		fprintf(stderr, "failed to create cairo egl surface\n");
+		return;
+	}
+
+	draw_stuff(surface, flower->width, flower->height);
+	cairo_surface_destroy(surface);
+}
+
 static int
 motion_handler(struct widget *widget, struct input *input,
 	       uint32_t time, int32_t x, int32_t y, void *data)
@@ -124,7 +141,6 @@
 
 int main(int argc, char *argv[])
 {
-	cairo_surface_t *s;
 	struct flower flower;
 	struct display *d;
 	struct timeval tv;
@@ -144,23 +160,14 @@
 	flower.window = window_create(d, flower.width, flower.height);
 	flower.widget = window_add_widget(flower.window, &flower);
 
-	window_set_title(flower.window, "flower");
 	window_set_decoration(flower.window, 0);
-	window_create_surface(flower.window);
-	s = window_get_surface(flower.window);
-	if (s == NULL || cairo_surface_status (s) != CAIRO_STATUS_SUCCESS) {
-		fprintf(stderr, "failed to create cairo egl surface\n");
-		return -1;
-	}
 
-	draw_stuff(s, flower.width, flower.height);
-	cairo_surface_flush(s);
-	cairo_surface_destroy(s);
-	window_flush(flower.window);
-
+	widget_set_redraw_handler(flower.widget, redraw_handler);
 	widget_set_motion_handler(flower.widget, motion_handler);
 	widget_set_button_handler(flower.widget, button_handler);
-	window_set_user_data(flower.window, &flower);
+
+	window_schedule_redraw(flower.window);
+
 	display_run(d);
 
 	return 0;
diff --git a/clients/gears.c b/clients/gears.c
index b5e7bd4..5dfb47a 100644
--- a/clients/gears.c
+++ b/clients/gears.c
@@ -42,6 +42,7 @@
 
 struct gears {
 	struct window *window;
+	struct widget *widget;
 
 	struct display *d;
 
@@ -212,7 +213,7 @@
 };
 
 static void
-redraw_handler(struct window *window, void *data)
+redraw_handler(struct widget *widget, void *data)
 {
 	GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
 	struct rectangle window_allocation;
@@ -277,7 +278,7 @@
 }
 
 static void
-resize_handler(struct window *window,
+resize_handler(struct widget *widget,
 	       int32_t width, int32_t height, void *data)
 {
 	struct gears *gears = data;
@@ -299,11 +300,7 @@
 keyboard_focus_handler(struct window *window,
 		       struct input *device, void *data)
 {
-	struct gears *gears = data;
-	struct rectangle allocation;
-
-	window_get_child_allocation(gears->window, &allocation);
-	resize_handler(window, allocation.width, allocation.height, gears);
+	window_schedule_redraw(window);
 }
 
 static struct gears *
@@ -317,6 +314,7 @@
 	memset(gears, 0, sizeof *gears);
 	gears->d = display;
 	gears->window = window_create(display, width, height);
+	gears->widget = window_add_widget(gears->window, gears);
 	window_set_transparent(gears->window, 0);
 	window_set_title(gears->window, "Wayland Gears");
 
@@ -358,9 +356,10 @@
 	glClearColor(0, 0, 0, 0.92);
 
 	window_set_user_data(gears->window, gears);
-	window_set_resize_handler(gears->window, resize_handler);
-	window_set_redraw_handler(gears->window, redraw_handler);
-	window_set_keyboard_focus_handler(gears->window, keyboard_focus_handler);
+	widget_set_resize_handler(gears->widget, resize_handler);
+	widget_set_redraw_handler(gears->widget, redraw_handler);
+	window_set_keyboard_focus_handler(gears->window,
+					  keyboard_focus_handler);
 
 	frame_callback(gears, NULL, 0);
 
diff --git a/clients/image.c b/clients/image.c
index 0e34103..517bb47 100644
--- a/clients/image.c
+++ b/clients/image.c
@@ -39,6 +39,7 @@
 
 struct image {
 	struct window *window;
+	struct widget *widget;
 	struct display *display;
 	gchar *filename;
 };
@@ -133,8 +134,9 @@
 }
 
 static void
-image_draw(struct image *image)
+redraw_handler(struct widget *widget, void *data)
 {
+	struct image *image = data;
 	struct rectangle allocation;
 	GdkPixbuf *pb;
 	cairo_t *cr;
@@ -177,14 +179,6 @@
 }
 
 static void
-redraw_handler(struct window *window, void *data)
-{
-	struct image *image = data;
-
-	image_draw(image);
-}
-
-static void
 keyboard_focus_handler(struct window *window,
 		       struct input *device, void *data)
 {
@@ -212,11 +206,12 @@
 	image->filename = g_strdup(filename);
 
 	image->window = window_create(display, 500, 400);
+	image->widget = window_add_widget(image->window, image);
 	window_set_title(image->window, title);
 	image->display = display;
 
 	window_set_user_data(image->window, image);
-	window_set_redraw_handler(image->window, redraw_handler);
+	widget_set_redraw_handler(image->widget, redraw_handler);
 	window_set_keyboard_focus_handler(image->window,
 					  keyboard_focus_handler);
 
diff --git a/clients/resizor.c b/clients/resizor.c
index 395fdcd..945f2ae 100644
--- a/clients/resizor.c
+++ b/clients/resizor.c
@@ -98,8 +98,9 @@
 }
 
 static void
-resizor_draw(struct resizor *resizor)
+redraw_handler(struct widget *widget, void *data)
 {
+	struct resizor *resizor = data;
 	cairo_surface_t *surface;
 	cairo_t *cr;
 	struct rectangle allocation;
@@ -123,14 +124,6 @@
 }
 
 static void
-redraw_handler(struct window *window, void *data)
-{
-	struct resizor *resizor = data;
-
-	resizor_draw(resizor);
-}
-
-static void
 keyboard_focus_handler(struct window *window,
 		       struct input *device, void *data)
 {
@@ -219,7 +212,7 @@
 
 	window_set_key_handler(resizor->window, key_handler);
 	window_set_user_data(resizor->window, resizor);
-	window_set_redraw_handler(resizor->window, redraw_handler);
+	widget_set_redraw_handler(resizor->widget, redraw_handler);
 	window_set_keyboard_focus_handler(resizor->window,
 					  keyboard_focus_handler);
 
diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c
index 90cb766..2331e68 100644
--- a/clients/tablet-shell.c
+++ b/clients/tablet-shell.c
@@ -202,8 +202,7 @@
 			  struct input *input, uint32_t time,
 			  int button, int state, void *data)
 {
-	struct window *window = data;
-	struct tablet_shell *shell = window_get_user_data(window);
+	struct tablet_shell *shell = data;
 
 	window_destroy(shell->lockscreen);
 	shell->lockscreen = NULL;
diff --git a/clients/terminal.c b/clients/terminal.c
index 9c3c56b..b6e3139 100644
--- a/clients/terminal.c
+++ b/clients/terminal.c
@@ -722,8 +722,6 @@
 				      pixel_width, pixel_height);
 	}
 
-	window_schedule_redraw (terminal->window);
-
 	data_pitch = width * sizeof(union utf8_char);
 	size = data_pitch * height;
 	data = malloc(size);
@@ -899,9 +897,11 @@
 	run->count += num_glyphs;
 }
 
+
 static void
-terminal_draw_contents(struct terminal *terminal)
+redraw_handler(struct widget *widget, void *data)
 {
+	struct terminal *terminal = data;
 	struct rectangle allocation;
 	cairo_t *cr;
 	int top_margin, side_margin;
@@ -1011,7 +1011,7 @@
 }
 
 static void
-resize_handler(struct window *window,
+resize_handler(struct widget *widget,
 	       int32_t pixel_width, int32_t pixel_height, void *data)
 {
 	struct terminal *terminal = data;
@@ -1030,14 +1030,6 @@
 }
 
 static void
-redraw_handler(struct window *window, void *data)
-{
-	struct terminal *terminal = data;
-
-	terminal_draw_contents(terminal);
-}
-
-static void
 terminal_data(struct terminal *terminal, const char *data, size_t length);
 
 static void
@@ -1498,7 +1490,7 @@
 			if (set[1] && set[2]) {
 				window_set_child_size(terminal->window,
 						      args[2], args[1]);
-				resize_handler(terminal->window,
+				resize_handler(terminal->widget,
 					       args[2], args[1], terminal);
 			}
 			break;
@@ -2285,12 +2277,11 @@
 	terminal->margin = 5;
 
 	window_set_user_data(terminal->window, terminal);
-	window_set_redraw_handler(terminal->window, redraw_handler);
-	window_set_resize_handler(terminal->window, resize_handler);
-
 	window_set_key_handler(terminal->window, key_handler);
 	window_set_keyboard_focus_handler(terminal->window,
 					  keyboard_focus_handler);
+	widget_set_redraw_handler(terminal->widget, redraw_handler);
+	widget_set_resize_handler(terminal->widget, resize_handler);
 	widget_set_button_handler(terminal->widget, button_handler);
 	widget_set_motion_handler(terminal->widget, motion_handler);
 
diff --git a/clients/view.c b/clients/view.c
index 1a345e6..6c12f97 100644
--- a/clients/view.c
+++ b/clients/view.c
@@ -111,7 +111,7 @@
 }
 
 static void
-redraw_handler(struct window *window, void *data)
+redraw_handler(struct widget *widget, void *data)
 {
 	struct view *view = data;
 
@@ -119,7 +119,7 @@
 }
 
 static void
-resize_handler(struct window *window,
+resize_handler(struct widget *widget,
 	       int32_t width, int32_t height, void *data)
 {
 	struct view *view = data;
@@ -248,13 +248,13 @@
 	view->display = display;
 
 	window_set_user_data(view->window, view);
-	window_set_redraw_handler(view->window, redraw_handler);
-	window_set_resize_handler(view->window, resize_handler);
 	window_set_key_handler(view->window, key_handler);
 	window_set_keyboard_focus_handler(view->window,
 					  keyboard_focus_handler);
-	widget_set_button_handler(window_get_widget(view->window),
-				  button_handler);
+	widget_set_button_handler(view->widget, button_handler);
+	widget_set_resize_handler(view->widget, resize_handler);
+	widget_set_redraw_handler(view->widget, redraw_handler);
+
 	view->page = 0;
 
 	view->fullscreen = fullscreen;
diff --git a/clients/window.c b/clients/window.c
index 5f80721..b736b81 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -115,6 +115,8 @@
 	int resize_edges;
 	int redraw_scheduled;
 	struct task redraw_task;
+	int resize_scheduled;
+	struct task resize_task;
 	int minimum_width, minimum_height;
 	int margin;
 	int type;
@@ -126,8 +128,6 @@
 
 	cairo_surface_t *cairo_surface, *pending_surface;
 
-	window_resize_handler_t resize_handler;
-	window_redraw_handler_t redraw_handler;
 	window_key_handler_t key_handler;
 	window_keyboard_focus_handler_t keyboard_focus_handler;
 	window_data_handler_t data_handler;
@@ -148,6 +148,8 @@
 	struct window *window;
 	struct wl_list link;
 	struct rectangle allocation;
+	widget_resize_handler_t resize_handler;
+	widget_redraw_handler_t redraw_handler;
 	widget_enter_handler_t enter_handler;
 	widget_leave_handler_t leave_handler;
 	widget_motion_handler_t motion_handler;
@@ -1009,6 +1011,8 @@
 
 	if (window->redraw_scheduled)
 		wl_list_remove(&window->redraw_task.link);
+	if (window->resize_scheduled)
+		wl_list_remove(&window->resize_task.link);
 
 	wl_list_for_each(input, &display->input_list, link) {
 		if (input->pointer_focus == window)
@@ -1101,6 +1105,20 @@
 }
 
 void
+widget_set_resize_handler(struct widget *widget,
+			  widget_resize_handler_t handler)
+{
+	widget->resize_handler = handler;
+}
+
+void
+widget_set_redraw_handler(struct widget *widget,
+			  widget_redraw_handler_t handler)
+{
+	widget->redraw_handler = handler;
+}
+
+void
 widget_set_enter_handler(struct widget *widget, widget_enter_handler_t handler)
 {
 	widget->enter_handler = handler;
@@ -1858,39 +1876,75 @@
 }
 
 static void
+window_resize(struct window *window, int32_t width, int32_t height)
+{
+	struct widget *widget;
+	struct rectangle allocation;
+
+	if (window->decoration) {
+		allocation.x = 20;
+		allocation.y = 60;
+		allocation.width = width - 20 - window->margin * 2;
+		allocation.height = height - 60 - window->margin * 2;
+	} else {
+		allocation.x = 0;
+		allocation.y = 0;
+		allocation.width = width;
+		allocation.height = height;
+	}
+
+	window->allocation.width = width;
+	window->allocation.height = height;
+
+	wl_list_for_each(widget, &window->widget_list, link) {
+		if (widget->resize_handler)
+			widget->resize_handler(widget,
+					       allocation.width,
+					       allocation.height,
+					       widget->user_data);
+		else
+			widget->allocation = allocation;
+	}
+
+	window_schedule_redraw(window);
+}
+
+static void
+idle_resize(struct task *task, uint32_t events)
+{
+	struct window *window =
+		container_of(task, struct window, resize_task);
+
+	window_resize(window,
+		      window->allocation.width, window->allocation.height);
+	window->resize_scheduled = 0;
+}
+
+void
+window_schedule_resize(struct window *window, int width, int height)
+{
+	if (!window->resize_scheduled) {
+		window->allocation.width = width;
+		window->allocation.height = height;
+		window->resize_task.run = idle_resize;
+		display_defer(window->display, &window->resize_task);
+		window->resize_scheduled = 1;
+	}
+}
+
+static void
 handle_configure(void *data, struct wl_shell_surface *shell_surface,
 		 uint32_t time, uint32_t edges,
 		 int32_t width, int32_t height)
 {
 	struct window *window = data;
-	struct widget *widget;
-	int32_t child_width, child_height;
 
-	/* FIXME: this is probably the wrong place to check for width
-	 * or height <= 0, but it prevents the compositor from crashing
-	 */
 	if (width <= 0 || height <= 0)
 		return;
 
 	window->resize_edges = edges;
 
-	if (window->resize_handler) {
-		child_width = width - 20 - window->margin * 2;
-		child_height = height - 60 - window->margin * 2;
-
-		(*window->resize_handler)(window,
-					  child_width, child_height,
-					  window->user_data);
-	} else {
-		window->allocation.width = width;
-		window->allocation.height = height;
-
-		if (window->redraw_handler)
-			window_schedule_redraw(window);
-	}
-
-	wl_list_for_each(widget, &window->widget_list, link)
-		widget->allocation = window->allocation;
+	window_resize(window, width, height);
 }
 
 static void
@@ -1954,12 +2008,14 @@
 {
 	struct window *window =
 		container_of(task, struct window, redraw_task);
+	struct widget *widget;
 
 	window_create_surface(window);
 	if (window->decoration)
 		window_draw_decorations(window);
 
-	window->redraw_handler(window, window->user_data);
+	wl_list_for_each_reverse(widget, &window->widget_list, link)
+		widget->redraw_handler(widget, widget->user_data);
 
 	window_flush(window);
 
@@ -2006,7 +2062,7 @@
 		window->decoration = 1;
 	}
 
-	(*window->resize_handler)(window, width, height, window->user_data);
+	window_resize(window, width, height);
 }
 
 void
@@ -2028,20 +2084,6 @@
 }
 
 void
-window_set_resize_handler(struct window *window,
-			  window_resize_handler_t handler)
-{
-	window->resize_handler = handler;
-}
-
-void
-window_set_redraw_handler(struct window *window,
-			  window_redraw_handler_t handler)
-{
-	window->redraw_handler = handler;
-}
-
-void
 window_set_key_handler(struct window *window,
 		       window_key_handler_t handler)
 {
@@ -2246,12 +2288,13 @@
 }
 
 static void
-menu_redraw_handler(struct window *window, void *data)
+menu_redraw_handler(struct widget *widget, void *data)
 {
 	cairo_t *cr;
 	const int32_t r = 3, margin = 3;
 	struct menu *menu = data;
 	int32_t width, height, i;
+	struct window *window = widget->window;
 
 	cr = cairo_create(window->cairo_surface);
 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
@@ -2319,9 +2362,7 @@
 				   window->parent->shell_surface,
 				   window->x, window->y, 0);
 
-	window_set_redraw_handler(window, menu_redraw_handler);
-	window_set_user_data(window, menu);
-
+	widget_set_redraw_handler(menu->widget, menu_redraw_handler);
 	widget_set_enter_handler(menu->widget, menu_enter_handler);
 	widget_set_leave_handler(menu->widget, menu_leave_handler);
 	widget_set_motion_handler(menu->widget, menu_motion_handler);
diff --git a/clients/window.h b/clients/window.h
index c50c0da..6d35d66 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -156,11 +156,6 @@
 	POINTER_HAND1,
 };
 
-typedef void (*window_resize_handler_t)(struct window *window,
-					int32_t width, int32_t height,
-					void *data);
-typedef void (*window_redraw_handler_t)(struct window *window, void *data);
-
 typedef void (*window_key_handler_t)(struct window *window, struct input *input,
 				     uint32_t time, uint32_t key, uint32_t unicode,
 				     uint32_t state, void *data);
@@ -180,6 +175,11 @@
 
 typedef void (*window_close_handler_t)(struct window *window, void *data);
 
+typedef void (*widget_resize_handler_t)(struct widget *widget,
+					int32_t width, int32_t height,
+					void *data);
+typedef void (*widget_redraw_handler_t)(struct widget *widget, void *data);
+
 typedef int (*widget_enter_handler_t)(struct widget *widget,
 				      struct input *input, uint32_t time,
 				      int32_t x, int32_t y, void *data);
@@ -250,6 +250,8 @@
 window_set_child_size(struct window *window, int32_t width, int32_t height);
 void
 window_schedule_redraw(struct window *window);
+void
+window_schedule_resize(struct window *window, int width, int height);
 
 void
 window_damage(struct window *window, int32_t x, int32_t y,
@@ -299,17 +301,9 @@
 window_get_user_data(struct window *window);
 
 void
-window_set_redraw_handler(struct window *window,
-			  window_redraw_handler_t handler);
-
-void
 window_set_decoration(struct window *window, int decoration);
 
 void
-window_set_resize_handler(struct window *window,
-			  window_resize_handler_t handler);
-
-void
 window_set_key_handler(struct window *window,
 		       window_key_handler_t handler);
 
@@ -346,6 +340,12 @@
 widget_get_user_data(struct widget *widget);
 
 void
+widget_set_redraw_handler(struct widget *widget,
+			  widget_redraw_handler_t handler);
+void
+widget_set_resize_handler(struct widget *widget,
+			  widget_resize_handler_t handler);
+void
 widget_set_enter_handler(struct widget *widget,
 			 widget_enter_handler_t handler);
 void