[gtk+] drawingarea: Add gtk_drawing_area_set_draw_func()



commit 5940625e9e55b713e2b112b558e447ac1d28644a
Author: Benjamin Otte <otte redhat com>
Date:   Fri Nov 18 05:45:36 2016 +0100

    drawingarea: Add gtk_drawing_area_set_draw_func()

 docs/reference/gtk/gtk4-sections.txt |    1 +
 gtk/gtkdrawingarea.c                 |  133 ++++++++++++++++++++++++++++------
 gtk/gtkdrawingarea.h                 |   29 +++++++-
 3 files changed, 140 insertions(+), 23 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index c80cde8..bf65d4d 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -896,6 +896,7 @@ gtk_drawing_area_get_content_width
 gtk_drawing_area_set_content_width
 gtk_drawing_area_get_content_height
 gtk_drawing_area_set_content_height
+gtk_drawing_area_set_draw_func
 <SUBSECTION Standard>
 GTK_DRAWING_AREA
 GTK_IS_DRAWING_AREA
diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c
index f2a5443..1a5849e 100644
--- a/gtk/gtkdrawingarea.c
+++ b/gtk/gtkdrawingarea.c
@@ -33,6 +33,10 @@ typedef struct _GtkDrawingAreaPrivate GtkDrawingAreaPrivate;
 struct _GtkDrawingAreaPrivate {
   int content_width;
   int content_height;
+
+  GtkDrawingAreaDrawFunc draw_func;
+  gpointer draw_func_target;
+  GDestroyNotify draw_func_target_destroy_notify;
 };
 
 enum {
@@ -46,7 +50,7 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
 
 /**
  * SECTION:gtkdrawingarea
- * @Short_description: A widget for custom user interface elements
+ * @Short_description: A simple widget for custom user interface elements
  * @Title: GtkDrawingArea
  * @See_also: #GtkImage
  *
@@ -65,32 +69,30 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
  * - The #GtkWidget::size-allocate signal to take any necessary
  *   actions when the widget changes size.
  *
- * - The #GtkWidget::draw signal to handle redrawing the
+ * - Call gtk_drawing_area_set_draw_func() to handle redrawing the
  *   contents of the widget.
  *
  * The following code portion demonstrates using a drawing
  * area to display a circle in the normal widget foreground
  * color.
  *
- * Note that GDK automatically clears the exposed area before sending
- * the expose event, and that drawing is implicitly clipped to the exposed
+ * Note that GDK automatically clears the exposed area before causing a
+ * redraw, and that drawing is implicitly clipped to the exposed
  * area. If you want to have a theme-provided background, you need
  * to call gtk_render_background() in your ::draw method.
  *
  * ## Simple GtkDrawingArea usage
  *
  * |[<!-- language="C" -->
- * gboolean
- * draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
+ * void
+ * draw_function (GtkDrawingArea *area, cairo_t *cr,
+ *                int width, int height,
+ *                gpointer data)
  * {
- *   guint width, height;
  *   GdkRGBA color;
  *   GtkStyleContext *context;
  *
- *   context = gtk_widget_get_style_context (widget);
- *
- *   width = gtk_widget_get_allocated_width (widget);
- *   height = gtk_widget_get_allocated_height (widget);
+ *   context = gtk_widget_get_style_context (GTK_WIDGET (area));
  *
  *   gtk_render_background (context, cr, 0, 0, width, height);
  *
@@ -105,23 +107,22 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
  *   gdk_cairo_set_source_rgba (cr, &color);
  *
  *   cairo_fill (cr);
- *
- *  return FALSE;
  * }
  * [...]
- *   GtkWidget *drawing_area = gtk_drawing_area_new ();
- *   gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (drawing_area), 100);
- *   gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (drawing_area), 100);
- *   g_signal_connect (G_OBJECT (drawing_area), "draw",
- *                     G_CALLBACK (draw_callback), NULL);
+ *   GtkWidget *area = gtk_drawing_area_new ();
+ *   gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100);
+ *   gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100);
+ *   gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area),
+ *                                   draw_function,
+ *                                   NULL, NULL);
  * ]|
  *
- * Draw signals are normally delivered when a drawing area first comes
+ * The draw function is normally called when a drawing area first comes
  * onscreen, or when it’s covered by another window and then uncovered.
- * You can also force an expose event by adding to the “damage region”
- * of the drawing area’s window using gtk_widget_queue_draw_region(),
+ * You can also force a redraw by adding to the “damage region” of the
+ * drawing area’s window using gtk_widget_queue_draw_region(),
  * gtk_widget_queue_draw_area() or gtk_widget_queue_draw().
- * You’ll then get a draw signal for the invalid region.
+ * This will cause the drawing area to call the draw function again.
  *
  * The available routines for drawing are documented on the
  * [GDK Drawing Primitives][gdk3-Cairo-Interaction] page
@@ -134,6 +135,9 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
  * area is focused. Use gtk_widget_has_focus() in your expose event
  * handler to decide whether to draw the focus indicator. See
  * gtk_render_focus() for one way to draw focus.
+ *
+ * If you need more complex control over your widget, you should consider
+ * creating your own #GtkWidget subclass.
  */
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkDrawingArea, gtk_drawing_area, GTK_TYPE_WIDGET)
@@ -186,6 +190,22 @@ gtk_drawing_area_get_property (GObject    *gobject,
 }
 
 static void
