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