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