+gtk_drawing_area_dispose (GObject *object)
+{
+  GtkDrawingArea *self = GTK_DRAWING_AREA (object);
+  GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
+
+  if (priv->draw_func_target_destroy_notify != NULL)
+    priv->draw_func_target_destroy_notify (priv->draw_func_target);
+
+  priv->draw_func = NULL;
+  priv->draw_func_target = NULL;
+  priv->draw_func_target_destroy_notify = NULL;
+
+  G_OBJECT_CLASS (gtk_drawing_area_parent_class)->dispose (object);
+}
+
+static void
 gtk_drawing_area_measure (GtkWidget      *widget,
                           GtkOrientation  orientation,
                           int             for_size,
@@ -208,6 +228,30 @@ gtk_drawing_area_measure (GtkWidget      *widget,
 }
 
 static void
+gtk_drawing_area_snapshot (GtkWidget   *widget,
+                           GtkSnapshot *snapshot)
+{
+  GtkDrawingArea *self = GTK_DRAWING_AREA (widget);
+  GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
+  cairo_t *cr;
+
+  if (!priv->draw_func)
+    return;
+
+  cr = gtk_snapshot_append_cairo_node (snapshot,
+                                       &(graphene_rect_t) GRAPHENE_RECT_INIT(0, 0,
+                                         gtk_widget_get_allocated_width (widget),
+                                         gtk_widget_get_allocated_height (widget)),
+                                       "DrawingAreaContents");
+  priv->draw_func (self,
+                   cr,
+                   gtk_widget_get_allocated_width (widget),
+                   gtk_widget_get_allocated_height (widget),
+                   priv->draw_func_target);
+  cairo_destroy (cr);
+}
+
+static void
 gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
 {
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
@@ -215,8 +259,10 @@ gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
 
   gobject_class->set_property = gtk_drawing_area_set_property;
   gobject_class->get_property = gtk_drawing_area_get_property;
+  gobject_class->dispose = gtk_drawing_area_dispose;
 
   widget_class->measure = gtk_drawing_area_measure;
+  widget_class->snapshot = gtk_drawing_area_snapshot;
 
   /**
    * GtkDrawingArea:content-width
@@ -376,3 +422,46 @@ gtk_drawing_area_get_content_height (GtkDrawingArea *self)
   return priv->content_height;
 }
 
+/**
+ * gtk_drawing_area_set_draw_func:
+ * @self: a #GtkDrawingArea
+ * @draw_func: (closure user_data) (allow-none): callback that lets you draw
+ *     the drawing area's contents
+ * @user_data: user data passed to @draw_func
+ * @destroy: destroy notifier for @user_data
+ *
+ * Setting a draw function is the main thing you want to do when using a drawing
+ * area. It is called whenever GTK needs to draw the contents of the drawing area 
+ * to the screen.
+ *
+ * The draw function will be called during the drawing stage of GTK. In the
+ * drawing stage it is not allowed to change properties of any GTK widgets or call
+ * any functions that would cause any properties to be changed.
+ * You should restrict yourself exclusively to drawing your contents in the draw
+ * function.
+ *
+ * If what you are drawing does change, call gtk_widget_queue_draw() on the
+ * drawing area. This will call a redraw and will call @draw_func again.
+ *
+ * Since: 3.90
+ */
+void
+gtk_drawing_area_set_draw_func (GtkDrawingArea         *self,
+                                GtkDrawingAreaDrawFunc  draw_func,
+                                gpointer                user_data,
+                                GDestroyNotify          destroy)
+{
+  GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
+
+  g_return_if_fail (GTK_IS_DRAWING_AREA (self));
+
+  if (priv->draw_func_target_destroy_notify != NULL)
+    priv->draw_func_target_destroy_notify (priv->draw_func_target);
+
+  priv->draw_func = draw_func;
+  priv->draw_func_target = user_data;
+  priv->draw_func_target_destroy_notify = destroy;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
diff --git a/gtk/gtkdrawingarea.h b/gtk/gtkdrawingarea.h
index 8307b37..7d0ebb0 100644
--- a/gtk/gtkdrawingarea.h
+++ b/gtk/gtkdrawingarea.h
@@ -42,10 +42,32 @@ G_BEGIN_DECLS
 #define GTK_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DRAWING_AREA))
 #define GTK_DRAWING_AREA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_DRAWING_AREA, 
GtkDrawingAreaClass))
 
-
 typedef struct _GtkDrawingArea       GtkDrawingArea;
 typedef struct _GtkDrawingAreaClass  GtkDrawingAreaClass;
 
+/**
+ * GtkDrawingAreaDrawFunc:
+ * @drawing_area: the #GtkDrawingArea to redraw
+ * @cr: the context to draw to
+ * @width: the actual width of the contents. This value will be at least
+ *   as wide as GtkDrawingArea:width.
+ * @height: the actual height of the contents. This value will be at least
+ *   as wide as GtkDrawingArea:height.
+ * @user_data: (closure): user data
+ *
+ * Whenever @drawing_area needs to redraw, this function will be called.
+ *
+ * This function should exclusively redraw the contents of the drawing area
+ * and must not call any widget functions that cause changes.
+ *
+ * Since: 3.90
+ */
+typedef void (* GtkDrawingAreaDrawFunc)  (GtkDrawingArea *drawing_area,
+                                          cairo_t        *cr,
+                                          int             width,
+                                          int             height,
+                                          gpointer        user_data);
+
 struct _GtkDrawingArea
 {
   GtkWidget widget;
@@ -78,6 +100,11 @@ void            gtk_drawing_area_set_content_height     (GtkDrawingArea
                                                          int                     height);
 GDK_AVAILABLE_IN_3_90
 int             gtk_drawing_area_get_content_height     (GtkDrawingArea         *self);
+GDK_AVAILABLE_IN_3_90
+void            gtk_drawing_area_set_draw_func          (GtkDrawingArea         *self,
+                                                         GtkDrawingAreaDrawFunc  draw_func,
+                                                         gpointer                user_data,
+                                                         GDestroyNotify          destroy);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]