diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am
index 74520fc2bf..091f06d7b7 100644
--- a/docs/reference/gtk/Makefile.am
+++ b/docs/reference/gtk/Makefile.am
@@ -328,6 +328,8 @@ HTML_IMAGES = \
$(srcdir)/images/layout-tbrl.png \
$(srcdir)/images/window-default.png \
$(srcdir)/images/hello-world.png \
+ $(srcdir)/images/grid-packing.png \
+ $(srcdir)/images/drawing.png \
$(srcdir)/images/switch.png \
$(srcdir)/images/linear.png \
$(srcdir)/images/ease.png \
diff --git a/docs/reference/gtk/getting_started.xml b/docs/reference/gtk/getting_started.xml
index aebc5ee42f..d47a09f1fd 100644
--- a/docs/reference/gtk/getting_started.xml
+++ b/docs/reference/gtk/getting_started.xml
@@ -147,4 +147,41 @@
+
+ Drawing
+
+ Many widgets, like buttons, do all their drawing themselves. You
+ just tell them the label you want to see, and they figure out what font
+ to use, draw the button outline and focus rectangle, etc. Sometimes, it
+ is necessary to do some custom drawing. In that case, a #GtkDrawingArea
+ might be the right widget to use. It offers a canvas on which you can
+ draw by connecting to the #GtkWidget::draw signal.
+
+
+ The contents of a widget often need to be partially or fully redrawn,
+ e.g. when another window is moved and uncovers part of the widget, or
+ when tie window containing it is resized. It is also possible to explicitly
+ cause part or all of the widget to be redrawn, by calling
+ gtk_widget_queue_draw() or its variants. GTK+ takes care of most of the
+ details by providing a ready-to-use cairo context to the ::draw signal
+ handler.
+
+ The following example shows a ::draw signal handler. It is a bit
+ more complicated than the previous examples, since it also demonstrates
+ input event handling by means of ::button-press and ::motion-notify
+ handlers.
+
+
+
+
+
+
+ Drawing in response to input
+
+
+ FIXME: MISSING XINCLUDE CONTENT
+
+
+
+
diff --git a/docs/reference/gtk/images/drawing.png b/docs/reference/gtk/images/drawing.png
new file mode 100644
index 0000000000..a5105002ef
Binary files /dev/null and b/docs/reference/gtk/images/drawing.png differ
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f4d06bfd41..948d58a213 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -48,4 +48,9 @@ LDADD = \
$(top_builddir)/gtk/libgtk-3.0.la \
$(GTK_DEP_LIBS)
-noinst_PROGRAMS = hello-world window-default bloatpad grid-packing
+noinst_PROGRAMS = \
+ hello-world \
+ window-default \
+ bloatpad \
+ grid-packing \
+ drawing
diff --git a/examples/drawing.c b/examples/drawing.c
new file mode 100644
index 0000000000..28f291b8b8
--- /dev/null
+++ b/examples/drawing.c
@@ -0,0 +1,200 @@
+#include
+
+/* Surface to store current scribbles */
+static cairo_surface_t *surface = NULL;
+
+static void
+clear_surface (void)
+{
+ cairo_t *cr;
+
+ cr = cairo_create (surface);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+}
+
+/* Create a new surface of the appropriate size to store our scribbles */
+static gboolean
+configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ if (surface)
+ cairo_surface_destroy (surface);
+
+ surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
+ CAIRO_CONTENT_COLOR,
+ gtk_widget_get_allocated_width (widget),
+ gtk_widget_get_allocated_height (widget));
+
+ /* Initialize the surface to white */
+ clear_surface ();
+
+ /* We've handled the configure event, no need for further processing. */
+ return TRUE;
+}
+
+/* Redraw the screen from the surface. Note that the ::draw
+ * signal receives a ready-to-be-used cairo_t that is already
+ * clipped to only draw the exposed areas of the widget
+ */
+static gboolean
+draw_cb (GtkWidget *widget,
+ cairo_t *cr,
+ gpointer data)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ return FALSE;
+}
+
+/* Draw a rectangle on the surface at the given position */
+static void
+draw_brush (GtkWidget *widget,
+ gdouble x,
+ gdouble y)
+{
+ cairo_t *cr;
+
+ /* Paint to the surface, where we store our state */
+ cr = cairo_create (surface);
+
+ cairo_rectangle (cr, x - 3, y - 3, 6, 6);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+
+ /* Now invalidate the affected region of the drawing area. */
+ gtk_widget_queue_draw_area (widget, x - 3, y - 3, 6, 6);
+}
+
+/* Handle button press events by either drawing a rectangle
+ * or clearing the surface, depending on which button was pressed.
+ * The ::button-press signal handler receives a GdkEventButton
+ * struct which contains this information.
+ */
+static gboolean
+button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ /* paranoia check, in case we haven't gotten a configure event */
+ if (surface == NULL)
+ return FALSE;
+
+ if (event->button == 1)
+ {
+ draw_brush (widget, event->x, event->y);
+ }
+ else if (event->button == 3)
+ {
+ clear_surface ();
+ gtk_widget_queue_draw (widget);
+ }
+
+ /* We've handled the event, stop processing */
+ return TRUE;
+}
+
+/* Handle motion events by continuing to draw if button 1 is
+ * still held down. The ::motion-notify signal handler receives
+ * a GdkEventMotion struct which contains this information.
+ */
+static gboolean
+motion_notify_event_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data)
+{
+ int x, y;
+ GdkModifierType state;
+
+ /* paranoia check, in case we haven't gotten a configure event */
+ if (surface == NULL)
+ return FALSE;
+
+ /* This call is very important; it requests the next motion event.
+ * If you don't call gdk_window_get_pointer() you'll only get
+ * a single motion event. The reason is that we specified
+ * GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events().
+ * If we hadn't specified that, we could just use event->x, event->y
+ * as the pointer location. But we'd also get deluged in events.
+ * By requesting the next event as we handle the current one,
+ * we avoid getting a huge number of events faster than we
+ * can cope.
+ */
+ gdk_window_get_pointer (event->window, &x, &y, &state);
+
+ if (state & GDK_BUTTON1_MASK)
+ draw_brush (widget, x, y);
+
+ /* We've handled it, stop processing */
+ return TRUE;
+}
+
+static void
+close_window (void)
+{
+ if (surface)
+ cairo_surface_destroy (surface);
+
+ gtk_main_quit ();
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *frame;
+ GtkWidget *da;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
+
+ g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (window), frame);
+
+ da = gtk_drawing_area_new ();
+ /* set a minimum size */
+ gtk_widget_set_size_request (da, 100, 100);
+
+ gtk_container_add (GTK_CONTAINER (frame), da);
+
+ /* Signals used to handle the backing surface */
+ g_signal_connect (da, "draw",
+ G_CALLBACK (draw_cb), NULL);
+ g_signal_connect (da,"configure-event",
+ G_CALLBACK (configure_event_cb), NULL);
+
+ /* Event signals */
+ g_signal_connect (da, "motion-notify-event",
+ G_CALLBACK (motion_notify_event_cb), NULL);
+ g_signal_connect (da, "button-press-event",
+ G_CALLBACK (button_press_event_cb), NULL);
+
+ /* Ask to receive events the drawing area doesn't normally
+ * subscribe to. In particular, we need to ask for the
+ * button press and motion notify events that want to handle.
+ */
+ gtk_widget_set_events (da, gtk_widget_get_events (da)
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}