widget: Stop tracking invalidations
authorBenjamin Otte <otte@redhat.com>
Wed, 28 Mar 2018 14:42:26 +0000 (16:42 +0200)
committerBenjamin Otte <otte@redhat.com>
Thu, 5 Apr 2018 12:56:38 +0000 (14:56 +0200)
Instead of calling gdk_surface_invalidate_region(), just
gdk_surface_queue_expose() and rely on the renderer computing the diff
from the previous rendering.

docs/reference/gdk/gdk4-sections.txt
gdk/gdksurface.c
gdk/gdksurface.h
gtk/gtkwidget.c

index 2bbbc4fa231526408733446e6e853f7e88f8a8e8..784615d1ea7f4737b3b0fa5e6226205fcae17a05 100644 (file)
@@ -240,6 +240,7 @@ gdk_surface_end_draw_frame
 <SUBSECTION>
 gdk_surface_invalidate_rect
 gdk_surface_invalidate_region
+gdk_surface_queue_expose
 gdk_surface_freeze_updates
 gdk_surface_thaw_updates
 gdk_surface_get_frame_clock
index ea1f3fe65415bb2024ce09f1fb9d64c9014a740d..bc12fd589dba8230e972700f7dfec79f99bca458 100644 (file)
@@ -129,8 +129,6 @@ static void recompute_visible_regions   (GdkSurface *private,
 static void gdk_surface_invalidate_in_parent (GdkSurface *private);
 static void update_cursor               (GdkDisplay *display,
                                          GdkDevice  *device);
-static void impl_surface_add_update_area (GdkSurface *impl_surface,
-                                          cairo_region_t *region);
 static cairo_surface_t *gdk_surface_ref_impl_surface (GdkSurface *surface);
 
 static void gdk_surface_set_frame_clock (GdkSurface      *surface,
@@ -2202,7 +2200,7 @@ gdk_surface_invalidate_rect (GdkSurface        *surface,
 }
 
 static void
-impl_surface_add_update_area (GdkSurface *impl_surface,
+impl_surface_add_update_area (GdkSurface     *impl_surface,
                               cairo_region_t *region)
 {
   if (impl_surface->update_area)
@@ -2215,6 +2213,33 @@ impl_surface_add_update_area (GdkSurface *impl_surface,
     }
 }
 
+/**
+ * gdk_surface_queue_expose:
+ * @surface: a #GdkSurface
+ *
+ * Forces an expose event for @surface to be scheduled.
+ *
+ * If the invalid area of @surface is empty, an expose event will
+ * still be emitted. Its invalid region will be empty.
+ *
+ * This function is useful for implementations that track invalid
+ * regions on their own.
+ **/
+void
+gdk_surface_queue_expose (GdkSurface *surface)
+{
+  cairo_region_t *region;
+
+  g_return_if_fail (GDK_IS_SURFACE (surface));
+
+  while (!gdk_surface_has_impl (surface))
+    surface = surface->parent;
+
+  region = cairo_region_create ();
+  impl_surface_add_update_area (surface, region);
+  cairo_region_destroy (region);
+}
+
 /**
  * gdk_surface_invalidate_region:
  * @surface: a #GdkSurface
index 0da93cb8795688f92a5a87779858a9052566d95a..bed9bb04e3d439e6bda7b6760bad76fd83442fd7 100644 (file)
@@ -803,6 +803,8 @@ void gdk_surface_begin_move_drag_for_device   (GdkSurface     *surface,
 
 /* Interface for dirty-region queueing */
 GDK_AVAILABLE_IN_ALL
+void       gdk_surface_queue_expose              (GdkSurface          *surface);
+GDK_AVAILABLE_IN_ALL
 void       gdk_surface_invalidate_rect           (GdkSurface          *surface,
                                                   const GdkRectangle   *rect);
 GDK_AVAILABLE_IN_ALL
index 92c8084cd5c1a301c714a906fe8fffcb4bd1ba2a..77cafe489015e4144dbb470b4aa55add1c580f93 100644 (file)
@@ -3977,49 +3977,6 @@ gtk_widget_get_surface_allocation (GtkWidget     *widget,
   *allocation = alloc;
 }
 
-/**
- * gtk_widget_queue_draw_area:
- * @widget: a #GtkWidget
- * @x: x coordinate of upper-left corner of rectangle to redraw
- * @y: y coordinate of upper-left corner of rectangle to redraw
- * @width: width of region to draw
- * @height: height of region to draw
- *
- * Convenience function that calls gtk_widget_queue_draw_region() on
- * the region created from the given coordinates.
- *
- * The region here is specified in widget coordinates of @widget.
- *
- * @width or @height may be 0, in this case this function does
- * nothing. Negative values for @width and @height are not allowed.
- */
-void
-gtk_widget_queue_draw_area (GtkWidget *widget,
-                           gint       x,
-                           gint       y,
-                           gint       width,
-                           gint       height)
-{
-  GdkRectangle rect;
-  cairo_region_t *region;
-
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (width >= 0);
-  g_return_if_fail (height >= 0);
-
-  if (width == 0 || height == 0)
-    return;
-
-  rect.x = x;
-  rect.y = y;
-  rect.width = width;
-  rect.height = height;
-
-  region = cairo_region_create_rectangle (&rect);
-  gtk_widget_queue_draw_region (widget, region);
-  cairo_region_destroy (region);
-}
-
 static void
 gtk_widget_invalidate_paintable_contents (GtkWidget *widget)
 {
@@ -4056,9 +4013,44 @@ gtk_widget_real_queue_draw (GtkWidget *widget)
       priv->draw_needed = TRUE;
       g_clear_pointer (&priv->render_node, gsk_render_node_unref);
       gtk_widget_invalidate_paintable_contents (widget);
+      if (_gtk_widget_get_has_surface (widget) &&
+          _gtk_widget_get_realized (widget))
+        gdk_surface_queue_expose (gtk_widget_get_surface (widget));
     }
 }
 
+/**
+ * gtk_widget_queue_draw_area:
+ * @widget: a #GtkWidget
+ * @x: x coordinate of upper-left corner of rectangle to redraw
+ * @y: y coordinate of upper-left corner of rectangle to redraw
+ * @width: width of region to draw
+ * @height: height of region to draw
+ *
+ * Convenience function that calls gtk_widget_queue_draw_region() on
+ * the region created from the given coordinates.
+ *
+ * The region here is specified in widget coordinates of @widget.
+ *
+ * @width or @height may be 0, in this case this function does
+ * nothing. Negative values for @width and @height are not allowed.
+ */
+void
+gtk_widget_queue_draw_area (GtkWidget *widget,
+                           gint       x,
+                           gint       y,
+                           gint       width,
+                           gint       height)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  /* Just return if the widget isn't mapped */
+  if (!_gtk_widget_get_mapped (widget))
+    return;
+
+  gtk_widget_real_queue_draw (widget);
+}
+
 /**
  * gtk_widget_queue_draw:
  * @widget: a #GtkWidget
@@ -4069,22 +4061,13 @@ gtk_widget_real_queue_draw (GtkWidget *widget)
 void
 gtk_widget_queue_draw (GtkWidget *widget)
 {
-  GtkWidget *parent;
-  GdkRectangle *rect;
-
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  gtk_widget_real_queue_draw (widget);
-
-  parent = _gtk_widget_get_parent (widget);
-  rect = &widget->priv->clip;
+  /* Just return if the widget isn't mapped */
+  if (!_gtk_widget_get_mapped (widget))
+    return;
 
-  if (!_gtk_widget_get_has_surface (widget))
-    gtk_widget_queue_draw_area (parent ? parent : widget,
-                                rect->x, rect->y, rect->width, rect->height);
-  else
-    gtk_widget_queue_draw_area (widget,
-                                0, 0, rect->width, rect->height);
+  gtk_widget_real_queue_draw (widget);
 }
 
 static void
