]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkregion-generic.c
Unshift the group when extracting it from the X keyboard event.
[~andy/gtk] / gdk / gdkregion-generic.c
index 4c3e42ece7f4d02be529ffcefff1e07bb67a86f5..524657a529b1f7d6e7b9ff2920faf5f95a5c5009 100644 (file)
@@ -123,6 +123,14 @@ gdk_region_new ()
   return temp;
 }
 
+/**
+ * gdk_region_rectangle:
+ * @rectangle: a #GdkRectangle
+ * 
+ * Creates a new region containing the area @rectangle.
+ * 
+ * Return value: a new region
+ **/
 GdkRegion *
 gdk_region_rectangle (GdkRectangle *rectangle)
 {
@@ -144,6 +152,14 @@ gdk_region_rectangle (GdkRectangle *rectangle)
   return temp;
 }
 
+/**
+ * gdk_region_copy:
+ * @region: a #GdkRegion
+ * 
+ * Copies @region, creating an identical new region.
+ * 
+ * Return value: a new region identical to @region
+ **/
 GdkRegion *
 gdk_region_copy (GdkRegion *region)
 {
@@ -170,6 +186,42 @@ gdk_region_get_clipbox (GdkRegion *r, GdkRectangle *rect)
   rect->height = r->extents.y2 - r->extents.y1;
 }
 
+
+/**
+ * gdk_region_get_rectangles:
+ * @region: a #GdkRegion
+ * @rectangles: return location for an array of rectangles
+ * @n_rectangles: length of returned array
+ *
+ * Obtains the area covered by the region as a list of rectangles.
+ * The array returned in @rectangles must be freed with g_free().
+ * 
+ **/
+void
+gdk_region_get_rectangles (GdkRegion     *region,
+                           GdkRectangle **rectangles,
+                           gint          *n_rectangles)
+{
+  gint i;
+  
+  g_return_if_fail (region != NULL);
+  g_return_if_fail (rectangles != NULL);
+  g_return_if_fail (n_rectangles != NULL);
+  
+  *n_rectangles = region->numRects;
+  *rectangles = g_new (GdkRectangle, region->numRects);
+
+  for (i = 0; i < region->numRects; i++)
+    {
+      GdkRegionBox rect;
+      rect = region->rects[i];
+      (*rectangles)[i].x = rect.x1;
+      (*rectangles)[i].y = rect.y1;
+      (*rectangles)[i].width = rect.x2 - rect.x1;
+      (*rectangles)[i].height = rect.y2 - rect.y1;
+    }
+}
+
 void
 gdk_region_union_with_rect (GdkRegion    *region,
                            GdkRectangle *rect)
@@ -456,6 +508,16 @@ miIntersectO (GdkRegion    *pReg,
     }
 }
 
+/**
+ * gdk_region_intersect:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * Converts @source1 into the intersection between @source1 and @source2.
+ * That is, after calling this function @source2 will be unchanged and
+ * @source1 will be the areas the two regions have in common.
+ * 
+ **/
 void
 gdk_region_intersect (GdkRegion *region,
                      GdkRegion *other)
@@ -1310,21 +1372,15 @@ miSubtractO (GdkRegion    *pReg,
        }
     }
 }
-       
-/*-
- *-----------------------------------------------------------------------
- * gdk_region_subtract --
- *     Subtract other from region and leave the result in region.
- *
- * Results:
- *     TRUE.
- *
- * Side Effects:
- *     region is overwritten.
- *
- *-----------------------------------------------------------------------
- */
 
+/**
+ * gdk_region_subtract:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * Subtracts any area in @source2 from the area in @source1.
+ * 
+ **/
 void
 gdk_region_subtract (GdkRegion *region,
                     GdkRegion *other)
@@ -1346,6 +1402,17 @@ gdk_region_subtract (GdkRegion *region,
   miSetExtents (region);
 }
 
+/**
+ * gdk_region_xor:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * XORs the two regions, placing the result in @source1.  The XOR of two
+ * regions contains all areas which were not overlapping.  That is,
+ * it's the union of the regions minus the intersection of the
+ * regions.
+ * 
+ **/
 void
 gdk_region_xor (GdkRegion *sra,
                GdkRegion *srb)
@@ -1505,3 +1572,151 @@ gdk_region_rect_in (GdkRegion    *region,
              GDK_OVERLAP_RECTANGLE_PART : GDK_OVERLAP_RECTANGLE_IN) : 
          GDK_OVERLAP_RECTANGLE_OUT);
 }
