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