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