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