+
+
+static void
+gdk_region_unsorted_spans_intersect_foreach (GdkRegion *region,
+                                            GdkSpan   *spans,
+                                            int        n_spans,
+                                            GdkSpanFunc function,
+                                            gpointer data)
+{
+  gint i, left, right, y;
+  gint clipped_left, clipped_right;
+  GdkRegionBox *pbox;
+  GdkRegionBox *pboxEnd;
+  GdkSpan out_span;
+
+  if (!region->numRects)
+    return;
+
+  for (i=0;i<n_spans;i++)
+    {
+      y = spans[i].y;
+      left = spans[i].x;
+      right = left + spans[i].width; /* right is not in the span! */
+    
+      if (! ((region->extents.y1 <= y) &&
+            (region->extents.y2 > y) &&
+            (region->extents.x1 < right) &&
+            (region->extents.x2 > left)) ) 
+       continue;
+
+      /* can stop when we passed y */
+      for (pbox = region->rects, pboxEnd = pbox + region->numRects;
+          pbox < pboxEnd;
+          pbox++)
+       {
+         if (pbox->y2 <= y)
+           continue; /* Not quite there yet */
+         
+         if (pbox->y1 > y)
+           break; /* passed the spanline */
+         
+         if ((right > pbox->x1) && (left < pbox->x2)) 
+           {
+             clipped_left = MAX (left, pbox->x1);
+             clipped_right = MIN (right, pbox->x2);
+             
+             out_span.y = y;
+             out_span.x = clipped_left;
+             out_span.width = clipped_right - clipped_left;
+             (*function) (&out_span, data);
+           }
+       }
+    }
+}
+
+
+void
+gdk_region_spans_intersect_foreach (GdkRegion  *region,
+                                   GdkSpan    *spans,
+                                   int         n_spans,
+                                   gboolean    sorted,
+                                   GdkSpanFunc function,
+                                   gpointer    data)
+{
+  gint left, right, y;
+  gint clipped_left, clipped_right;
+  GdkRegionBox *pbox;
+  GdkRegionBox *pboxEnd;
+  GdkSpan *span, *tmpspan;
+  GdkSpan *end_span;
+  GdkSpan out_span;
+
+  if (!sorted)
+    {
+      gdk_region_unsorted_spans_intersect_foreach (region,
+                                                  spans,
+                                                  n_spans,
+                                                  function,
+                                                  data);
+      return;
+    }
+  
+  if ((!region->numRects) || (n_spans == 0))
+    return;
+
+  y = span->y;
+  left = span->x;
+  right = span->x + span->width; /* right is not in the span! */
+
+  /* The main method here is to step along the
+   * sorted rectangles and spans in lock step, and
+   * clipping the spans that are in the current
+   * rectangle before going on to the next rectangle.
+   */
+
+  span = spans;
+  end_span = spans + n_spans;
+  pbox = region->rects;
+  pboxEnd = pbox + region->numRects;
+  while (pbox < pboxEnd)
+    {
+      while ((pbox->y2 < span->y) || (span->y < pbox->y1))
+       {
+         /* Skip any rectangles that are above the current span */
+         if (pbox->y2 < span->y)
+           {
+             pbox++;
+             if (pbox == pboxEnd)
+               return;
+           }
+         /* Skip any spans that are above the current rectangle */
+         if (span->y < pbox->y1)
+           {
+             span++;
+             if (span == end_span)
+               return;
+           }
+       }
+      
+      /* Ok, we got at least one span that might intersect this rectangle. */
+      tmpspan = span;
+      while ((tmpspan < end_span) &&
+            (tmpspan->y < pbox->y2))
+       {
+         y = tmpspan->y;
+         left = tmpspan->x;
+         right = left + tmpspan->width; /* right is not in the span! */
+         
+         if ((right > pbox->x1) && (left < pbox->x2))
+           {
+             clipped_left = MAX (left, pbox->x1);
+             clipped_right = MIN (right, pbox->x2);
+             
+             out_span.y = y;
+             out_span.x = clipped_left;
+             out_span.width = clipped_right - clipped_left;
+             (*function) (&out_span, data);
+           }
+         
+         tmpspan++;
+       }
+
+      /* Finished this rectangle.
+       * The spans could still intersect the next one
+       */
+      pbox++;
+    }
+}