@@ -4314,85 +4297,15 @@ void
 gtk_widget_queue_draw_region (GtkWidget            *widget,
                               const cairo_region_t *region)
 {
-  GtkWidget *windowed_parent;
-  cairo_rectangle_int_t self_clip;
-  cairo_region_t *clip_region = NULL;
-  cairo_region_t *region2;
-  int x, y;
-  GtkCssStyle *parent_style;
-  GtkBorder border, padding;
-
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  if (cairo_region_is_empty (region))
-    return;
-
   /* Just return if the widget isn't mapped */
   if (!_gtk_widget_get_mapped (widget))
     return;
 
   gtk_widget_real_queue_draw (widget);
-
-  if (!_gtk_widget_get_parent (widget))
-    {
-      g_assert (_gtk_widget_get_has_surface (widget));
-      region2 = cairo_region_copy (region);
-      windowed_parent = widget;
-      goto invalidate;
-    }
-
-  /* priv->clip is in parent coordinates, transform it to @widget coordinates. */
-  self_clip = widget->priv->clip;
-  self_clip.x -= widget->priv->allocation.x;
-  self_clip.y -= widget->priv->allocation.y;
-  clip_region = cairo_region_create_rectangle (&self_clip);
-
-  region2 = cairo_region_copy (region);
-  cairo_region_intersect (region2, clip_region);
-
-  /* Look for the parent with a window and invalidate @region in there. */
-  windowed_parent = widget;
-  while (windowed_parent != NULL && !_gtk_widget_get_has_surface (windowed_parent))
-    windowed_parent = _gtk_widget_get_parent (windowed_parent);
-
-  g_assert (windowed_parent != NULL);
-
-  /* @region's coordinates are originally relative to @widget's origin */
-  if (widget != windowed_parent)
-    gtk_widget_translate_coordinates (widget,
-                                      windowed_parent,
-                                      0, 0,
-                                      &x, &y);
-  else
-    x = y = 0;
-
-  /* At this point, x and y are relative to the windowed parent's origin,
-   * but the window of the parent spans over its entire allocation, so we need
-   * to account for border and padding manually. The values returned from
-   * gtk_widget_get_surface_allocation, which should've been used to size and position
-   * @parent's window, do not include widget margins nor css margins.
-   */
-  parent_style = gtk_css_node_get_style (windowed_parent->priv->cssnode);
-  get_box_border (parent_style, &border);
-  get_box_padding (parent_style, &padding);
-
-  x += border.left + padding.left;
-  y += border.top + padding.top;
-
-  cairo_region_translate (region2, x, y);
-
-invalidate:
-  gdk_surface_invalidate_region (_gtk_widget_get_surface (widget), region2);
-
-  cairo_region_destroy (region2);
-
-  if (clip_region)
-    cairo_region_destroy (clip_region);
 }
 
-
-
-
 /**
  * gtk_widget_size_allocate:
  * @widget: a #GtkWidget