#include #include #include #define NO_MAIN #include "region-iter.c" static const pixman_rectangle32_t rects[] = { { 0, 50, 200, 100 }, { 250, 0, 200, 100 }, { 500, 0, 50, 350 }, { 400, 100, 50, 100 }, { 100, 150, 50, 50 }, { 50, 200, 150, 150 }, { 0, 300, 50, 50 }, { 200, 250, 100, 100 }, { 250, 150, 100, 100 }, { 350, 200, 100, 150 }, { 250, 350, 150, 50 }, { 450, 350, 50, 50 }, { 50, 450, 400, 50 }, { 25, 135, 600, 25 }, { 25, 355, 600, 25 }, { 125, 305, 300, 25 } }; #define N_RECTS (sizeof (rects) / sizeof (rects[0])) static corner_t * make_path (int *n_corners) { corner_t *corners; pixman_region32_t region; int i; pixman_box32_t *boxes = malloc (N_RECTS * sizeof (pixman_box32_t)); for (i = 0; i < N_RECTS; ++i) { boxes[i].x1 = rects[i].x; boxes[i].y1 = rects[i].y; boxes[i].x2 = rects[i].x + rects[i].width; boxes[i].y2 = rects[i].y + rects[i].height; } region_from_boxes (®ion, boxes, N_RECTS); pixman_region32_init (®ion); for (i = 0; i < N_RECTS; ++i) { pixman_region32_union_rect (®ion, ®ion, 50 + rects[i].x, 50 + rects[i].y, rects[i].width, rects[i].height); } corners = region_path (®ion, n_corners); pixman_region32_fini (®ion); return corners; } static gboolean on_expose (GtkWidget *widget, GdkEvent *event, gpointer data) { cairo_t *cr; int i; if (GTK_WIDGET_DRAWABLE (widget)) { corner_t *corners; int n_corners; cr = gdk_cairo_create (widget->window); for (i = 0; i < N_RECTS; ++i) { cairo_rectangle (cr, 50 + rects[i].x, 50 + rects[i].y, rects[i].width, rects[i].height); cairo_set_source_rgba ( cr, g_random_double(), g_random_double(), g_random_double(), 0.4); cairo_fill (cr); } corners = make_path (&n_corners); for (i = 0; i < n_corners; ++i) { corner_t *corner = &(corners[i]); cairo_move_to (cr, corner->x, corner->y); while (corner->next != -1) { corner_t *next = &(corners[corner->next]); cairo_line_to (cr, next->x, next->y); corner->next = -1; corner = next; } } cairo_set_source_rgba (cr, 0.2, g_random_double(), 0.2, 0); cairo_fill_preserve (cr); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); cairo_stroke (cr); free (corners); cairo_destroy (cr); } return TRUE; } static void on_allocate (GtkWidget *widget, GtkAllocation *allocation) { gtk_widget_queue_draw (widget); } int main (int argc, char **argv) { GtkWidget *window; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 1200, 768); g_signal_connect (window, "size_allocate", G_CALLBACK (on_allocate), NULL); g_signal_connect (window, "expose_event", G_CALLBACK (on_expose), NULL); gtk_widget_show_all (GTK_WIDGET (window)); gtk_main (); return 0; }