]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgc-win32.c
Merge from stable:
[~andy/gtk] / gdk / win32 / gdkgc-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
29                          GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
30
31 #include <string.h>
32
33 #include "gdkgc.h"
34 #include "gdkfont.h"
35 #include "gdkpixmap.h"
36 #include "gdkregion-generic.h"
37 #include "gdkprivate-win32.h"
38
39 static void gdk_win32_gc_get_values (GdkGC           *gc,
40                                      GdkGCValues     *values);
41 static void gdk_win32_gc_set_values (GdkGC           *gc,
42                                      GdkGCValues     *values,
43                                      GdkGCValuesMask  values_mask);
44 static void gdk_win32_gc_set_dashes (GdkGC           *gc,
45                                      gint             dash_offset,
46                                      gint8            dash_list[],
47                                      gint             n);
48
49 static void gdk_gc_win32_class_init (GdkGCWin32Class *klass);
50 static void gdk_gc_win32_finalize   (GObject         *object);
51
52 static gpointer parent_class = NULL;
53
54 GType
55 _gdk_gc_win32_get_type (void)
56 {
57   static GType object_type = 0;
58
59   if (!object_type)
60     {
61       static const GTypeInfo object_info =
62       {
63         sizeof (GdkGCWin32Class),
64         (GBaseInitFunc) NULL,
65         (GBaseFinalizeFunc) NULL,
66         (GClassInitFunc) gdk_gc_win32_class_init,
67         NULL,           /* class_finalize */
68         NULL,           /* class_data */
69         sizeof (GdkGCWin32),
70         0,              /* n_preallocs */
71         (GInstanceInitFunc) NULL,
72       };
73       
74       object_type = g_type_register_static (GDK_TYPE_GC,
75                                             "GdkGCWin32",
76                                             &object_info, 0);
77     }
78   
79   return object_type;
80 }
81
82 static void
83 gdk_gc_win32_class_init (GdkGCWin32Class *klass)
84 {
85   GObjectClass *object_class = G_OBJECT_CLASS (klass);
86   GdkGCClass *gc_class = GDK_GC_CLASS (klass);
87   
88   parent_class = g_type_class_peek_parent (klass);
89
90   object_class->finalize = gdk_gc_win32_finalize;
91
92   gc_class->get_values = gdk_win32_gc_get_values;
93   gc_class->set_values = gdk_win32_gc_set_values;
94   gc_class->set_dashes = gdk_win32_gc_set_dashes;
95 }
96
97 static void
98 gdk_gc_win32_finalize (GObject *object)
99 {
100   GdkGCWin32 *win32_gc = GDK_GC_WIN32 (object);
101   
102   if (win32_gc->hcliprgn != NULL)
103     DeleteObject (win32_gc->hcliprgn);
104   
105   if (win32_gc->values_mask & GDK_GC_FONT)
106     gdk_font_unref (win32_gc->font);
107   
108   if (win32_gc->values_mask & GDK_GC_TILE)
109     gdk_drawable_unref (win32_gc->tile);
110   
111   if (win32_gc->values_mask & GDK_GC_STIPPLE)
112     gdk_drawable_unref (win32_gc->stipple);
113
114   if (win32_gc->pen_dashes)
115     g_free (win32_gc->pen_dashes);
116   
117   G_OBJECT_CLASS (parent_class)->finalize (object);
118 }
119
120 static void
121 gdk_win32_gc_values_to_win32values (GdkGCValues    *values,
122                                     GdkGCValuesMask mask,
123                                     GdkGCWin32     *win32_gc)
124 {                                   
125   char *s = "";
126   gint sw, sh;
127
128   GDK_NOTE (GC, g_print ("{"));
129
130   if (mask & GDK_GC_FOREGROUND)
131     {
132       win32_gc->foreground = values->foreground.pixel;
133       win32_gc->values_mask |= GDK_GC_FOREGROUND;
134       GDK_NOTE (GC, (g_print ("fg=%.06lx", win32_gc->foreground),
135                      s = ","));
136     }
137   
138   if (mask & GDK_GC_BACKGROUND)
139     {
140       win32_gc->background = values->background.pixel;
141       win32_gc->values_mask |= GDK_GC_BACKGROUND;
142       GDK_NOTE (GC, (g_print ("%sbg=%.06lx", s, win32_gc->background),
143                      s = ","));
144     }
145
146   if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT
147                                || values->font->type == GDK_FONT_FONTSET))
148     {
149       if (win32_gc->font != NULL)
150         gdk_font_unref (win32_gc->font);
151       win32_gc->font = values->font;
152       if (win32_gc->font != NULL)
153         {
154           gdk_font_ref (win32_gc->font);
155           win32_gc->values_mask |= GDK_GC_FONT;
156           GDK_NOTE (GC, (g_print ("%sfont=%p", s, win32_gc->font),
157                          s = ","));
158         }
159       else
160         {
161           win32_gc->values_mask &= ~GDK_GC_FONT;
162           GDK_NOTE (GC, (g_print ("%sfont=NULL", s),
163                          s = ","));
164         }
165     }
166
167   if (mask & GDK_GC_FUNCTION)
168     {
169       GDK_NOTE (GC, (g_print ("%srop2=", s),
170                      s = ","));
171       switch (values->function)
172         {
173 #define CASE(x,y) case GDK_##x: win32_gc->rop2 = R2_##y; GDK_NOTE (GC, g_print (#y)); break
174         CASE (COPY, COPYPEN);
175         CASE (INVERT, NOT);
176         CASE (XOR, XORPEN);
177         CASE (CLEAR, BLACK);
178         CASE (AND, MASKPEN);
179         CASE (AND_REVERSE, MASKPENNOT);
180         CASE (AND_INVERT, MASKNOTPEN);
181         CASE (NOOP, NOP);
182         CASE (OR, MERGEPEN);
183         CASE (EQUIV, NOTXORPEN);
184         CASE (OR_REVERSE, MERGEPENNOT);
185         CASE (COPY_INVERT, NOTCOPYPEN);
186         CASE (OR_INVERT, MERGENOTPEN);
187         CASE (NAND, NOTMASKPEN);
188         CASE (NOR, NOTMERGEPEN);
189         CASE (SET, WHITE);
190 #undef CASE
191         }
192       win32_gc->values_mask |= GDK_GC_FUNCTION;
193     }
194
195   if (mask & GDK_GC_FILL)
196     {
197       win32_gc->fill_style = values->fill;
198       win32_gc->values_mask |= GDK_GC_FILL;
199       GDK_NOTE (GC, (g_print ("%sfill=%s", s,
200                               _gdk_win32_fill_style_to_string (win32_gc->fill_style)),
201                      s = ","));
202     }
203
204   if (mask & GDK_GC_TILE)
205     {
206       if (win32_gc->tile != NULL)
207         gdk_drawable_unref (win32_gc->tile);
208       win32_gc->tile = values->tile;
209       if (win32_gc->tile != NULL)
210         {
211           gdk_drawable_ref (win32_gc->tile);
212           win32_gc->values_mask |= GDK_GC_TILE;
213           GDK_NOTE (GC,
214                     (g_print ("%stile=%p", s,
215                               GDK_PIXMAP_HBITMAP (win32_gc->tile)),
216                      s = ","));
217         }
218       else
219         {
220           win32_gc->values_mask &= ~GDK_GC_TILE;
221           GDK_NOTE (GC, (g_print ("%stile=NULL", s),
222                          s = ","));
223         }
224     }
225
226   if (mask & GDK_GC_STIPPLE)
227     {
228       if (win32_gc->stipple != NULL)
229         gdk_drawable_unref (win32_gc->stipple);
230       win32_gc->stipple = values->stipple;
231       if (win32_gc->stipple != NULL)
232         {
233           gdk_drawable_get_size (win32_gc->stipple, &sw, &sh);
234
235 #if 0 /* HB: this size limitation is disabled to make radio and check
236        * buttons work. I got the impression from the API docs, that
237        * it shouldn't be necessary at all, but win9x would do the clipping
238        */
239           if (   (sw != 8 || sh != 8)
240               && !IS_WIN_NT ()) /* HB: the MSDN says it's a Win95 limitation */
241             {
242               /* It seems that it *must* be 8x8, at least on my machine. 
243                * Thus, tile an 8x8 bitmap with the stipple in case it is
244                * smaller, or simply use just the top left 8x8 in case it is
245                * larger.
246                */
247               gchar dummy[8];
248               GdkPixmap *bm = gdk_bitmap_create_from_data (NULL, dummy, 8, 8);
249               GdkGC *gc = gdk_gc_new (bm);
250               gint i, j;
251
252               i = 0;
253               while (i < 8)
254                 {
255                   j = 0;
256                   while (j < 8)
257                     {
258                       gdk_draw_drawable (bm, gc, win32_gc->stipple, 0, 0, i, j, sw, sh);
259                       j += sh;
260                     }
261                   i += sw;
262                 }
263               win32_gc->stipple = bm;
264               gdk_gc_unref (gc);
265             }
266           else
267 #endif
268             gdk_drawable_ref (win32_gc->stipple);
269           win32_gc->values_mask |= GDK_GC_STIPPLE;
270           GDK_NOTE (GC,
271                     (g_print ("%sstipple=%p", s,
272                               GDK_PIXMAP_HBITMAP (win32_gc->stipple)),
273                      s = ","));
274         }
275       else
276         {
277           win32_gc->values_mask &= ~GDK_GC_STIPPLE;
278           GDK_NOTE (GC, (g_print ("%sstipple=NULL", s),
279                          s = ","));
280         }
281     }
282
283   if (mask & GDK_GC_CLIP_MASK)
284     {
285       if (win32_gc->hcliprgn != NULL)
286         DeleteObject (win32_gc->hcliprgn);
287
288       if (values->clip_mask != NULL)
289         {
290           win32_gc->hcliprgn = _gdk_win32_bitmap_to_hrgn (values->clip_mask);
291           win32_gc->values_mask |= GDK_GC_CLIP_MASK;
292         }
293       else
294         {
295           win32_gc->hcliprgn = NULL;
296           win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
297         }
298       GDK_NOTE (GC, (g_print ("%sclip=%p", s, win32_gc->hcliprgn),
299                      s = ","));
300     }
301
302   if (mask & GDK_GC_SUBWINDOW)
303     {
304       win32_gc->subwindow_mode = values->subwindow_mode;
305       win32_gc->values_mask |= GDK_GC_SUBWINDOW;
306       GDK_NOTE (GC, (g_print ("%ssubw=%d", s, win32_gc->subwindow_mode),
307                      s = ","));
308     }
309
310   if (mask & GDK_GC_TS_X_ORIGIN)
311     {
312       win32_gc->values_mask |= GDK_GC_TS_X_ORIGIN;
313       GDK_NOTE (GC, (g_print ("%sts_x=%d", s, values->ts_x_origin),
314                      s = ","));
315     }
316
317   if (mask & GDK_GC_TS_Y_ORIGIN)
318     {
319       win32_gc->values_mask |= GDK_GC_TS_Y_ORIGIN;
320       GDK_NOTE (GC, (g_print ("%sts_y=%d", s, values->ts_y_origin),
321                      s = ","));
322     }
323
324   if (mask & GDK_GC_CLIP_X_ORIGIN)
325     {
326       win32_gc->values_mask |= GDK_GC_CLIP_X_ORIGIN;
327       GDK_NOTE (GC, (g_print ("%sclip_x=%d", s, values->clip_x_origin),
328                      s = ","));
329     }
330
331   if (mask & GDK_GC_CLIP_Y_ORIGIN)
332     {
333       win32_gc->values_mask |= GDK_GC_CLIP_Y_ORIGIN;
334       GDK_NOTE (GC, (g_print ("%sclip_y=%d", s, values->clip_y_origin),
335                      s = ","));
336     }
337
338   if (mask & GDK_GC_EXPOSURES)
339     {
340       win32_gc->graphics_exposures = values->graphics_exposures;
341       win32_gc->values_mask |= GDK_GC_EXPOSURES;
342       GDK_NOTE (GC, (g_print ("%sexp=%d", s, win32_gc->graphics_exposures),
343                      s = ","));
344     }
345
346   if (mask & GDK_GC_LINE_WIDTH)
347     {
348       win32_gc->pen_width = values->line_width;
349       win32_gc->values_mask |= GDK_GC_LINE_WIDTH;
350       GDK_NOTE (GC, (g_print ("%spw=%d", s, win32_gc->pen_width),
351                      s = ","));
352     }
353
354   if (mask & GDK_GC_LINE_STYLE)
355     {
356       switch (values->line_style)
357         {
358         case GDK_LINE_SOLID:
359           if (win32_gc->pen_dashes)
360             {
361               g_free (win32_gc->pen_dashes);
362               win32_gc->pen_dashes = NULL;
363             win32_gc->pen_num_dashes = 0;
364             }
365           win32_gc->pen_style &= ~(PS_STYLE_MASK);
366           win32_gc->pen_style |= PS_SOLID;
367           break;
368         case GDK_LINE_ON_OFF_DASH:
369         case GDK_LINE_DOUBLE_DASH: 
370           if (!win32_gc->pen_dashes)
371             {
372             /* setting to PS_DASH probably isn't correct. If I understand the
373              * xlib docs correctly it should influence the handling of
374              * line endings ? --hb
375              */
376             win32_gc->pen_style &= ~(PS_STYLE_MASK);
377             win32_gc->pen_style |= PS_DASH;
378           }
379           break;
380         }
381       GDK_NOTE (GC, (g_print ("%sps|=PS_STYLE_%s", s, _gdk_win32_psstyle_to_string (win32_gc->pen_style)),
382                      s = ","));
383       win32_gc->values_mask |= GDK_GC_LINE_STYLE;
384     }
385
386   if (mask & GDK_GC_CAP_STYLE)
387     {
388       win32_gc->pen_style &= ~(PS_ENDCAP_MASK);
389       switch (values->cap_style)
390         {
391         case GDK_CAP_NOT_LAST:  /* ??? */
392         case GDK_CAP_BUTT:
393           win32_gc->pen_style |= PS_ENDCAP_FLAT;
394           break;
395         case GDK_CAP_ROUND:
396           win32_gc->pen_style |= PS_ENDCAP_ROUND;
397           break;
398         case GDK_CAP_PROJECTING:
399           win32_gc->pen_style |= PS_ENDCAP_SQUARE;
400           break;
401         }
402       GDK_NOTE (GC, (g_print ("%sps|=PS_ENDCAP_%s", s, _gdk_win32_psendcap_to_string (win32_gc->pen_style)),
403                      s = ","));
404       win32_gc->values_mask |= GDK_GC_CAP_STYLE;
405     }
406
407   if (mask & GDK_GC_JOIN_STYLE)
408     {
409       win32_gc->pen_style &= ~(PS_JOIN_MASK);
410       switch (values->join_style)
411         {
412         case GDK_JOIN_MITER:
413           win32_gc->pen_style |= PS_JOIN_MITER;
414           break;
415         case GDK_JOIN_ROUND:
416           win32_gc->pen_style |= PS_JOIN_ROUND;
417           break;
418         case GDK_JOIN_BEVEL:
419           win32_gc->pen_style |= PS_JOIN_BEVEL;
420           break;
421         }
422       GDK_NOTE (GC, (g_print ("%sps|=PS_JOIN_%s", s, _gdk_win32_psjoin_to_string (win32_gc->pen_style)),
423                      s = ","));
424       win32_gc->values_mask |= GDK_GC_JOIN_STYLE;
425     }
426   GDK_NOTE (GC, g_print ("} mask=(%s)", _gdk_win32_gcvalues_mask_to_string (win32_gc->values_mask)));
427 }
428
429 GdkGC*
430 _gdk_win32_gc_new (GdkDrawable    *drawable,
431                    GdkGCValues    *values,
432                    GdkGCValuesMask mask)
433 {
434   GdkGC *gc;
435   GdkGCWin32 *win32_gc;
436
437   /* NOTICE that the drawable here has to be the impl drawable,
438    * not the publically-visible drawables.
439    */
440   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable), NULL);
441
442   gc = g_object_new (_gdk_gc_win32_get_type (), NULL);
443   win32_gc = GDK_GC_WIN32 (gc);
444
445   win32_gc->hcliprgn = NULL;
446
447   /* Use the same default values as X11 does, even if they don't make
448    * sense per se. But apps always set fg and bg anyway.
449    */
450   win32_gc->foreground = 0;
451   win32_gc->background = 1;
452   win32_gc->font = NULL;
453   win32_gc->rop2 = R2_COPYPEN;
454   win32_gc->fill_style = GDK_SOLID;
455   win32_gc->tile = NULL;
456   win32_gc->stipple = NULL;
457   win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_MITER;
458   win32_gc->pen_width = 0;
459   win32_gc->pen_dashes = NULL;
460   win32_gc->pen_num_dashes = 0;
461
462   win32_gc->values_mask = GDK_GC_FUNCTION | GDK_GC_FILL;
463
464   GDK_NOTE (GC, g_print ("_gdk_win32_gc_new: %p: ", win32_gc));
465   gdk_win32_gc_values_to_win32values (values, mask, win32_gc);
466   GDK_NOTE (GC, g_print ("\n"));
467
468   win32_gc->hdc = NULL;
469   win32_gc->hwnd = NULL;
470
471   return gc;
472 }
473
474 static void
475 gdk_win32_gc_get_values (GdkGC       *gc,
476                          GdkGCValues *values)
477 {
478   GdkGCWin32 *win32_gc = GDK_GC_WIN32 (gc);
479
480   values->foreground.pixel = win32_gc->foreground;
481   values->background.pixel = win32_gc->background;
482   values->font = win32_gc->font;
483
484   switch (win32_gc->rop2)
485     {
486     case R2_COPYPEN:
487       values->function = GDK_COPY; break;
488     case R2_NOT:
489       values->function = GDK_INVERT; break;
490     case R2_XORPEN:
491       values->function = GDK_XOR; break;
492     case R2_BLACK:
493       values->function = GDK_CLEAR; break;
494     case R2_MASKPEN:
495       values->function = GDK_AND; break;
496     case R2_MASKPENNOT:
497       values->function = GDK_AND_REVERSE; break;
498     case R2_MASKNOTPEN:
499       values->function = GDK_AND_INVERT; break;
500     case R2_NOP:
501       values->function = GDK_NOOP; break;
502     case R2_MERGEPEN:
503       values->function = GDK_OR; break;
504     case R2_NOTXORPEN:
505       values->function = GDK_EQUIV; break;
506     case R2_MERGEPENNOT:
507       values->function = GDK_OR_REVERSE; break;
508     case R2_NOTCOPYPEN:
509       values->function = GDK_COPY_INVERT; break;
510     case R2_MERGENOTPEN:
511       values->function = GDK_OR_INVERT; break;
512     case R2_NOTMASKPEN:
513       values->function = GDK_NAND; break;
514     case R2_NOTMERGEPEN:
515       values->function = GDK_NOR; break;
516     case R2_WHITE:
517       values->function = GDK_SET; break;
518     }
519
520   values->fill = win32_gc->fill_style;
521
522   values->tile = win32_gc->tile;
523   values->stipple = win32_gc->stipple;
524
525   /* Also the X11 backend always returns a NULL clip_mask */
526   values->clip_mask = NULL;
527
528   values->subwindow_mode = win32_gc->subwindow_mode;
529   values->ts_x_origin = win32_gc->parent_instance.ts_x_origin;
530   values->ts_y_origin = win32_gc->parent_instance.ts_y_origin;
531   values->clip_x_origin = win32_gc->parent_instance.clip_x_origin;
532   values->clip_y_origin = win32_gc->parent_instance.clip_y_origin;
533   values->graphics_exposures = win32_gc->graphics_exposures;
534   values->line_width = win32_gc->pen_width;
535   
536   if (win32_gc->pen_style & PS_SOLID)
537     values->line_style = GDK_LINE_SOLID;
538   else if (win32_gc->pen_style & PS_DASH)
539     values->line_style = GDK_LINE_ON_OFF_DASH;
540   else
541     values->line_style = GDK_LINE_SOLID;
542
543   /* PS_ENDCAP_ROUND is zero */
544   if (win32_gc->pen_style & PS_ENDCAP_FLAT)
545     values->cap_style = GDK_CAP_BUTT;
546   else if (win32_gc->pen_style & PS_ENDCAP_SQUARE)
547     values->cap_style = GDK_CAP_PROJECTING;
548   else
549     values->cap_style = GDK_CAP_ROUND;
550     
551   /* PS_JOIN_ROUND is zero */
552   if (win32_gc->pen_style & PS_JOIN_MITER)
553     values->join_style = GDK_JOIN_MITER;
554   else if (win32_gc->pen_style & PS_JOIN_BEVEL)
555     values->join_style = GDK_JOIN_BEVEL;
556   else
557     values->join_style = GDK_JOIN_ROUND;
558 }
559
560 static void
561 gdk_win32_gc_set_values (GdkGC           *gc,
562                          GdkGCValues     *values,
563                          GdkGCValuesMask  mask)
564 {
565   g_return_if_fail (GDK_IS_GC (gc));
566
567   GDK_NOTE (GC, g_print ("gdk_win32_gc_set_values: %p: ", GDK_GC_WIN32 (gc)));
568   gdk_win32_gc_values_to_win32values (values, mask, GDK_GC_WIN32 (gc));
569   GDK_NOTE (GC, g_print ("\n"));
570 }
571
572 static void
573 gdk_win32_gc_set_dashes (GdkGC *gc,
574                          gint   dash_offset,
575                          gint8  dash_list[],
576                          gint   n)
577 {
578   GdkGCWin32 *win32_gc;
579   int i;
580
581   g_return_if_fail (GDK_IS_GC (gc));
582   g_return_if_fail (dash_list != NULL);
583
584   win32_gc = GDK_GC_WIN32 (gc);
585
586   /* mark as set, see gdk_win32_gc_values_to_win32values () for the reason */
587   win32_gc->values_mask |= GDK_GC_LINE_STYLE;
588
589   win32_gc->pen_style &= ~(PS_STYLE_MASK);
590
591   win32_gc->pen_style |= (PS_GEOMETRIC | PS_USERSTYLE);
592   win32_gc->pen_num_dashes = n;
593   win32_gc->pen_dashes = g_new (DWORD, n);
594   for (i = 0; i < n; i++)
595     win32_gc->pen_dashes[i] = dash_list[i];
596 }
597
598 void
599 gdk_gc_set_clip_rectangle (GdkGC        *gc,
600                            GdkRectangle *rectangle)
601 {
602   GdkGCWin32 *win32_gc;
603
604   g_return_if_fail (GDK_IS_GC (gc));
605
606   win32_gc = GDK_GC_WIN32 (gc);
607
608   if (win32_gc->hcliprgn)
609     DeleteObject (win32_gc->hcliprgn);
610
611   if (rectangle)
612     {
613       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_rectangle: %p: %s\n",
614                              win32_gc,
615                              _gdk_win32_gdkrectangle_to_string (rectangle)));
616       win32_gc->hcliprgn = CreateRectRgn (rectangle->x, rectangle->y,
617                                           rectangle->x + rectangle->width,
618                                           rectangle->y + rectangle->height);
619       win32_gc->values_mask |= GDK_GC_CLIP_MASK;
620     }
621   else
622     {
623       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_rectangle: NULL\n"));
624
625       win32_gc->hcliprgn = NULL;
626       win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
627     }
628
629   gc->clip_x_origin = 0;
630   gc->clip_y_origin = 0;
631   
632   win32_gc->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
633
634
635 void
636 gdk_gc_set_clip_region (GdkGC     *gc,
637                         GdkRegion *region)
638 {
639   GdkGCWin32 *win32_gc;
640
641   g_return_if_fail (GDK_IS_GC (gc));
642
643   win32_gc = GDK_GC_WIN32 (gc);
644
645   if (win32_gc->hcliprgn)
646     DeleteObject (win32_gc->hcliprgn);
647
648   if (region)
649     {
650       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_region: %p: %s\n",
651                              win32_gc,
652                              _gdk_win32_gdkregion_to_string (region)));
653
654       win32_gc->hcliprgn = _gdk_win32_gdkregion_to_hrgn (region, 0, 0);
655       win32_gc->values_mask |= GDK_GC_CLIP_MASK;
656     }
657   else
658     {
659       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_region: NULL\n"));
660
661       win32_gc->hcliprgn = NULL;
662       win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
663     }
664
665   gc->clip_x_origin = 0;
666   gc->clip_y_origin = 0;
667   
668   win32_gc->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
669 }
670
671 void
672 gdk_gc_copy (GdkGC *dst_gc,
673              GdkGC *src_gc)
674 {
675   GdkGCWin32 *dst_win32_gc;
676   GdkGCWin32 *src_win32_gc;
677
678   g_return_if_fail (GDK_IS_GC_WIN32 (dst_gc));
679   g_return_if_fail (GDK_IS_GC_WIN32 (src_gc));
680   
681   dst_win32_gc = GDK_GC_WIN32 (dst_gc);
682   src_win32_gc = GDK_GC_WIN32 (src_gc);
683
684   GDK_NOTE (GC, g_print ("gdk_gc_copy: %p := %p\n", dst_win32_gc, src_win32_gc));
685
686   if (dst_gc->colormap)
687     g_object_unref (G_OBJECT (dst_gc->colormap));
688
689   if (dst_win32_gc->hcliprgn != NULL)
690     DeleteObject (dst_win32_gc->hcliprgn);
691
692   if (dst_win32_gc->font != NULL)
693     gdk_font_unref (dst_win32_gc->font);
694
695   if (dst_win32_gc->tile != NULL)
696     gdk_drawable_unref (dst_win32_gc->tile);
697
698   if (dst_win32_gc->stipple != NULL)
699     gdk_drawable_unref (dst_win32_gc->stipple);
700
701   if (dst_win32_gc->pen_dashes)
702     g_free (dst_win32_gc->pen_dashes);
703   
704   *dst_win32_gc = *src_win32_gc;
705   dst_win32_gc->hdc = NULL;
706
707   if (dst_gc->colormap)
708     g_object_ref (G_OBJECT (dst_gc->colormap));
709
710   if (dst_win32_gc->hcliprgn)
711     {
712       /* create a new region, to copy to */
713       dst_win32_gc->hcliprgn = CreateRectRgn (0,0,1,1);
714       /* overwrite from source */
715       CombineRgn (dst_win32_gc->hcliprgn, src_win32_gc->hcliprgn,
716                   NULL, RGN_COPY);
717     }
718
719   if (dst_win32_gc->font != NULL)
720     gdk_font_ref (dst_win32_gc->font);
721
722   if (dst_win32_gc->tile != NULL)
723     gdk_drawable_ref (dst_win32_gc->tile);
724
725   if (dst_win32_gc->stipple != NULL)
726     gdk_drawable_ref (dst_win32_gc->stipple);
727
728   if (dst_win32_gc->pen_dashes)
729     dst_win32_gc->pen_dashes = g_memdup (src_win32_gc->pen_dashes, 
730                                          sizeof (DWORD) * src_win32_gc->pen_num_dashes);
731 }
732
733 static guint bitmask[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
734
735 COLORREF
736 _gdk_win32_colormap_color (GdkColormap *colormap,
737                            gulong       pixel)
738 {
739   const GdkVisual *visual;
740   GdkColormapPrivateWin32 *colormap_private;
741   guchar r, g, b;
742
743   if (colormap == NULL)
744     return DIBINDEX (pixel & 1);
745
746   colormap_private = GDK_WIN32_COLORMAP_DATA (colormap);
747
748   g_assert (colormap_private != NULL);
749
750   visual = colormap->visual;
751   switch (visual->type)
752     {
753     case GDK_VISUAL_GRAYSCALE:
754     case GDK_VISUAL_PSEUDO_COLOR:
755     case GDK_VISUAL_STATIC_COLOR:
756       return PALETTEINDEX (pixel);
757
758     case GDK_VISUAL_TRUE_COLOR:
759       r = (pixel & visual->red_mask) >> visual->red_shift;
760       r = (r * 255) / bitmask[visual->red_prec];
761       g = (pixel & visual->green_mask) >> visual->green_shift;
762       g = (g * 255) / bitmask[visual->green_prec];
763       b = (pixel & visual->blue_mask) >> visual->blue_shift;
764       b = (b * 255) / bitmask[visual->blue_prec];
765       return RGB (r, g, b);
766
767     default:
768       g_assert_not_reached ();
769       return 0;
770     }
771 }
772
773 static COLORREF
774 predraw_set_foreground (GdkGC       *gc,
775                         GdkColormap *colormap,
776                         gboolean    *ok)
777 {
778   COLORREF fg;
779   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
780   GdkColormapPrivateWin32 *colormap_private;
781   gint k;
782
783   if (colormap &&
784       (colormap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
785        colormap->visual->type == GDK_VISUAL_STATIC_COLOR))
786     {
787       colormap_private = GDK_WIN32_COLORMAP_DATA (colormap);
788
789       g_assert (colormap_private != NULL);
790
791       if (!(win32_gc->holdpal = SelectPalette (win32_gc->hdc, colormap_private->hpal, FALSE)))
792         WIN32_GDI_FAILED ("SelectPalette"), *ok = FALSE;
793       else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR)
794         WIN32_GDI_FAILED ("RealizePalette"), *ok = FALSE;
795       else if (k > 0)
796         GDK_NOTE (COLORMAP, g_print ("predraw_set_foreground: realized %p: %d colors\n",
797                                      colormap_private->hpal, k));
798     }
799
800   fg = _gdk_win32_colormap_color (colormap, win32_gc->foreground);
801
802   GDK_NOTE (GC, g_print ("predraw_set_foreground: fg=%06lx\n", fg));
803   return fg;
804 }
805
806 /**
807  * gdk_win32_hdc_get:
808  * @drawable: destination #GdkDrawable
809  * @gc: #GdkGC to use for drawing on @drawable
810  * @usage: mask indicating what properties needs to be set up
811  *
812  * Allocates a Windows device context handle (HDC) for drawing into
813  * @drawable, and sets it up appropriately according to @usage.
814  *
815  * Each #GdkGC can at one time have only one HDC associated with it.
816  *
817  * The following flags in @mask are handled:
818  *
819  * If %GDK_GC_FOREGROUND is set in @mask, a solid brush of the
820  * foreground color in @gc is selected into the HDC. The text color of
821  * the HDC is also set. If the @drawable has a palette (256-color
822  * mode), the palette is selected and realized.
823  *
824  * If any of the line attribute flags (%GDK_GC_LINE_WIDTH,
825  * %GDK_GC_LINE_STYLE, %GDK_GC_CAP_STYLE and %GDK_GC_JOIN_STYLE) is
826  * set in @mask, a solid pen of the foreground color and appropriate
827  * width and stule is created and selected into the HDC. Note that the
828  * dash properties are not completely implemented.
829  *
830  * If the %GDK_GC_FONT flag is set, the background mix mode is set to
831  * %TRANSPARENT. and the text alignment is set to
832  * %TA_BASELINE|%TA_LEFT. Note that no font gets selected into the HDC
833  * by this function.
834  *
835  * Some things are done regardless of @mask: If the function in @gc is
836  * any other than %GDK_COPY, the raster operation of the HDC is
837  * set. If @gc has a clip mask, the clip region of the HDC is set.
838  *
839  * Note that the fill style, tile, stipple, and tile and stipple
840  * origins in the @gc are ignored by this function. (In general, tiles
841  * and stipples can't be implemented directly on Win32; you need to do
842  * multiple pass drawing and blitting to implement tiles or
843  * stipples. GDK does just that when you call the GDK drawing
844  * functions with a GC that asks for tiles or stipples.)
845  *
846  * When the HDC is no longer used, it should be released by calling
847  * <function>gdk_win32_hdc_release()</function> with the same
848  * parameters.
849  *
850  * If you modify the HDC by calling <function>SelectObject</function>
851  * you should undo those modifications before calling
852  * <function>gdk_win32_hdc_release()</function>.
853  *
854  * Return value: The HDC.
855  **/
856 HDC
857 gdk_win32_hdc_get (GdkDrawable    *drawable,
858                    GdkGC          *gc,
859                    GdkGCValuesMask usage)
860 {
861   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
862   GdkDrawableImplWin32 *impl = NULL;
863   gboolean ok = TRUE;
864   COLORREF fg = RGB (0, 0, 0);
865   LOGBRUSH logbrush;
866   HPEN hpen;
867   HBRUSH hbr;
868
869   g_assert (win32_gc->hdc == NULL);
870
871   if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable))
872     impl = GDK_DRAWABLE_IMPL_WIN32(drawable);
873   else if (GDK_IS_WINDOW (drawable))
874     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_WINDOW_OBJECT (drawable))->impl);
875   else if (GDK_IS_PIXMAP (drawable))
876     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_PIXMAP_OBJECT (drawable))->impl);
877   else
878     g_assert_not_reached ();
879
880   win32_gc->hwnd = impl->handle;
881
882   if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
883     {
884       if ((win32_gc->hdc = CreateCompatibleDC (NULL)) == NULL)
885         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
886
887       if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0)
888         WIN32_GDI_FAILED ("SaveDC"), ok = FALSE;
889       
890       if (ok && SelectObject (win32_gc->hdc, win32_gc->hwnd) == NULL)
891         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
892     }
893   else
894     {
895       if ((win32_gc->hdc = GetDC (win32_gc->hwnd)) == NULL)
896         WIN32_GDI_FAILED ("GetDC");
897       
898       if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0)
899         WIN32_GDI_FAILED ("SaveDC");
900     }
901   
902   if (ok && (usage & GDK_GC_FOREGROUND))
903     {
904       fg = predraw_set_foreground (gc, impl->colormap, &ok);
905       if (ok && (hbr = CreateSolidBrush (fg)) == NULL)
906         WIN32_GDI_FAILED ("CreateSolidBrush"), ok = FALSE;
907
908       if (ok && SelectObject (win32_gc->hdc, hbr) == NULL)
909         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
910
911       if (ok && SetTextColor (win32_gc->hdc, fg) == CLR_INVALID)
912         WIN32_GDI_FAILED ("SetTextColor"), ok = FALSE;
913     }
914
915   if (ok && (usage & LINE_ATTRIBUTES))
916     {
917       /* Create and select pen */
918       logbrush.lbStyle = BS_SOLID;
919       logbrush.lbColor = fg;
920       logbrush.lbHatch = 0;
921       
922       if (win32_gc->pen_num_dashes > 0 && !IS_WIN_NT ())
923         {
924           /* The Win9x GDI is rather limited so we either draw dashed
925            * lines ourselves (only horizontal and vertical) or let them be
926            * drawn solid to avoid implementing a whole line renderer.
927            */
928           if ((hpen = ExtCreatePen (
929                                     (win32_gc->pen_style & ~(PS_STYLE_MASK)) | PS_SOLID,
930                                     MAX (win32_gc->pen_width, 1),
931                                     &logbrush, 
932                                     0, NULL)) == NULL)
933             WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
934         }
935       else
936         {
937           if ((hpen = ExtCreatePen (win32_gc->pen_style,
938                                     MAX (win32_gc->pen_width, 1),
939                                     &logbrush, 
940                                     win32_gc->pen_num_dashes,
941                                     win32_gc->pen_dashes)) == NULL)
942             WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
943         }
944       
945       if (ok && SelectObject (win32_gc->hdc, hpen) == NULL)
946         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
947     }
948
949   if (ok && (usage & GDK_GC_FONT))
950     {
951       if (SetBkMode (win32_gc->hdc, TRANSPARENT) == 0)
952         WIN32_GDI_FAILED ("SetBkMode"), ok = FALSE;
953   
954       if (ok && SetTextAlign (win32_gc->hdc, TA_BASELINE|TA_LEFT|TA_NOUPDATECP) == GDI_ERROR)
955         WIN32_GDI_FAILED ("SetTextAlign"), ok = FALSE;
956     }
957   
958   if (ok && win32_gc->rop2 != R2_COPYPEN)
959     if (SetROP2 (win32_gc->hdc, win32_gc->rop2) == 0)
960       WIN32_GDI_FAILED ("SetROP2"), ok = FALSE;
961
962   if (ok &&
963       (win32_gc->values_mask & GDK_GC_CLIP_MASK) &&
964       win32_gc->hcliprgn != NULL)
965     {
966       if (SelectClipRgn (win32_gc->hdc, win32_gc->hcliprgn) == ERROR)
967         WIN32_API_FAILED ("SelectClipRgn"), ok = FALSE;
968
969       if (ok && win32_gc->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN) &&
970           OffsetClipRgn (win32_gc->hdc,
971             win32_gc->values_mask & GDK_GC_CLIP_X_ORIGIN ? gc->clip_x_origin : 0,
972             win32_gc->values_mask & GDK_GC_CLIP_Y_ORIGIN ? gc->clip_y_origin : 0) == ERROR)
973         WIN32_API_FAILED ("OffsetClipRgn"), ok = FALSE;
974     }
975
976   GDK_NOTE (GC, (g_print ("gdk_win32_hdc_get: %p (%s): ",
977                           win32_gc, _gdk_win32_gcvalues_mask_to_string (usage)),
978                  _gdk_win32_print_dc (win32_gc->hdc)));
979
980   return win32_gc->hdc;
981 }
982
983 /**
984  * gdk_win32_hdc_release:
985  * @drawable: destination #GdkDrawable
986  * @gc: #GdkGC to use for drawing on @drawable
987  * @usage: mask indicating what properties were set up
988  *
989  * This function deallocates the Windows device context allocated by
990  * <funcion>gdk_win32_hdc_get()</function>. It should be called with
991  * the same parameters.
992  **/
993 void
994 gdk_win32_hdc_release (GdkDrawable    *drawable,
995                        GdkGC          *gc,
996                        GdkGCValuesMask usage)
997 {
998   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
999   GdkDrawableImplWin32 *impl = NULL;
1000   HGDIOBJ hpen = NULL;
1001   HGDIOBJ hbr = NULL;
1002
1003   GDK_NOTE (GC, g_print ("gdk_win32_hdc_release: %p: %p (%s)\n",
1004                          win32_gc, win32_gc->hdc,
1005                          _gdk_win32_gcvalues_mask_to_string (usage)));
1006
1007   if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable))
1008     impl = GDK_DRAWABLE_IMPL_WIN32(drawable);
1009   else if (GDK_IS_WINDOW (drawable))
1010     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_WINDOW_OBJECT (drawable))->impl);
1011   else if (GDK_IS_PIXMAP (drawable))
1012     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_PIXMAP_OBJECT (drawable))->impl);
1013   else
1014     g_assert_not_reached ();
1015
1016   if (win32_gc->holdpal != NULL)
1017     {
1018       gint k;
1019       
1020       if (!SelectPalette (win32_gc->hdc, win32_gc->holdpal, FALSE))
1021         WIN32_GDI_FAILED ("SelectPalette");
1022       else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR)
1023         WIN32_GDI_FAILED ("RealizePalette");
1024       else if (k > 0)
1025         GDK_NOTE (COLORMAP, g_print ("gdk_win32_hdc_release: realized %p: %d colors\n",
1026                                      win32_gc->holdpal, k));
1027       win32_gc->holdpal = NULL;
1028     }
1029
1030   if (usage & LINE_ATTRIBUTES)
1031     if ((hpen = GetCurrentObject (win32_gc->hdc, OBJ_PEN)) == NULL)
1032       WIN32_GDI_FAILED ("GetCurrentObject");
1033   
1034   if (usage & GDK_GC_FOREGROUND)
1035     if ((hbr = GetCurrentObject (win32_gc->hdc, OBJ_BRUSH)) == NULL)
1036       WIN32_GDI_FAILED ("GetCurrentObject");
1037
1038   GDI_CALL (RestoreDC, (win32_gc->hdc, win32_gc->saved_dc));
1039
1040   if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1041     GDI_CALL (DeleteDC, (win32_gc->hdc));
1042   else
1043     GDI_CALL (ReleaseDC, (win32_gc->hwnd, win32_gc->hdc));
1044
1045   if (hpen != NULL)
1046     GDI_CALL (DeleteObject, (hpen));
1047   
1048   if (hbr != NULL)
1049     GDI_CALL (DeleteObject, (hbr));
1050
1051   win32_gc->hdc = NULL;
1052 }
1053
1054 /* This function originally from Jean-Edouard Lachand-Robert, and
1055  * available at www.codeguru.com. Simplified for our needs, not sure
1056  * how much of the original code left any longer. Now handles just
1057  * one-bit deep bitmaps (in Window parlance, ie those that GDK calls
1058  * bitmaps (and not pixmaps), with zero pixels being transparent.
1059  */
1060
1061 /* _gdk_win32_bitmap_to_hrgn : Create a region from the
1062  * "non-transparent" pixels of a bitmap.
1063  */
1064
1065 HRGN
1066 _gdk_win32_bitmap_to_hrgn (GdkPixmap *pixmap)
1067 {
1068   HRGN hRgn = NULL;
1069   HRGN h;
1070   DWORD maxRects;
1071   RGNDATA *pData;
1072   GdkImage *image;
1073   guchar *p;
1074   gint x, y;
1075
1076   image = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl)->image;
1077   g_assert (image->depth == 1);
1078
1079   /* For better performances, we will use the ExtCreateRegion()
1080    * function to create the region. This function take a RGNDATA
1081    * structure on entry. We will add rectangles by amount of
1082    * ALLOC_UNIT number in this structure.
1083    */
1084   #define ALLOC_UNIT  100
1085   maxRects = ALLOC_UNIT;
1086
1087   pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
1088   pData->rdh.dwSize = sizeof (RGNDATAHEADER);
1089   pData->rdh.iType = RDH_RECTANGLES;
1090   pData->rdh.nCount = pData->rdh.nRgnSize = 0;
1091   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1092
1093   for (y = 0; y < image->height; y++)
1094     {
1095       /* Scan each bitmap row from left to right*/
1096       p = (guchar *) image->mem + y * image->bpl;
1097       for (x = 0; x < image->width; x++)
1098         {
1099           /* Search for a continuous range of "non transparent pixels"*/
1100           gint x0 = x;
1101           while (x < image->width)
1102             {
1103               if ((((p[x/8])>>(7-(x%8)))&1) == 0)
1104                 /* This pixel is "transparent"*/
1105                 break;
1106               x++;
1107             }
1108           
1109           if (x > x0)
1110             {
1111               RECT *pr;
1112               /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
1113                * in the region
1114                */
1115               if (pData->rdh.nCount >= maxRects)
1116                 {
1117                   maxRects += ALLOC_UNIT;
1118                   pData = g_realloc (pData, sizeof(RGNDATAHEADER)
1119                                      + (sizeof(RECT) * maxRects));
1120                 }
1121               pr = (RECT *) &pData->Buffer;
1122               SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
1123               if (x0 < pData->rdh.rcBound.left)
1124                 pData->rdh.rcBound.left = x0;
1125               if (y < pData->rdh.rcBound.top)
1126                 pData->rdh.rcBound.top = y;
1127               if (x > pData->rdh.rcBound.right)
1128                 pData->rdh.rcBound.right = x;
1129               if (y+1 > pData->rdh.rcBound.bottom)
1130                 pData->rdh.rcBound.bottom = y+1;
1131               pData->rdh.nCount++;
1132               
1133               /* On Windows98, ExtCreateRegion() may fail if the
1134                * number of rectangles is too large (ie: >
1135                * 4000). Therefore, we have to create the region by
1136                * multiple steps.
1137                */
1138               if (pData->rdh.nCount == 2000)
1139                 {
1140                   HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
1141                   if (hRgn)
1142                     {
1143                       CombineRgn(hRgn, hRgn, h, RGN_OR);
1144                       DeleteObject(h);
1145                     }
1146                   else
1147                     hRgn = h;
1148                   pData->rdh.nCount = 0;
1149                   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1150                 }
1151             }
1152         }
1153     }
1154   
1155   /* Create or extend the region with the remaining rectangles*/
1156   h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
1157                        + (sizeof (RECT) * maxRects), pData);
1158   if (hRgn)
1159     {
1160       CombineRgn (hRgn, hRgn, h, RGN_OR);
1161       DeleteObject (h);
1162     }
1163   else
1164     hRgn = h;
1165
1166   /* Clean up*/
1167   g_free (pData);
1168
1169   return hRgn;
1170 }
1171
1172 HRGN
1173 _gdk_win32_gdkregion_to_hrgn (GdkRegion *region,
1174                               gint       x_origin,
1175                               gint       y_origin)
1176 {
1177   HRGN hrgn;
1178   RGNDATA *rgndata;
1179   RECT *rect;
1180   GdkRegionBox *boxes = region->rects;
1181   guint nbytes =
1182     sizeof (RGNDATAHEADER) + (sizeof (RECT) * region->numRects);
1183   int i;
1184
1185   rgndata = g_malloc (nbytes);
1186   rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
1187   rgndata->rdh.iType = RDH_RECTANGLES;
1188   rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
1189   SetRect (&rgndata->rdh.rcBound,
1190            G_MAXSHORT, G_MAXSHORT, G_MINSHORT, G_MINSHORT);
1191
1192   for (i = 0; i < region->numRects; i++)
1193     {
1194       rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
1195
1196       rect->left = CLAMP (boxes[i].x1 + x_origin,
1197                           G_MINSHORT, G_MAXSHORT);
1198       rect->right = CLAMP (boxes[i].x2 + x_origin,
1199                            G_MINSHORT, G_MAXSHORT);
1200       rect->top = CLAMP (boxes[i].y1 + y_origin,
1201                          G_MINSHORT, G_MAXSHORT);
1202       rect->bottom = CLAMP (boxes[i].y2 + y_origin,
1203                             G_MINSHORT, G_MAXSHORT);
1204
1205       if (rect->left < rgndata->rdh.rcBound.left)
1206         rgndata->rdh.rcBound.left = rect->left;
1207       if (rect->right > rgndata->rdh.rcBound.right)
1208         rgndata->rdh.rcBound.right = rect->right;
1209       if (rect->top < rgndata->rdh.rcBound.top)
1210         rgndata->rdh.rcBound.top = rect->top;
1211       if (rect->bottom > rgndata->rdh.rcBound.bottom)
1212         rgndata->rdh.rcBound.bottom = rect->bottom;
1213     }
1214   if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
1215     WIN32_API_FAILED ("ExtCreateRegion");
1216
1217   g_free (rgndata);
1218
1219   return (hrgn);
1220 }