summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2011-01-18 23:57:17 -0500
committerMatthias Clasen <mclasen@redhat.com>2011-01-18 23:59:17 -0500
commit80e1340e51855f9fee469bc8dac95abdb7c56da4 (patch)
tree0d8b8ced51ca154b4feba176b8121e1d5faae4c6 /examples
parentceeaf183a11f2abfc487d6381718a2707e65f41d (diff)
downloadgtk+-80e1340e51855f9fee469bc8dac95abdb7c56da4.tar.gz
Add a drawing example to the tutorial
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile.am7
-rw-r--r--examples/drawing.c200
2 files changed, 206 insertions, 1 deletions
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 <gtk/gtk.h>
+
+/* 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;
+}