]> Pileus Git - ~andy/gtk/blob - gdk/testgdk.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~andy/gtk] / gdk / testgdk.c
1 /* testgdk -- validation program for GDK
2  * Copyright (C) 2000 Tor Lillqvist
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /* This program is intended to be used to validate the correctness of
21  * the basic graphics operations in a GDK backend. The results of the
22  * operations are compared against those produced by a correctly
23  * functioning X11 backend (and X11 server).
24  *
25  * Obviously, only the most basic operations reasonably be expected to
26  * produce pixel-by-pixel identical results as the X11 backend. We
27  * don't even try to test the correctness of ellipses, tiles or
28  * stipples. Not to mention fonts.
29  *
30  * But, for those operations we do test, we should try to test quite
31  * many combinations of parameters.
32  *
33  * This is just a quick hack, and could be improved a lot. There are
34  * copy-pasted code snippets all over that need to be factored out
35  * into separate functions.
36  */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42
43 #include <gdk/gdk.h>
44
45 /* CQTESTF -- "Conditionally Quiet TEST with Fail message"
46  * macro that prints PASS or FAIL messages
47  * parms:       quiet:  if TRUE, only print FAIL messages
48  *              expr:   the expression to test
49  *              failfmt:if expr is FALSE, print this message
50  *                      (both format and args)
51  */
52
53 #define CQTESTF(quiet, expr, failfmt) \
54   (tmpb = (expr), \
55    (tmpb ? (quiet ? 0 : printf ("PASS: %d %s\n", __LINE__, #expr)) \
56          : (printf ("FAIL: %d %s", __LINE__, #expr), \
57          printf failfmt, \
58          printf ("\n"), \
59          retval = FALSE, \
60          error (), \
61          return_value++)), \
62    tmpb)
63
64 /* Variations with less parms */
65
66 #define CQTEST(quiet, expr) \
67   CQTESTF (quiet, expr, (""))
68
69 #define TEST(expr) \
70   CQTEST (FALSE, expr)
71
72 #define QTEST(expr) \
73   CQTEST (TRUE, expr)
74
75 #define TESTF(expr, failfmt) \
76   CQTESTF (FALSE, expr, failfmt)
77
78 #define QTESTF(expr, failfmt) \
79   CQTESTF (TRUE, expr, failfmt)
80
81 #define ASSERT(expr) \
82   do { \
83     if (!QTEST (expr)) \
84       printf ("That is fatal. Goodbye\n"), exit (1);\
85   } while (0)
86
87 #define N(a) (sizeof(a)/sizeof(*a))
88
89 static int return_value = 0;
90
91 static gboolean retval;
92 static gboolean tmpb;
93
94 static GdkVisual *system_visual;
95 static GdkVisual *best_visual;
96 static GdkWindow *w;
97
98 static GdkColormap *system_colourmap;
99
100 static GdkColor white, black, red, green, blue, rand1_colour, rand2_colour;
101
102 static GdkGC *black_gc, *white_gc, *red_gc, *rand1_gc, *rand2_gc;
103 static GdkGC *gcs[5];
104 static GdkGC *black_bitmap_gc;
105
106 static int
107 error (void)
108 {
109   /* Place breakpoint here to catch failures */
110   return 0;
111 }
112
113 static gboolean
114 test_visual_coherency (gboolean   quiet,
115                  GdkVisual *visual)
116 {
117   gboolean retval = TRUE;
118
119   CQTEST (quiet, visual->type >= GDK_VISUAL_STATIC_GRAY &&
120           visual->type <= GDK_VISUAL_DIRECT_COLOR);
121   CQTEST (quiet, visual->depth >= 1 && visual->depth <= 32);
122   CQTEST (quiet, visual->byte_order == GDK_LSB_FIRST || visual->byte_order ==
123           GDK_MSB_FIRST);
124   
125   return retval;
126 }
127
128 /* Test visuals
129  */
130 static void
131 test_visuals (void)
132 {
133   GdkVisual *visual;
134   GList *visuals;
135
136   system_visual = gdk_visual_get_system ();
137   ASSERT (system_visual != NULL);
138   TEST (test_visual_coherency (FALSE, system_visual));
139
140   best_visual = gdk_visual_get_best ();
141   if (best_visual != system_visual)
142     TEST (test_visual_coherency (TRUE, best_visual));
143
144   visuals = gdk_list_visuals ();
145   while (visuals)
146     {
147       visual = visuals->data;
148       TEST (test_visual_coherency (TRUE, visual));
149       visuals = visuals->next;
150     }
151 }
152
153 /* Create a top-level window used by other tests
154  */
155 static void
156 test_first_window (void)
157 {
158   GdkWindowAttr wa;
159
160   wa.width = 100;
161   wa.height = 100;
162   wa.window_type = GDK_WINDOW_TOPLEVEL;
163   wa.wclass = GDK_INPUT_OUTPUT;
164
165   w = gdk_window_new (NULL, &wa, 0);
166
167   ASSERT (w != NULL);
168 }
169
170 /* Test colourmaps.
171  */
172 static void
173 test_colourmaps (void)
174 {
175   system_colourmap = gdk_colormap_get_system ();
176   ASSERT (system_colourmap != NULL);
177 }
178
179 /* Test colours.
180  */
181 static void
182 test_colours (void)
183 {
184   ASSERT (gdk_color_white (system_colourmap, &white));
185   ASSERT (gdk_color_black (system_colourmap, &black));
186   red.red = 65535;
187   red.green = red.blue = 0;
188   TEST (gdk_colormap_alloc_color (system_colourmap, &red, FALSE, TRUE));
189
190   rand1_colour.red = rand () % 65536;
191   rand1_colour.green = rand () % 65536;
192   rand1_colour.blue = rand () % 65536;
193   TEST (gdk_colormap_alloc_color (system_colourmap, &rand1_colour, FALSE,
194 TRUE));
195
196   rand2_colour.red = rand () % 65536;
197   rand2_colour.green = rand () % 65536;
198   rand2_colour.blue = rand () % 65536;
199   TEST (gdk_colormap_alloc_color (system_colourmap, &rand2_colour, FALSE,
200 TRUE));
201 }
202
203 static gboolean
204 test_default_gc (GdkGCValues *gcvalues,
205            gboolean     quiet)
206 {
207   gboolean retval = TRUE;
208
209   CQTEST (quiet, gcvalues->foreground.pixel == 0);
210   CQTEST (quiet, gcvalues->background.pixel == 1);
211   CQTEST (quiet, gcvalues->function == GDK_COPY);
212   CQTEST (quiet, gcvalues->fill == GDK_SOLID);
213   CQTEST (quiet, gcvalues->tile == NULL);
214   CQTEST (quiet, gcvalues->stipple == NULL);
215   CQTEST (quiet, gcvalues->clip_mask == NULL);
216   CQTEST (quiet, gcvalues->subwindow_mode == GDK_CLIP_BY_CHILDREN);
217   CQTEST (quiet, gcvalues->line_width == 0);
218   CQTEST (quiet, gcvalues->line_style == GDK_LINE_SOLID);
219   CQTEST (quiet, gcvalues->cap_style == GDK_CAP_BUTT);
220   CQTEST (quiet, gcvalues->join_style == GDK_JOIN_MITER);
221
222   return retval;
223 }
224
225 /* Create GdkGCs with various values,
226  * check that gdk_gc_get_values returns the same,
227  * or something reasonably close.
228  */
229 static void
230 test_gcs (void)
231 {
232   GdkPixmap *pixmap;
233   GdkGC *gc;
234   GdkGCValues gcvalues;
235   GdkColor colour;
236   GdkFunction function;
237   GdkFill fill;
238   gboolean retval;
239
240   gc = gdk_gc_new (w);
241   gdk_gc_get_values (gc, &gcvalues);
242   test_default_gc (&gcvalues, FALSE);
243
244   colour.pixel = 1234;
245   gdk_gc_set_foreground (gc, &colour);
246   gdk_gc_get_values (gc, &gcvalues);
247   TEST (gcvalues.foreground.pixel == 1234);
248
249   colour.pixel = 0;
250   gdk_gc_set_foreground (gc, &colour);
251   gdk_gc_get_values (gc, &gcvalues);
252   TEST (test_default_gc (&gcvalues, TRUE));
253
254   colour.pixel = 5678;
255   gdk_gc_set_background (gc, &colour);
256   gdk_gc_get_values (gc, &gcvalues);
257   TEST (gcvalues.background.pixel == 5678);
258
259   colour.pixel = 1;
260   gdk_gc_set_background (gc, &colour);
261   gdk_gc_get_values (gc, &gcvalues);
262   TEST (test_default_gc (&gcvalues, TRUE));
263
264   retval = TRUE;
265   for (function = GDK_COPY; function <= GDK_SET; function++)
266     {
267       gdk_gc_set_function (gc, function);
268       gdk_gc_get_values (gc, &gcvalues);
269       QTEST (gcvalues.function == function);
270       gdk_gc_set_function (gc, GDK_COPY);
271       gdk_gc_get_values (gc, &gcvalues);
272       QTEST (test_default_gc (&gcvalues, TRUE));
273     }
274   TEST (retval);
275
276   retval = TRUE;
277   for (fill = GDK_SOLID; fill <= GDK_OPAQUE_STIPPLED; fill++)
278     {
279       gdk_gc_set_fill (gc, fill);
280       gdk_gc_get_values (gc, &gcvalues);
281       QTEST (gcvalues.fill == fill);
282       gdk_gc_set_fill (gc, GDK_SOLID);
283       gdk_gc_get_values (gc, &gcvalues);
284       QTEST (test_default_gc (&gcvalues, TRUE));
285     }
286   TEST (retval);
287
288   black_gc = gdk_gc_new (w);
289   gdk_gc_copy (black_gc, gc);
290   gdk_gc_get_values (black_gc, &gcvalues);
291   TEST (test_default_gc (&gcvalues, TRUE));
292   gdk_gc_unref (gc);
293
294   gdk_gc_set_foreground (black_gc, &black);
295   gdk_gc_get_values (black_gc, &gcvalues);
296   TEST (gcvalues.foreground.pixel == black.pixel);
297
298   white_gc = gdk_gc_new (w);
299
300   gdk_gc_set_foreground (white_gc, &white);
301   gdk_gc_get_values (white_gc, &gcvalues);
302   TEST (gcvalues.foreground.pixel == white.pixel);
303
304   red_gc = gdk_gc_new (w);
305   gdk_gc_set_foreground (red_gc, &red);
306   gdk_gc_get_values (red_gc, &gcvalues);
307   TEST (gcvalues.foreground.pixel == red.pixel);
308
309   rand1_gc = gdk_gc_new (w);
310   gdk_gc_set_foreground (rand1_gc, &rand1_colour);
311   gdk_gc_get_values (rand1_gc, &gcvalues);
312   TESTF (gcvalues.foreground.pixel == rand1_colour.pixel,
313          (" %#06x != %#06x", gcvalues.foreground.pixel, rand1_colour.pixel));
314
315   rand2_gc = gdk_gc_new (w);
316   gdk_gc_set_foreground (rand2_gc, &rand2_colour);
317   gdk_gc_get_values (rand2_gc, &gcvalues);
318   TESTF (gcvalues.foreground.pixel == rand2_colour.pixel,
319          (" %#06x != %#06x", gcvalues.foreground.pixel, rand2_colour.pixel));
320
321   gcs[0] = black_gc;
322   gcs[1] = white_gc;
323   gcs[2] = red_gc;
324   gcs[3] = rand1_gc;
325   gcs[4] = rand2_gc;
326
327   pixmap = gdk_pixmap_new (NULL, 1, 1, 1);
328   black_bitmap_gc = gdk_gc_new (pixmap);
329   gdk_pixmap_unref (pixmap);
330 }
331
332 /* Create pixmaps, check that properties are as expected.
333  * No graphic operations tested yet.
334  */
335 static void
336 test_pixmaps (gint depth)
337 {
338   GdkPixmap *pixmap;
339   GdkImage *image;
340   GdkGC *gc;
341   gint width, height;
342   gint w, h;
343   gboolean retval = TRUE;
344
345   for (width = 1; width <= 64; width += 2)
346     for (height = 1; height <= 32; height += 3)
347       {
348         pixmap = gdk_pixmap_new (NULL, width, height, depth);
349         ASSERT (pixmap != NULL);
350         gdk_window_get_size (pixmap, &w, &h);
351         QTESTF (w == width, (" w:%d", w));
352         QTESTF (h == height, (" h:%d", h));
353         image = gdk_image_get (pixmap, 0, 0, w, h);
354         QTEST (image != NULL);
355         QTEST (image->width == width);
356         QTEST (image->height == height);
357         QTEST (image->depth == depth);
358         gdk_image_destroy (image);
359         gdk_pixmap_unref (pixmap);
360       }
361   TEST (retval);
362 }
363
364 /* Ditto for images.
365  */
366 static void
367 test_images (void)
368 {
369   GdkImage *image;
370   GdkImageType image_type;
371   gint width, height;
372   gboolean retval = TRUE;
373
374   for (width = 1; width <= 64; width += 3)
375     for (height = 1; height <= 32; height += 7)
376       for (image_type = GDK_IMAGE_NORMAL;
377            image_type <= GDK_IMAGE_FASTEST;
378            image_type++)
379         {
380           image = gdk_image_new (image_type, system_visual, width, height);
381           if (image == NULL && image_type == GDK_IMAGE_SHARED)
382             /* Ignore failure to create shared image,
383              * display might not be local.
384              */
385             ;
386           else
387             {
388               ASSERT (image != NULL);
389               QTEST (image->width == width);
390               QTEST (image->height == height);
391               QTEST (image->depth == system_visual->depth);
392               QTEST (image->bpp >= (image->depth-1)/8 + 1);
393               QTEST (image->mem != NULL);
394               gdk_image_destroy (image);
395             }
396         }
397   TEST (retval);
398 }
399
400 /* Test creating temp windows.
401  */
402 static void
403 test_temp_windows (void)
404 {
405   GdkWindow *window;
406   GdkWindowAttr wa;
407   GdkVisual *visual;
408   gint width, height;
409   gint w, h, x, y, d;
410   gboolean retval = TRUE;
411
412   wa.window_type = GDK_WINDOW_TEMP;
413   wa.wclass = GDK_INPUT_OUTPUT;
414
415   for (width = 1; width <= 64; width += 4)
416     for (height = 1; height <= 32; height += 7)
417       {
418         wa.width = width;
419         wa.height = height;
420         window = gdk_window_new (NULL, &wa, 0);
421         ASSERT (window != NULL);
422         gdk_window_get_geometry (window, &x, &y, &w, &h, &d);
423         QTESTF (w == width, ("w:%d", w));
424         QTESTF (h == height, ("h:%d", h));
425         gdk_window_show (window);
426         gdk_window_get_geometry (window, &x, &y, &w, &h, &d);
427         QTESTF (w == width, ("w:%d", w));
428         QTESTF (h == height, ("h:%d", h));
429         gdk_window_resize (window, 37, 19);
430         gdk_window_get_geometry (window, &x, &y, &w, &h, &d);
431         QTESTF (w == 37, ("w:%d", w));
432         QTESTF (h == 19, ("h:%d", h));
433         visual = gdk_window_get_visual (window);
434         QTEST (visual == system_visual);
435         gdk_window_hide (window);
436         gdk_window_unref (window);
437       }
438   TEST (retval);
439 }
440
441 static void
442 test_gc_function (GdkFunction function,
443             guint32     oldpixel,
444             guint32     newpixel,
445             guint32     foreground,
446             guint32     mask)
447 {
448   switch (function)
449     {
450     case GDK_COPY:
451       QTEST (newpixel == (foreground & mask)); break;
452     case GDK_INVERT:
453       QTEST (newpixel == ((~oldpixel) & mask)); break;
454     case GDK_XOR:
455       QTEST (newpixel == ((oldpixel ^ foreground) & mask)); break;
456     case GDK_CLEAR:
457       QTEST (newpixel == 0); break;
458     case GDK_AND:
459       QTEST (newpixel == ((oldpixel & foreground) & mask)); break;
460     case GDK_AND_REVERSE:
461       QTEST (newpixel == (((~oldpixel) & foreground) & mask)); break;
462     case GDK_AND_INVERT:
463       QTEST (newpixel == ((oldpixel & (~foreground)) & mask)); break;
464     case GDK_NOOP:
465       QTEST (newpixel == (oldpixel & mask)); break;
466     case GDK_OR:
467       QTEST (newpixel == ((oldpixel | foreground) & mask)); break;
468     case GDK_EQUIV:
469       QTEST (newpixel == ((oldpixel ^ (~foreground)) & mask)); break;
470     case GDK_OR_REVERSE:
471       QTEST (newpixel == (((~oldpixel) | foreground) & mask)); break;
472     case GDK_COPY_INVERT:
473       QTEST (newpixel == ((~foreground) & mask)); break;
474     case GDK_OR_INVERT:
475       QTEST (newpixel == ((oldpixel | (~foreground)) & mask)); break;
476     case GDK_NAND:
477       QTEST (newpixel == (((~oldpixel) | (~foreground)) & mask)); break;
478     case GDK_SET:
479       QTEST (newpixel == ((~0) & mask)); break;
480     default:
481       ASSERT (FALSE);
482     }
483 }
484
485 static void
486 test_one_point_on_drawable (GdkDrawable *drawable,
487                    GdkGC       *gc,
488                    int          depth)
489 {
490   GdkImage *image;
491   GdkGCValues gcvalues;
492   gint xoff, yoff;
493   guint32 oldpixels[3][3], newpixel, mask;
494   const gint x = 4;
495   const gint y = 5;
496
497   gdk_gc_get_values (gc, &gcvalues);
498
499   image = gdk_image_get (drawable, x+-1, y+-1, 3, 3);
500   QTEST (image != NULL);
501   for (xoff = -1; xoff <= 1; xoff++)
502     for (yoff = -1; yoff <= 1; yoff++)
503       {
504         oldpixels[xoff+1][yoff+1] = gdk_image_get_pixel (image, xoff+1, yoff+1);
505       }
506   gdk_image_destroy (image);
507
508   if (depth == 32)
509     mask = 0xFFFFFFFF;
510   else
511     mask = (1 << depth) - 1;
512
513   gdk_draw_point (drawable, gc, x, y);
514
515   image = gdk_image_get (drawable, x-1, y-1, 3, 3);
516   QTEST (image != NULL);
517   for (xoff = -1; xoff <= 1; xoff++)
518     for (yoff = -1; yoff <= 1; yoff++)
519       {
520         newpixel = gdk_image_get_pixel (image, xoff+1, yoff+1);
521         if (xoff == 0 && yoff == 0)
522           test_gc_function (gcvalues.function, oldpixels[1][1], newpixel,
523                             gcvalues.foreground.pixel, mask);
524         else
525           QTEST (newpixel == oldpixels[xoff+1][yoff+1]);
526       }
527   gdk_image_destroy (image);
528 }
529
530
531 /* Test drawing points.
532  */
533 static void
534 test_points (void)
535 {
536   GdkPixmap *pixmap;
537   GdkWindow *window;
538   GdkFunction function;
539   gint width, height;
540   int i, j;
541
542   width = 8;
543   height = 8;
544   pixmap = gdk_pixmap_new (w, width, height, -1);
545
546   for (i = 0; i < N(gcs); i++)
547     for (j = 0; j < N(gcs); j++)
548       for (function = GDK_COPY; function <= GDK_SET; function++)
549         {
550           gdk_draw_rectangle (pixmap, gcs[i], TRUE, 0, 0, width, height);
551           gdk_gc_set_function (gcs[j], function);
552           test_one_point_on_drawable (pixmap, gcs[j], system_visual->depth);
553           gdk_gc_set_function (gcs[j], GDK_COPY);
554         }
555   
556   gdk_pixmap_unref (pixmap);
557   
558   pixmap = gdk_pixmap_new (w, width, height, 1);
559   test_one_point_on_drawable (pixmap, black_bitmap_gc, 1);
560   for (function = GDK_COPY; function <= GDK_SET; function++)
561     {
562       gdk_gc_set_function (black_bitmap_gc, function);
563       test_one_point_on_drawable (pixmap, black_bitmap_gc, 1);
564     }
565
566   gdk_pixmap_unref (pixmap);
567 }
568
569 static void
570 test_one_line_on_drawable (GdkDrawable *drawable,
571                   GdkGC       *gc,
572                   int          depth,
573                   gboolean     horisontal)
574 {
575   GdkImage *oldimage, *newimage;
576   GdkGCValues gcvalues;
577   gint line_width;
578   gint w, h;
579   gint w_up, w_down, w_left, w_right;
580   gint x, y;
581   guint32 oldpixel, newpixel, mask;
582
583   gdk_gc_get_values (gc, &gcvalues);
584   line_width = gcvalues.line_width > 0 ? gcvalues.line_width : 1;
585   w_up = w_left = line_width/2;
586   w_down = w_right = (line_width & 1) ? line_width/2 : line_width/2-1;
587   gdk_window_get_size (drawable, &w, &h);
588   oldimage = gdk_image_get (drawable, 0, 0, w, h);
589
590   if (depth == 32)
591     mask = 0xFFFFFFFF;
592   else
593     mask = (1 << depth) - 1;
594
595   if (horisontal)
596     {
597       const gint x1 = 10;
598       const gint y1 = 10;
599       const gint x2 = 13;
600       const gint y2 = y1;
601
602       gdk_draw_line (drawable, gc, x1, y1, x2, y2);
603       newimage = gdk_image_get (drawable, 0, 0, w, h);
604       for (x = x1-1; x <= x2+1; x++)
605         for (y = y1-w_up-1; y <= y1+w_down+1; y++)
606           {
607             oldpixel = gdk_image_get_pixel (oldimage, x, y);
608             newpixel = gdk_image_get_pixel (newimage, x, y);
609             if (x >= x1 && x < x2 && y >= y1-w_up && y <= y1+w_down)
610               test_gc_function (gcvalues.function, oldpixel, newpixel,
611                                 gcvalues.foreground.pixel, mask);
612             else
613               QTEST (oldpixel == newpixel);
614           }
615     }
616   else /* vertical */
617     {
618       const gint x1 = 10;
619       const gint y1 = 10;
620       const gint x2 = 10;
621       const gint y2 = 13;
622
623       gdk_draw_line (drawable, gc, x1, y1, x2, y2);
624       newimage = gdk_image_get (drawable, 0, 0, w, h);
625       for (x = x1-w_left-1; x <= x1+w_right+1; x++)
626         for (y = y1-1; y <= y2+1; y++)
627           {
628             oldpixel = gdk_image_get_pixel (oldimage, x, y);
629             newpixel = gdk_image_get_pixel (newimage, x, y);
630             if (x >= x1-w_left && x <= x1+w_right && y >= y1 && y < y2)
631               test_gc_function (gcvalues.function, oldpixel, newpixel,
632                                 gcvalues.foreground.pixel, mask);
633             else
634               QTEST (oldpixel == newpixel);
635           }
636     }
637   
638   gdk_image_destroy (oldimage);
639   gdk_image_destroy (newimage);
640 }
641
642 /* Test drawing lines.
643  */
644 static void
645 test_lines (void)
646 {
647   GdkPixmap *pixmap;
648   GdkFunction function;
649   gint width;
650   int i, j;
651   gboolean horisontal = TRUE;
652
653   pixmap = gdk_pixmap_new (w, 30, 30, -1);
654
655   for (i = 0; i < N(gcs); i++)
656     for (j = 0; j < N(gcs); j++)
657       for (function = GDK_COPY; function <= GDK_SET; function++)
658         for (width = 1; width <= 4; width++)
659           {
660             gdk_draw_rectangle (pixmap, gcs[i], TRUE, 0, 0, 30, 30);
661             gdk_gc_set_function (gcs[j], function);
662             gdk_gc_set_line_attributes (gcs[j], width,
663                                         GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
664             test_one_line_on_drawable (pixmap, gcs[j], system_visual->depth,
665                                        horisontal);
666             /* Toggle between horisontal and vertical... */
667             horisontal = !horisontal;
668             gdk_gc_set_function (gcs[j], GDK_COPY);
669           }
670
671   gdk_pixmap_unref (pixmap);
672 }
673
674 static void
675 test_one_rectangle_on_drawable (GdkDrawable *drawable,
676                     GdkGC       *gc,
677                     int          depth,
678                     gboolean     filled)
679 {
680   GdkImage *oldimage, *newimage;
681   GdkGCValues gcvalues;
682   gint line_width;
683   gint w, h;
684   gint w_up, w_down, w_left, w_right;
685   gint x, y;
686   guint32 oldpixel, newpixel, mask;
687   const gint x0 = 10;
688   const gint y0 = 13;
689   const gint width = 7;
690   const gint height = 9;
691
692   gdk_gc_get_values (gc, &gcvalues);
693
694   if (!filled)
695     {
696       line_width = gcvalues.line_width > 0 ? gcvalues.line_width : 1;
697       w_up = w_left = line_width/2;
698       w_down = w_right = (line_width & 1) ? line_width/2 : line_width/2-1;
699     }
700
701   gdk_window_get_size (drawable, &w, &h);
702   oldimage = gdk_image_get (drawable, 0, 0, w, h);
703
704   if (depth == 32)
705     mask = 0xFFFFFFFF;
706   else
707     mask = (1 << depth) - 1;
708
709   gdk_draw_rectangle (drawable, gc, filled, x0, y0, width, height);
710   newimage = gdk_image_get (drawable, 0, 0, w, h);
711
712   for (x = x0 - 1; x <= x0 + width + 1; x++)
713     for (y = y0 - 1; y < y0 + height + 1; y++)
714       {
715         oldpixel = gdk_image_get_pixel (oldimage, x, y);
716         newpixel = gdk_image_get_pixel (newimage, x, y);
717         
718         if (filled)
719           {
720             if (x >= x0 && x < x0+width &&
721                 y >= y0 && y < y0+height)
722               test_gc_function (gcvalues.function, oldpixel, newpixel,
723                                 gcvalues.foreground.pixel, mask);
724             else
725               QTEST (oldpixel == newpixel);
726           }
727         else
728           {
729             if ((x >= x0-w_left && x <= x0+width+w_right &&
730                  y >= y0-w_up && y <= y0+w_down) ||
731                 (x >= x0-w_left && x <= x0+width+w_right &&
732                  y >= y0+height-w_up && y <= y0+height+w_down) ||
733                 (x >= x0-w_left && x <= x0+w_right &&
734                  y >= y0-w_up && y <= y0+height+w_down) ||
735                 (x >= x0+width-w_left && x <= x0+width+w_right &&
736                  y >= y0-w_up && y <= y0+height+w_down))
737               test_gc_function (gcvalues.function, oldpixel, newpixel,
738                                 gcvalues.foreground.pixel, mask);
739             else
740               QTEST (oldpixel == newpixel);
741           }
742       }
743   
744   gdk_image_destroy (oldimage);
745   gdk_image_destroy (newimage);
746 }
747
748 /* Test drawing rectangles.
749  */
750 static void
751 test_rectangles (void)
752 {
753   GdkPixmap *pixmap;
754   GdkFunction function;
755   gint width;
756   int i, j;
757   gboolean filled = FALSE;
758
759   pixmap = gdk_pixmap_new (w, 30, 30, -1);
760
761   for (i = 0; i < N(gcs); i++)
762     for (j = 0; j < N(gcs); j++)
763       for (function = GDK_COPY; function <= GDK_SET; function++)
764         for (width = 1; width <= 4; width++)
765           {
766             gdk_draw_rectangle (pixmap, gcs[i], TRUE, 0, 0, 30, 30);
767             gdk_gc_set_function (gcs[j], function);
768             gdk_gc_set_line_attributes (gcs[j], width,
769                                         GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
770             test_one_rectangle_on_drawable (pixmap, gcs[j],
771                                             system_visual->depth, filled);
772             filled = !filled;
773             gdk_gc_set_function (gcs[j], GDK_COPY);
774           }
775   
776   gdk_pixmap_unref (pixmap);
777 }
778
779 static void
780 test_some_arcs_on_drawable (GdkDrawable *drawable,
781                    GdkGC       *gc,
782                    int          depth,
783                    gboolean     filled)
784 {
785   GdkImage *oldimage, *newimage;
786   GdkGCValues gcvalues;
787   gint line_width;
788   gint w, h;
789   gint w_up, w_down, w_left, w_right;
790   gint x, y;
791   guint32 oldpixel, newpixel, mask;
792   /* XXX */
793   const gint x0 = 10;
794   const gint y0 = 13;
795   const gint width = 7;
796   const gint height = 9;
797
798   gdk_gc_get_values (gc, &gcvalues);
799
800   if (!filled)
801     {
802       line_width = gcvalues.line_width > 0 ? gcvalues.line_width : 1;
803       w_up = w_left = line_width/2;
804       w_down = w_right = (line_width & 1) ? line_width/2 : line_width/2-1;
805     }
806
807   gdk_window_get_size (drawable, &w, &h);
808   oldimage = gdk_image_get (drawable, 0, 0, w, h);
809
810   if (depth == 32)
811     mask = 0xFFFFFFFF;
812   else
813     mask = (1 << depth) - 1;
814
815   /* XXX */
816   newimage = gdk_image_get (drawable, 0, 0, w, h);
817
818   for (x = x0 - 1; x <= x0 + width + 1; x++)
819     for (y = y0 - 1; y < y0 + height + 1; y++)
820       {
821         oldpixel = gdk_image_get_pixel (oldimage, x, y);
822         newpixel = gdk_image_get_pixel (newimage, x, y);
823         
824         if (filled)
825           {
826             /* XXX */
827           }
828         else
829           {
830             /* XXX */
831           }
832       }
833   
834   gdk_image_destroy (oldimage);
835   gdk_image_destroy (newimage);
836 }
837
838 /* Test drawing arcs. Results don't have to be exactly as on X11,
839  * but "close".
840  */
841 static void
842 test_arcs (void)
843 {
844   GdkPixmap *pixmap;
845   GdkFunction function;
846   gint width;
847   int i, j;
848   gboolean filled = FALSE;
849
850   pixmap = gdk_pixmap_new (w, 30, 30, -1);
851
852   for (i = 0; i < N(gcs); i++)
853     for (j = 0; j < N(gcs); j++)
854       for (function = GDK_COPY; function <= GDK_SET; function++)
855         for (width = 1; width <= 4; width++)
856           {
857             gdk_draw_rectangle (pixmap, gcs[i], TRUE, 0, 0, 30, 30);
858             gdk_gc_set_function (gcs[j], function);
859             gdk_gc_set_line_attributes (gcs[j], width,
860                                         GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
861             test_some_arcs_on_drawable (pixmap, gcs[j], system_visual->depth,
862                                         filled);
863             filled = !filled;
864             gdk_gc_set_function (gcs[j], GDK_COPY);
865           }
866
867   gdk_pixmap_unref (pixmap);
868 }
869
870 /* Test region operations.
871  */
872 static void
873 test_regions (void)
874 {
875 }
876
877 static void
878 tests (void)
879 {
880   srand (time (NULL));
881
882   test_visuals ();
883   test_first_window ();
884   test_colourmaps ();
885   test_colours ();
886   test_gcs ();
887   test_pixmaps (1);
888   test_pixmaps (system_visual->depth);
889   if (best_visual->depth != system_visual->depth)
890     test_pixmaps (best_visual->depth);
891   test_images ();
892   test_temp_windows ();
893   test_points ();
894   test_lines ();
895   test_rectangles ();
896   test_arcs ();
897   test_regions ();
898 }
899
900 int
901 main (int argc, char **argv)
902 {
903   gdk_init (&argc, &argv);
904
905   tests ();
906
907   return return_value;
908 }