]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgc-win32.c
Intermediate commit.
[~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  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <string.h>
30
31 #include "gdkgc.h"
32 #include "gdkfont.h"
33 #include "gdkpixmap.h"
34 #include "gdkprivate.h"
35 #include "gdkwin32.h"
36
37 static void gdk_win32_gc_destroy    (GdkGC           *gc);
38 static void gdk_win32_gc_get_values (GdkGC           *gc,
39                                      GdkGCValues     *values);
40 static void gdk_win32_gc_set_values (GdkGC           *gc,
41                                      GdkGCValues     *values,
42                                      GdkGCValuesMask  values_mask);
43 static void gdk_win32_gc_set_dashes (GdkGC           *gc,
44                                      gint             dash_offset,
45                                      gchar            dash_list[],
46                                      gint             n);
47
48 static GdkGCClass gdk_win32_gc_class = {
49   gdk_win32_gc_destroy,
50   gdk_win32_gc_get_values,
51   gdk_win32_gc_set_values,
52   gdk_win32_gc_set_dashes
53 };
54
55 GdkGC*
56 _gdk_win32_gc_new (GdkDrawable    *drawable,
57                    GdkGCValues    *values,
58                    GdkGCValuesMask values_mask)
59 {
60   GdkGC *gc;
61   GdkGCPrivate *private;
62   GdkGCWin32Data *data;
63   static GdkColor black;
64   static GdkColor white;
65   static gboolean beenhere = FALSE;
66
67   if (!beenhere)
68     {
69       gdk_color_black (gdk_colormap_get_system (), &black);
70       gdk_color_white (gdk_colormap_get_system (), &white);
71       beenhere = TRUE;
72     }
73
74   gc = gdk_gc_alloc ();
75   private = (GdkGCPrivate *)gc;
76
77   private->klass = &gdk_win32_gc_class;
78   private->klass_data = data = g_new (GdkGCWin32Data, 1);
79     
80   data->rop2 = R2_COPYPEN;
81   data->fill_style = GDK_SOLID;
82   data->values_mask = values_mask;
83   data->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL;
84
85   GDK_NOTE (MISC, g_print ("_gdk_win32_gc_new: {"));
86
87   if (values_mask & GDK_GC_FOREGROUND)
88     {
89       data->foreground = values->foreground;
90     }
91   else
92     data->foreground = black;
93   
94   if (values_mask & GDK_GC_BACKGROUND)
95     {
96       data->background = values->background;
97     }
98   else
99     data->background = white;
100
101   if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT
102                                       || values->font->type == GDK_FONT_FONTSET))
103     {
104       data->font = values->font;
105       gdk_font_ref (data->font);
106       GDK_NOTE (MISC, g_print (" font"));
107     }
108   else
109     data->font = NULL;
110
111   if (values_mask & GDK_GC_FUNCTION)
112     {
113       switch (values->function)
114         {
115         case GDK_COPY:
116           data->rop2 = R2_COPYPEN; break;
117         case GDK_INVERT:
118           data->rop2 = R2_NOT; break;
119         case GDK_XOR:
120           data->rop2 = R2_XORPEN; break;
121         case GDK_CLEAR:
122           data->rop2 = R2_BLACK; break;
123         case GDK_AND:
124           data->rop2 = R2_MASKPEN; break;
125         case GDK_AND_REVERSE:
126           data->rop2 = R2_MASKPENNOT; break;
127         case GDK_AND_INVERT:
128           data->rop2 = R2_MASKNOTPEN; break;
129         case GDK_NOOP:
130           data->rop2 = R2_NOP; break;
131         case GDK_OR:
132           data->rop2 = R2_MERGEPEN; break;
133         case GDK_EQUIV:
134           data->rop2 = R2_NOTXORPEN; break;
135         case GDK_OR_REVERSE:
136           data->rop2 = R2_MERGEPENNOT; break;
137         case GDK_COPY_INVERT:
138           data->rop2 = R2_NOTCOPYPEN; break;
139         case GDK_OR_INVERT:
140           data->rop2 = R2_MERGENOTPEN; break;
141         case GDK_NAND:
142           data->rop2 = R2_NOTMASKPEN; break;
143         case GDK_SET:
144           data->rop2 = R2_WHITE; break;
145         }
146       GDK_NOTE (MISC, g_print (" function=%d", data->rop2));
147     }
148
149   if (values_mask & GDK_GC_FILL)
150     {
151       data->fill_style = values->fill;
152       GDK_NOTE (MISC, g_print (" fill=%d", data->fill_style));
153     }
154
155   if (values_mask & GDK_GC_TILE)
156     {
157       data->tile = values->tile;
158       gdk_pixmap_ref (data->tile);
159       GDK_NOTE (MISC, g_print (" tile=%#x", GDK_DRAWABLE_XID (data->tile)));
160     }
161   else
162     data->tile = NULL;
163
164   if (values_mask & GDK_GC_STIPPLE)
165     {
166       data->stipple = values->stipple;
167       gdk_pixmap_ref (data->stipple);
168       GDK_NOTE (MISC, g_print (" stipple=%#x", GDK_DRAWABLE_XID (data->stipple)));
169     }
170   else
171     data->stipple = NULL;
172
173   if (values_mask & GDK_GC_CLIP_MASK)
174     {
175       data->clip_region =
176         BitmapToRegion ((HBITMAP) GDK_DRAWABLE_XID (values->clip_mask));
177       GDK_NOTE (MISC, g_print (" clip=%#x", data->clip_region));
178     }
179   else
180     data->clip_region = NULL;
181
182   if (values_mask & GDK_GC_SUBWINDOW)
183     {
184       data->subwindow_mode = values->subwindow_mode;
185       GDK_NOTE (MISC, g_print (" subw=%d", data->subwindow_mode));
186     }
187
188   if (values_mask & GDK_GC_TS_X_ORIGIN)
189     {
190       data->ts_x_origin = values->ts_x_origin;
191       GDK_NOTE (MISC, g_print (" ts_x=%d", data->ts_x_origin));
192     }
193
194   if (values_mask & GDK_GC_TS_Y_ORIGIN)
195     {
196       data->ts_y_origin = values->ts_y_origin;
197       GDK_NOTE (MISC, g_print (" ts_y=%d", data->ts_y_origin));
198     }
199
200   if (values_mask & GDK_GC_CLIP_X_ORIGIN)
201     {
202       data->clip_x_origin = values->clip_x_origin;
203       GDK_NOTE (MISC, g_print (" clip_x=%d", data->clip_x_origin));
204     }
205
206   if (values_mask & GDK_GC_CLIP_Y_ORIGIN)
207     {
208       data->clip_y_origin = values->clip_y_origin; 
209       GDK_NOTE (MISC, g_print (" clip_y=%d", data->clip_y_origin));
210    }
211  
212   if (values_mask & GDK_GC_EXPOSURES)
213     {
214       data->graphics_exposures = values->graphics_exposures;
215       GDK_NOTE (MISC, g_print (" exp=%d", data->graphics_exposures));
216     }
217
218   data->pen_style = PS_GEOMETRIC;
219   data->pen_width = 1;
220
221   if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE))
222     {
223       if (values_mask & GDK_GC_LINE_WIDTH)
224         {
225           data->pen_width = values->line_width;
226           GDK_NOTE (MISC, g_print (" pw=%d", data->pen_width));
227         }
228       if (values_mask & GDK_GC_LINE_STYLE)
229         {
230           switch (values->line_style)
231             {
232             case GDK_LINE_SOLID:
233               data->pen_style |= PS_SOLID; break;
234             case GDK_LINE_ON_OFF_DASH:
235             case GDK_LINE_DOUBLE_DASH: /* ??? */
236               data->pen_style |= PS_DASH; break;
237             }
238           GDK_NOTE (MISC, g_print (" ps=%#x", data->pen_style));
239         }
240     }
241
242   if (values_mask & GDK_GC_CAP_STYLE)
243     {
244       switch (values->cap_style)
245         {
246         case GDK_CAP_NOT_LAST:  /* ??? */
247         case GDK_CAP_BUTT:
248           data->pen_style |= PS_ENDCAP_FLAT;    break;
249         case GDK_CAP_ROUND:
250           data->pen_style |= PS_ENDCAP_ROUND; break;
251         case GDK_CAP_PROJECTING:
252           data->pen_style |= PS_ENDCAP_SQUARE; break;
253         }
254       GDK_NOTE (MISC, g_print (" ps=%#x", data->pen_style));
255     }
256
257   if (values_mask & GDK_GC_JOIN_STYLE)
258     {
259       switch (values->join_style)
260         {
261         case GDK_JOIN_MITER:
262           data->pen_style |= PS_JOIN_MITER;
263           break;
264         case GDK_JOIN_ROUND:
265           data->pen_style |= PS_JOIN_ROUND;
266           break;
267         case GDK_JOIN_BEVEL:
268           data->pen_style |= PS_JOIN_BEVEL;
269           break;
270         }
271       GDK_NOTE (MISC, g_print (" ps=%#x", data->pen_style));
272     }
273
274   data->hwnd = NULL;
275   data->xgc = NULL;
276
277   GDK_NOTE (MISC, g_print ("} = %p\n", gc));
278
279   return gc;
280 }
281
282 static void
283 gdk_win32_gc_destroy (GdkGC *gc)
284 {
285   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc);
286
287   if (data->values_mask & GDK_GC_FONT)
288     gdk_font_unref (data->font);
289   
290   if (data->values_mask & GDK_GC_TILE)
291     gdk_pixmap_unref (data->tile);
292   
293   if (data->values_mask & GDK_GC_STIPPLE)
294     gdk_pixmap_unref (data->stipple);
295   
296   if (data->values_mask & GDK_GC_CLIP_MASK)
297     DeleteObject (data->clip_region);
298
299   g_free (GDK_GC_WIN32DATA (gc));
300 }
301
302 static void
303 gdk_win32_gc_get_values (GdkGC       *gc,
304                          GdkGCValues *values)
305 {
306   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc);
307
308   values->foreground = data->foreground;
309   values->background = data->background;
310   values->font = data->font;
311
312   switch (data->rop2)
313     {
314     case R2_COPYPEN:
315       values->function = GDK_COPY; break;
316     case R2_NOT:
317       values->function = GDK_INVERT; break;
318     case R2_XORPEN:
319       values->function = GDK_XOR; break;
320     case R2_BLACK:
321       values->function = GDK_CLEAR; break;
322     case R2_MASKPEN:
323       values->function = GDK_AND; break;
324     case R2_MASKPENNOT:
325       values->function = GDK_AND_REVERSE; break;
326     case R2_MASKNOTPEN:
327       values->function = GDK_AND_INVERT; break;
328     case R2_NOP:
329       values->function = GDK_NOOP; break;
330     case R2_MERGEPEN:
331       values->function = GDK_OR; break;
332     case R2_NOTXORPEN:
333       values->function = GDK_EQUIV; break;
334     case R2_MERGEPENNOT:
335       values->function = GDK_OR_REVERSE; break;
336     case R2_NOTCOPYPEN:
337       values->function = GDK_COPY_INVERT; break;
338     case R2_MERGENOTPEN:
339       values->function = GDK_OR_INVERT; break;
340     case R2_NOTMASKPEN:
341       values->function = GDK_NAND; break;
342     case R2_WHITE:
343       values->function = GDK_SET; break;
344     }
345
346   values->fill = data->fill_style;
347
348   values->tile = data->tile;
349   values->stipple = data->stipple;
350   if (data->clip_region != NULL)
351     {
352       RECT rect;
353       HBRUSH hbr;
354       HDC hdc;
355       HGDIOBJ oldbitmap;
356       GdkPixmap *pixmap;
357
358       GetRgnBox (data->clip_region, &rect);
359       pixmap =
360         gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top,
361                         1);
362       hbr = GetStockObject (WHITE_BRUSH);
363       if ((hdc = CreateCompatibleDC (NULL)) == NULL)
364         g_warning ("gdk_gc_get_values: CreateCompatibleDC failed");
365       if ((oldbitmap =
366            SelectObject (hdc, GDK_DRAWABLE_XID (pixmap))) == NULL)
367         g_warning ("gdk_gc_get_values: SelectObject #1 failed");
368       hbr = GetStockObject (BLACK_BRUSH);
369       if (!FillRect (hdc, &rect, hbr))
370         g_warning ("gdk_gc_get_values: FillRect failed");
371       hbr = GetStockObject (WHITE_BRUSH);
372       if (!FillRgn (hdc, data->clip_region, hbr))
373         g_warning ("gdk_gc_get_values: FillRgn failed");
374       if (SelectObject (hdc, oldbitmap) == NULL)
375         g_warning ("gdk_gc_get_values: SelectObject #2 failed");
376       DeleteDC (hdc);
377       values->clip_mask = pixmap;
378     }
379   else
380     values->clip_mask = NULL;
381   values->subwindow_mode = data->subwindow_mode;
382   values->ts_x_origin = data->ts_x_origin;
383   values->ts_y_origin = data->ts_y_origin;
384   values->clip_x_origin = data->clip_x_origin;
385   values->clip_y_origin = data->clip_y_origin;
386   values->graphics_exposures = data->graphics_exposures;
387   values->line_width = data->pen_width;
388   
389   if (data->pen_style & PS_SOLID)
390     values->line_style = GDK_LINE_SOLID;
391   else if (data->pen_style & PS_DASH)
392     values->line_style = GDK_LINE_ON_OFF_DASH;
393   else
394     values->line_style = GDK_LINE_SOLID;
395
396   /* PS_ENDCAP_ROUND is zero */
397   if (data->pen_style & PS_ENDCAP_FLAT)
398     values->cap_style = GDK_CAP_BUTT;
399   else if (data->pen_style & PS_ENDCAP_SQUARE)
400     values->cap_style = GDK_CAP_PROJECTING;
401   else
402     values->cap_style = GDK_CAP_ROUND;
403     
404   /* PS_JOIN_ROUND is zero */
405   if (data->pen_style & PS_JOIN_MITER)
406     values->join_style = GDK_JOIN_MITER;
407   else if (data->pen_style & PS_JOIN_BEVEL)
408     values->join_style = GDK_JOIN_BEVEL;
409   else
410     values->join_style = GDK_JOIN_ROUND;
411 }
412
413 static void
414 gdk_win32_gc_set_values (GdkGC           *gc,
415                          GdkGCValues     *values,
416                          GdkGCValuesMask  values_mask)
417 {
418   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc);
419   gchar *xlfd;
420
421   GDK_NOTE (MISC, g_print ("gdk_win32_gc_set_values: {"));
422
423   if (values_mask & GDK_GC_FOREGROUND)
424     {
425       GDK_NOTE (MISC, g_print ("fg = %s ",
426                                gdk_color_to_string (&values->foreground)));
427       data->foreground = values->foreground;
428       data->values_mask |= GDK_GC_FOREGROUND;
429     }
430   
431   if (values_mask & GDK_GC_BACKGROUND)
432     {
433       GDK_NOTE (MISC, g_print ("bg = %s ",
434                                gdk_color_to_string (&values->foreground)));
435       data->background = values->background;
436       data->values_mask |= GDK_GC_BACKGROUND;
437     }
438
439   if (values_mask & GDK_GC_FONT)
440     {
441       if (data->font != NULL)
442         gdk_font_unref (data->font);
443       data->font = values->font;
444       if (data->font != NULL)
445         {
446           GDK_NOTE (MISC, (xlfd = gdk_font_xlfd_create (data->font),
447                            g_print ("font = %s ", xlfd),
448                            gdk_font_xlfd_free (xlfd)));
449           gdk_font_ref (data->font);
450           data->values_mask |= GDK_GC_FONT;
451         }
452       else
453         {
454           GDK_NOTE (MISC, g_print ("font = NULL "));
455           data->values_mask &= ~GDK_GC_FONT;
456         }
457     }
458
459   if (values_mask & GDK_GC_FUNCTION)
460     {
461       GDK_NOTE (MISC, g_print ("fun = %d ", values->function));
462
463       switch (values->function)
464         {
465         case GDK_COPY:
466           data->rop2 = R2_COPYPEN; break;
467         case GDK_INVERT:
468           data->rop2 = R2_NOT; break;
469         case GDK_XOR:
470           data->rop2 = R2_XORPEN; break;
471         case GDK_CLEAR:
472           data->rop2 = R2_BLACK; break;
473         case GDK_AND:
474           data->rop2 = R2_MASKPEN; break;
475         case GDK_AND_REVERSE:
476           data->rop2 = R2_MASKPENNOT; break;
477         case GDK_AND_INVERT:
478           data->rop2 = R2_MASKNOTPEN; break;
479         case GDK_NOOP:
480           data->rop2 = R2_NOP; break;
481         case GDK_OR:
482           data->rop2 = R2_MERGEPEN; break;
483         case GDK_EQUIV:
484           data->rop2 = R2_NOTXORPEN; break;
485         case GDK_OR_REVERSE:
486           data->rop2 = R2_MERGEPENNOT; break;
487         case GDK_COPY_INVERT:
488           data->rop2 = R2_NOTCOPYPEN; break;
489         case GDK_OR_INVERT:
490           data->rop2 = R2_MERGENOTPEN; break;
491         case GDK_NAND:
492           data->rop2 = R2_NOTMASKPEN; break;
493         case GDK_SET:
494           data->rop2 = R2_WHITE; break;
495         }
496       data->values_mask |= GDK_GC_FUNCTION;
497     }
498
499   if (values_mask & GDK_GC_FILL)
500     {
501       GDK_NOTE (MISC, g_print ("fill = %d ", values->fill));
502       data->fill_style = values->fill;
503       data->values_mask |= GDK_GC_FILL;
504     }
505
506   if (values_mask & GDK_GC_TILE)
507     {
508       if (data->tile != NULL)
509         gdk_pixmap_unref (data->tile);
510       data->tile = values->tile;
511       if (data->tile != NULL)
512         {
513           GDK_NOTE (MISC, g_print ("tile = %#x ",
514                                    GDK_DRAWABLE_XID (values->tile)));
515           gdk_pixmap_ref (data->tile);
516           data->values_mask |= GDK_GC_TILE;
517         }
518       else
519         {
520           GDK_NOTE (MISC, g_print ("tile = NULL "));
521           data->values_mask &= ~GDK_GC_TILE;
522         }
523     }
524
525   if (values_mask & GDK_GC_STIPPLE)
526     {
527       if (data->stipple != NULL)
528         gdk_pixmap_unref (data->stipple);
529       data->stipple = values->stipple;
530       if (data->stipple != NULL)
531         {
532           GDK_NOTE (MISC, g_print ("stipple = %#x ",
533                                    GDK_DRAWABLE_XID (values->stipple)));
534           gdk_pixmap_ref (data->stipple);
535           data->values_mask |= GDK_GC_STIPPLE;
536         }
537       else
538         {
539           GDK_NOTE (MISC, g_print ("stipple = NULL "));
540           data->values_mask &= ~GDK_GC_STIPPLE;
541         }
542     }
543
544   if (values_mask & GDK_GC_CLIP_MASK)
545     {
546       if (data->clip_region != NULL)
547         if (!DeleteObject (data->clip_region))
548           g_warning ("gdk_win32_gc_set_values: DeleteObject failed");
549       if (values->clip_mask != NULL)
550         {
551           data->clip_region =
552             BitmapToRegion (GDK_DRAWABLE_XID (values->clip_mask));
553           data->values_mask |= GDK_GC_CLIP_MASK;
554         }
555       else
556         {
557           data->clip_region = NULL;
558           data->values_mask &= ~GDK_GC_CLIP_MASK;
559         }
560     }
561
562   if (values_mask & GDK_GC_SUBWINDOW)
563     {
564       data->values_mask |= GDK_GC_SUBWINDOW;
565     }
566
567   if (values_mask & GDK_GC_TS_X_ORIGIN)
568     {
569       data->ts_x_origin = values->ts_x_origin;
570       data->values_mask |= GDK_GC_TS_X_ORIGIN;
571     }
572   
573   if (values_mask & GDK_GC_TS_Y_ORIGIN)
574     {
575       data->ts_y_origin = values->ts_y_origin;
576       data->values_mask |= GDK_GC_TS_Y_ORIGIN;
577     }
578   
579   if (values_mask & GDK_GC_CLIP_X_ORIGIN)
580     {
581       data->clip_x_origin = values->clip_x_origin;
582       data->values_mask |= GDK_GC_CLIP_X_ORIGIN;
583     }
584   
585   if (values_mask & GDK_GC_CLIP_Y_ORIGIN)
586     {
587       data->clip_y_origin = values->clip_y_origin;
588       data->values_mask |= GDK_GC_CLIP_Y_ORIGIN;
589     }
590   
591   if (values_mask & GDK_GC_EXPOSURES)
592     {
593       data->values_mask |= GDK_GC_EXPOSURES;
594     }
595
596   if (values_mask & GDK_GC_LINE_WIDTH)
597     {
598       data->pen_width = values->line_width;
599       data->values_mask |= GDK_GC_LINE_WIDTH;
600     }
601
602   if (values_mask & GDK_GC_LINE_STYLE)
603     {
604       data->pen_style &= ~(PS_STYLE_MASK);
605       switch (values->line_style)
606         {
607         case GDK_LINE_SOLID:
608           data->pen_style |= PS_SOLID; break;
609         case GDK_LINE_ON_OFF_DASH:
610         case GDK_LINE_DOUBLE_DASH: /* ??? */
611           data->pen_style |= PS_DASH; break;
612         }
613       data->values_mask |= GDK_GC_LINE_STYLE;
614     }
615   
616   if (values_mask & GDK_GC_CAP_STYLE)
617     {
618       data->pen_style &= ~(PS_ENDCAP_MASK);
619       switch (values->cap_style)
620         {
621         case GDK_CAP_NOT_LAST:
622           /* ??? */
623           break;
624         case GDK_CAP_BUTT:
625           data->pen_style |= PS_ENDCAP_FLAT; break;
626         case GDK_CAP_ROUND:
627           data->pen_style |= PS_ENDCAP_ROUND; break;
628         case GDK_CAP_PROJECTING:
629           data->pen_style |= PS_ENDCAP_SQUARE; break;
630         }
631       data->values_mask |= GDK_GC_CAP_STYLE;
632     }
633
634   if (values_mask & GDK_GC_JOIN_STYLE)
635     {
636       data->pen_style &= ~(PS_JOIN_MASK);
637
638       switch (values->join_style)
639         {
640         case GDK_JOIN_MITER:
641           data->pen_style |= PS_JOIN_MITER; break;
642         case GDK_JOIN_ROUND:
643           data->pen_style |= PS_JOIN_ROUND; break;
644         case GDK_JOIN_BEVEL:
645           data->pen_style |= PS_JOIN_BEVEL; break;
646         }
647       data->values_mask |= GDK_GC_JOIN_STYLE;
648     }
649 }
650
651 static void
652 gdk_win32_gc_set_dashes (GdkGC *gc,
653                          gint     dash_offset,
654                          gchar  dash_list[],
655                          gint   n)
656 {
657   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc);
658
659   /* XXX ??? */
660
661   data->pen_style &= ~(PS_STYLE_MASK);
662   data->pen_style |= PS_DASH;
663 }
664
665 void
666 gdk_gc_set_clip_rectangle (GdkGC        *gc,
667                            GdkRectangle *rectangle)
668 {
669   GdkGCWin32Data *data;
670    
671   g_return_if_fail (gc != NULL);
672
673   data = GDK_GC_WIN32DATA (gc);
674
675   if (data->clip_region != NULL)
676     if (!DeleteObject (data->clip_region))
677       g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed");
678   if (rectangle)
679     {
680       GDK_NOTE (MISC,
681                 g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n",
682                          data,
683                          rectangle->width, rectangle->height,
684                          rectangle->x, rectangle->y));
685       if ((data->clip_region =
686            CreateRectRgn (rectangle->x, rectangle->y,
687                           rectangle->x + rectangle->width,
688                           rectangle->y + rectangle->height)) == NULL)
689         g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed");
690
691       data->values_mask |= GDK_GC_CLIP_MASK;
692     }
693   else
694     {
695       GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) NULL\n",
696                                data));
697       data->clip_region = NULL;
698       data->values_mask &= ~GDK_GC_CLIP_MASK;
699     }
700     data->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN);
701
702
703 void
704 gdk_gc_set_clip_region (GdkGC            *gc,
705                         GdkRegion        *region)
706 {
707   GdkGCWin32Data *data;
708
709   g_return_if_fail (gc != NULL);
710
711   data = GDK_GC_WIN32DATA (gc);
712
713   GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n",
714                            data, (region != NULL ? "xxx" : "None")));
715
716   if (data->clip_region != NULL)
717     if (!DeleteObject (data->clip_region))
718       g_warning ("gdk_gc_set_clip_region: DeleteObject failed");
719   if (region)
720     {
721       GdkRegionPrivate *region_private;
722
723       region_private = (GdkRegionPrivate*) region;
724       data->clip_region = CreateRectRgn (1, 1, 0, 0);
725       CombineRgn (data->clip_region, region_private->xregion, NULL, RGN_COPY);
726       data->values_mask |= GDK_GC_CLIP_MASK;
727     }
728   else
729     {
730       data->clip_region = NULL;
731       data->values_mask &= ~GDK_GC_CLIP_MASK;
732     }
733 }
734
735 void
736 gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
737 {
738   GdkGCWin32Data *dst_data = GDK_GC_WIN32DATA (dst_gc);
739   GdkGCWin32Data *src_data = GDK_GC_WIN32DATA (src_gc);
740
741   if (dst_data->font)
742     gdk_font_unref (dst_data->font);
743   if (dst_data->tile)
744     gdk_pixmap_unref (dst_data->tile);
745   if (dst_data->stipple)
746     gdk_pixmap_unref (dst_data->stipple);
747   
748   *dst_data = *src_data;
749   
750   if (dst_data->font)
751     gdk_font_ref (dst_data->font);
752   if (dst_data->tile)
753     gdk_pixmap_ref (dst_data->tile);
754   if (dst_data->stipple)
755     gdk_pixmap_ref (dst_data->stipple);
756 }
757
758 HDC
759 gdk_gc_predraw (GdkDrawable  *drawable,
760                 GdkGCPrivate *gc_private)
761 {
762   GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
763   GdkColormapPrivateWin32 *colormap_private =
764     (GdkColormapPrivateWin32 *) drawable_private->colormap;
765   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc_private);
766   GdkVisual *visual;
767   COLORREF bg;
768   COLORREF fg;
769   LOGBRUSH logbrush;
770   HPEN hpen;
771   HBRUSH hbr;
772   guchar r, g, b;
773   static guint mask[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
774
775   g_assert (data->xgc == NULL);
776
777   if (GDK_DRAWABLE_TYPE (drawable) == GDK_DRAWABLE_PIXMAP)
778     {
779       if ((data->xgc = CreateCompatibleDC (NULL)) == NULL)
780         g_warning ("gdk_gc_predraw: CreateCompatibleDC failed");
781
782       if ((data->saved_dc = SaveDC (data->xgc)) == 0)
783         g_warning ("gdk_gc_predraw: SaveDC #1 failed");
784       
785       if (SelectObject (data->xgc, GDK_DRAWABLE_XID (drawable)) == NULL)
786         g_warning ("gdk_gc_predraw: SelectObject #1 failed");
787     }
788   else
789     {
790       if ((data->xgc = GetDC (GDK_DRAWABLE_XID (drawable))) == NULL)
791         g_warning ("gdk_gc_predraw: GetDC failed");
792       
793       if ((data->saved_dc = SaveDC (data->xgc)) == 0)
794         g_warning ("gdk_gc_predraw: SaveDC #2 failed");
795     }
796   
797   data->hwnd = GDK_DRAWABLE_XID (drawable);
798   
799   if (colormap_private == NULL)
800     {
801       /* A 1 bit deep bitmap */
802       struct
803       {
804         WORD palVersion;
805         WORD palNumEntries;
806         PALETTEENTRY palPalEntry[2];
807       } logpal;
808       static HPALETTE hpal = NULL;
809
810       if (hpal == NULL)
811         {
812           /* Create a b&w palette */
813           logpal.palVersion = 0x300;
814           logpal.palNumEntries = 2;
815           logpal.palPalEntry[0].peRed = 
816             logpal.palPalEntry[0].peGreen = 
817             logpal.palPalEntry[0].peBlue = 0x00;
818           logpal.palPalEntry[0].peFlags = 0x00;
819           logpal.palPalEntry[1].peRed = 
820             logpal.palPalEntry[1].peGreen = 
821             logpal.palPalEntry[1].peBlue = 0xFF;
822           logpal.palPalEntry[1].peFlags = 0x00;
823           if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
824             g_warning ("gdk_gc_predraw: CreatePalette failed");
825         }
826       SelectPalette (data->xgc, hpal, FALSE);
827       RealizePalette (data->xgc);
828       fg = PALETTEINDEX (data->foreground.pixel);
829     }
830   else if (colormap_private->xcolormap->rc_palette)
831     {
832       int k;
833       if (SelectPalette (data->xgc,
834                          colormap_private->xcolormap->palette, FALSE) == NULL)
835         g_warning ("gdk_gc_predraw: SelectPalette failed");
836       if (TRUE || colormap_private->xcolormap->stale)
837         {
838           if ((k = RealizePalette (data->xgc)) == GDI_ERROR)
839             g_warning ("gdk_gc_predraw: RealizePalette failed");
840           colormap_private->xcolormap->stale = FALSE;
841         }
842 #if 0
843       g_print ("Selected palette %#x for gc %#x, realized %d colors\n",
844                colormap_private->xcolormap->palette, data->xgc, k);
845 #endif
846       fg = PALETTEINDEX (data->foreground.pixel);
847     }
848   else
849     {
850       visual = colormap_private->visual;
851       r = (data->foreground.pixel & visual->red_mask) >> visual->red_shift;
852       r = (r * 255) / mask[visual->red_prec];
853       g = (data->foreground.pixel & visual->green_mask) >> visual->green_shift;
854       g = (g * 255) / mask[visual->green_prec];
855       b = (data->foreground.pixel & visual->blue_mask) >> visual->blue_shift;
856       b = (b * 255) / mask[visual->blue_prec];
857
858       fg = GetNearestColor (data->xgc, RGB (r, g, b));
859     }
860   logbrush.lbStyle = BS_SOLID;
861   logbrush.lbColor = fg;
862   if ((hpen = ExtCreatePen (data->pen_style, data->pen_width,
863                             &logbrush, 0, NULL)) == NULL)
864     g_warning ("gdk_gc_predraw: CreatePen failed");
865   
866   if (SelectObject (data->xgc, hpen) == NULL)
867     g_warning ("gdk_gc_predraw: SelectObject #2 failed");
868
869   if (SetTextColor (data->xgc, fg) == CLR_INVALID)
870     g_warning ("gdk_gc_predraw: SetTextColor failed");
871
872 #if 0
873   switch (data->fill_style)
874     {
875     case GDK_STIPPLED:
876       {
877         GdkPixmap *stipple = data->stipple;
878         GdkPixmapPrivate *stipple_private = (GdkPixmapPrivate *) stipple;
879         HBITMAP hbm = GDK_DRAWABLE_XID (stipple);
880         if (NULL == (hbr = CreatePatternBrush (hbm)))
881           g_warning ("gdk_gc_predraw: CreatePatternBrush failed");
882         
883 #ifdef NATIVE_WIN16
884         SetBrushOrg  (data->xgc, data->ts_x_origin,
885                       data->ts_y_origin);
886 #else
887         SetBrushOrgEx(data->xgc, data->ts_x_origin,
888                       data->ts_y_origin, NULL);
889 #endif
890       }
891       break;
892     case GDK_SOLID:
893     default:
894       if ((hbr = CreateSolidBrush (fg)) == NULL)
895         g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
896       break;
897   }
898 #else
899   if ((hbr = CreateSolidBrush (fg)) == NULL)
900     g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
901 #endif
902   if (SelectObject (data->xgc, hbr) == NULL)
903     g_warning ("gdk_gc_predraw: SelectObject #3 failed");
904
905   if (data->values_mask & GDK_GC_BACKGROUND)
906     {
907       if (colormap_private == NULL)
908         {
909           /* a bitmap */
910           bg = PALETTEINDEX (data->background.pixel);
911         }
912       else if (colormap_private->xcolormap->rc_palette)
913         {
914           bg = PALETTEINDEX (data->background.pixel);
915         }
916       else
917         {
918           visual = colormap_private->visual;
919           r = (data->background.pixel & visual->red_mask) >> visual->red_shift;
920           r = (r * 255) / mask[visual->red_prec];
921           g = (data->background.pixel & visual->green_mask) >> visual->green_shift;
922           g = (g * 255) / mask[visual->green_prec];
923           b = (data->background.pixel & visual->blue_mask) >> visual->blue_shift;
924           b = (b * 255) / mask[visual->green_prec];
925           
926           fg = GetNearestColor (data->xgc, RGB (r, g, b));
927         }
928       if (SetBkColor (data->xgc, bg) == CLR_INVALID)
929         g_warning ("gdk_gc_predraw: SetBkColor failed");
930     }
931   
932   if (SetBkMode (data->xgc, TRANSPARENT) == 0)
933     g_warning ("gdk_gc_predraw: SetBkMode failed");
934   
935   if (SetTextAlign (data->xgc, TA_BASELINE) == GDI_ERROR)
936     g_warning ("gdk_gc_predraw: SetTextAlign failed");
937   
938   if (data->values_mask & GDK_GC_FUNCTION)
939     if (SetROP2 (data->xgc, data->rop2) == 0)
940       g_warning ("gdk_gc_predraw: SetROP2 failed");
941
942   if (data->values_mask & GDK_GC_CLIP_MASK
943       && data->clip_region != NULL)
944     {
945       if (data->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
946         OffsetRgn (data->clip_region,
947                    data->clip_x_origin, data->clip_y_origin);
948       SelectClipRgn (data->xgc, data->clip_region);
949     }
950
951   return data->xgc;
952 }
953
954 void
955 gdk_gc_postdraw (GdkDrawable  *drawable,
956                  GdkGCPrivate *gc_private)
957 {
958   GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
959   GdkColormapPrivateWin32 *colormap_private =
960     (GdkColormapPrivateWin32 *) drawable_private->colormap;
961   GdkGCWin32Data *data = GDK_GC_WIN32DATA (gc_private);
962   HGDIOBJ hpen;
963   HGDIOBJ hbr;
964
965   if ((hpen = GetCurrentObject (data->xgc, OBJ_PEN)) == NULL)
966     g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
967
968   if ((hbr = GetCurrentObject (data->xgc, OBJ_BRUSH)) == NULL)
969     g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
970
971   if (!RestoreDC (data->xgc, data->saved_dc))
972     g_warning ("gdk_gc_postdraw: RestoreDC failed");
973 #if 0
974   if (colormap_private != NULL
975       && colormap_private->xcolormap->rc_palette
976       && colormap_private->xcolormap->stale)
977     {
978       SelectPalette (data->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
979       if (!UnrealizeObject (colormap_private->xcolormap->palette))
980         g_warning ("gdk_gc_postraw: UnrealizeObject failed");
981     }
982 #endif
983   if (GDK_DRAWABLE_TYPE (drawable) == GDK_DRAWABLE_PIXMAP)
984     {
985       if (!DeleteDC (data->xgc))
986         g_warning ("gdk_gc_postdraw: DeleteDC failed");
987     }
988   else
989     {
990       ReleaseDC (data->hwnd, data->xgc);
991     }
992
993   if (hpen != NULL)
994     if (!DeleteObject (hpen))
995       g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
996   
997   if (hbr != NULL)
998     if (!DeleteObject (hbr))
999       g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
1000
1001   data->xgc = NULL;
1002 }
1003
1004 /* This function originally from Jean-Edouard Lachand-Robert, and
1005  * available at www.codeguru.com. Simplified for our needs, now
1006  * handles just one-bit deep bitmaps (in Window parlance, ie those
1007  * that GDK calls bitmaps (and not pixmaps), with zero pixels being
1008  * transparent.
1009  */
1010
1011 /*
1012  *  BitmapToRegion :  Create a region from the "non-transparent" pixels of
1013  *  a bitmap
1014  *  Author :      Jean-Edouard Lachand-Robert
1015  *  (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
1016  */
1017
1018 HRGN
1019 BitmapToRegion (HBITMAP hBmp)
1020 {
1021   HRGN hRgn = NULL;
1022   HDC hMemDC;
1023   BITMAP bm;
1024
1025   struct
1026   {
1027     BITMAPINFOHEADER bmiHeader;
1028 #if 1
1029     WORD bmiColors[2];
1030 #else
1031     RGBQUAD bmiColors[2];
1032 #endif
1033   } bmi;
1034   VOID *pbits8; 
1035   HBITMAP hbm8;
1036   struct
1037   {
1038     WORD palVersion;
1039     WORD palNumEntries;
1040     PALETTEENTRY palPalEntry[2];
1041   } logpal;
1042   static HPALETTE bwPalette = NULL;
1043
1044   HBITMAP holdBmp;
1045   HDC hDC;
1046
1047   BITMAP bm8;
1048   HBITMAP holdBmp2;
1049   DWORD maxRects;
1050   RGNDATA *pData;
1051   BYTE *p8;
1052   int x, y;
1053   HRGN h;
1054
1055   /* Create a B&W palette */
1056   if (bwPalette == NULL)
1057     {
1058       /* Create a b&w palette */
1059       logpal.palVersion = 0x300;
1060       logpal.palNumEntries = 2;
1061       logpal.palPalEntry[0].peRed = 
1062         logpal.palPalEntry[0].peGreen = 
1063         logpal.palPalEntry[0].peBlue = 0;
1064       logpal.palPalEntry[0].peFlags = 0;
1065       logpal.palPalEntry[1].peRed = 
1066         logpal.palPalEntry[1].peGreen = 
1067         logpal.palPalEntry[1].peBlue = 0xFF;
1068       logpal.palPalEntry[1].peFlags = 0;
1069       if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
1070         g_warning ("BitmapToRegion: CreatePalette failed");
1071     }
1072
1073   /* Create a memory DC inside which we will scan the bitmap content */
1074   hMemDC = CreateCompatibleDC (NULL);
1075   if (!hMemDC)
1076     {
1077       g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
1078       return NULL;
1079     }
1080
1081   SelectPalette (hMemDC, bwPalette, FALSE);
1082   RealizePalette (hMemDC);
1083
1084   /* Get bitmap size */
1085   GetObject(hBmp, sizeof(bm), &bm);
1086   
1087   /* Create a 8 bits depth bitmap and select it into the memory DC */
1088   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
1089   bmi.bmiHeader.biWidth = bm.bmWidth;
1090   bmi.bmiHeader.biHeight = bm.bmHeight;
1091   bmi.bmiHeader.biPlanes = 1;
1092   bmi.bmiHeader.biBitCount = 8;
1093   bmi.bmiHeader.biCompression = BI_RGB;
1094   bmi.bmiHeader.biSizeImage = 0;
1095   bmi.bmiHeader.biXPelsPerMeter = 0;
1096   bmi.bmiHeader.biYPelsPerMeter = 0;
1097   bmi.bmiHeader.biClrUsed = 2;
1098   bmi.bmiHeader.biClrImportant = 2;
1099 #if 1
1100   bmi.bmiColors[0] = 0;
1101   bmi.bmiColors[1] = 1;
1102   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1103                             DIB_PAL_COLORS, &pbits8, NULL, 0);
1104 #else
1105   bmi.bmiColors[0].rgbBlue =
1106     bmi.bmiColors[0].rgbGreen =
1107     bmi.bmiColors[0].rgbRed = 0x00;
1108   bmi.bmiColors[0].rgbReserved = 0x00;
1109
1110   bmi.bmiColors[1].rgbBlue =
1111     bmi.bmiColors[1].rgbGreen =
1112     bmi.bmiColors[1].rgbRed = 0xFF;
1113   bmi.bmiColors[0].rgbReserved = 0x00;
1114
1115   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1116                             DIB_RGB_COLORS, &pbits8, NULL, 0);
1117 #endif
1118   if (!hbm8)
1119     {
1120       g_warning ("BitmapToRegion: CreateDIBSection failed");
1121       DeleteDC (hMemDC);
1122       return NULL;
1123     }
1124
1125   holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
1126
1127   /* Create a DC just to copy the bitmap into the memory DC*/
1128   hDC = CreateCompatibleDC (hMemDC);
1129   if (!hDC)
1130     {
1131       g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
1132       SelectObject (hMemDC, holdBmp);
1133       DeleteObject (hbm8);
1134       DeleteDC (hMemDC);
1135       return NULL;
1136     }
1137
1138   /* Get how many bytes per row we have for the bitmap bits */
1139   GetObject (hbm8, sizeof (bm8), &bm8);
1140
1141   /* Hans Breuer found a fix to the long-standing erroneous behaviour
1142    * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
1143    * in bitmaps are dword aligned on both Win95 and NT. In the case of
1144    * a bitmap with 22 bytes worth of width, GetObject above returns
1145    * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
1146    * but on NT is it 22. We need to correct this here.
1147    */
1148   bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
1149
1150   /* Copy the bitmap into the memory DC*/
1151   holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
1152
1153   if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
1154     {
1155       g_warning ("BitmapToRegion: BitBlt failed");
1156       SelectObject (hDC, holdBmp2);
1157       SelectObject (hMemDC, holdBmp);
1158       DeleteObject (hbm8);
1159       DeleteDC (hMemDC);
1160       return NULL;
1161     }
1162   SelectObject (hDC, holdBmp2);
1163   DeleteDC (hDC);
1164
1165   /* For better performances, we will use the ExtCreateRegion()
1166    * function to create the region. This function take a RGNDATA
1167    * structure on entry. We will add rectangles by amount of
1168    * ALLOC_UNIT number in this structure.
1169    */
1170   #define ALLOC_UNIT  100
1171   maxRects = ALLOC_UNIT;
1172
1173   pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
1174   pData->rdh.dwSize = sizeof (RGNDATAHEADER);
1175   pData->rdh.iType = RDH_RECTANGLES;
1176   pData->rdh.nCount = pData->rdh.nRgnSize = 0;
1177   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1178
1179   /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
1180   p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
1181   for (y = 0; y < bm.bmHeight; y++)
1182     {
1183       /* Scan each bitmap row from left to right*/
1184       for (x = 0; x < bm.bmWidth; x++)
1185         {
1186           /* Search for a continuous range of "non transparent pixels"*/
1187           int x0 = x;
1188           BYTE *p = p8 + x;
1189           while (x < bm.bmWidth)
1190             {
1191               if (*p == 0)
1192                 /* This pixel is "transparent"*/
1193                 break;
1194               p++;
1195               x++;
1196             }
1197           
1198           if (x > x0)
1199             {
1200               RECT *pr;
1201               /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
1202                * in the region
1203                */
1204               if (pData->rdh.nCount >= maxRects)
1205                 {
1206                   maxRects += ALLOC_UNIT;
1207                   pData = g_realloc (pData, sizeof(RGNDATAHEADER)
1208                                      + (sizeof(RECT) * maxRects));
1209                 }
1210               pr = (RECT *) &pData->Buffer;
1211               SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
1212               if (x0 < pData->rdh.rcBound.left)
1213                 pData->rdh.rcBound.left = x0;
1214               if (y < pData->rdh.rcBound.top)
1215                 pData->rdh.rcBound.top = y;
1216               if (x > pData->rdh.rcBound.right)
1217                 pData->rdh.rcBound.right = x;
1218               if (y+1 > pData->rdh.rcBound.bottom)
1219                 pData->rdh.rcBound.bottom = y+1;
1220               pData->rdh.nCount++;
1221               
1222               /* On Windows98, ExtCreateRegion() may fail if the
1223                * number of rectangles is too large (ie: >
1224                * 4000). Therefore, we have to create the region by
1225                * multiple steps.
1226                */
1227               if (pData->rdh.nCount == 2000)
1228                 {
1229                   HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
1230                   if (hRgn)
1231                     {
1232                       CombineRgn(hRgn, hRgn, h, RGN_OR);
1233                       DeleteObject(h);
1234                     }
1235                   else
1236                     hRgn = h;
1237                   pData->rdh.nCount = 0;
1238                   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1239                 }
1240             }
1241         }
1242       
1243       /* Go to next row (remember, the bitmap is inverted vertically)*/
1244       p8 -= bm8.bmWidthBytes;
1245     }
1246   
1247   /* Create or extend the region with the remaining rectangles*/
1248   h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
1249                        + (sizeof (RECT) * maxRects), pData);
1250   if (hRgn)
1251     {
1252       CombineRgn (hRgn, hRgn, h, RGN_OR);
1253       DeleteObject (h);
1254     }
1255   else
1256     hRgn = h;
1257
1258   /* Clean up*/
1259   SelectObject(hMemDC, holdBmp);
1260   DeleteObject (hbm8);
1261   DeleteDC (hMemDC);
1262
1263   return hRgn;
1264 }