]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgc-win32.c
Change GDK_WINDOWING_WIN32 usage to #ifdef also here.
[~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 "gdkgc.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->stipple;
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   GDK_NOTE (MISC, g_print ("gdk_gc_set_function: (%d) %d\n", private, function));
506
507   switch (function)
508     {
509     case GDK_COPY:
510       private->rop2 = R2_COPYPEN; break;
511     case GDK_INVERT:
512       private->rop2 = R2_NOT; break;
513     case GDK_XOR:
514       private->rop2 = R2_XORPEN; break;
515     case GDK_CLEAR:
516       private->rop2 = R2_BLACK; break;
517     case GDK_AND:
518       private->rop2 = R2_MASKPEN; break;
519     case GDK_AND_REVERSE:
520       private->rop2 = R2_MASKPENNOT; break;
521     case GDK_AND_INVERT:
522       private->rop2 = R2_MASKNOTPEN; break;
523     case GDK_NOOP:
524       private->rop2 = R2_NOP; break;
525     case GDK_OR:
526       private->rop2 = R2_MERGEPEN; break;
527     case GDK_EQUIV:
528       private->rop2 = R2_NOTXORPEN; break;
529     case GDK_OR_REVERSE:
530       private->rop2 = R2_MERGEPENNOT; break;
531     case GDK_COPY_INVERT:
532       private->rop2 = R2_NOTCOPYPEN; break;
533     case GDK_OR_INVERT:
534       private->rop2 = R2_MERGENOTPEN; break;
535     case GDK_NAND:
536       private->rop2 = R2_NOTMASKPEN; break;
537     case GDK_SET:
538       private->rop2 = R2_WHITE; break;
539     }
540   private->values_mask |= GDK_GC_FUNCTION;
541 }
542
543 void
544 gdk_gc_set_fill (GdkGC   *gc,
545                  GdkFill  fill)
546 {
547   GdkGCPrivate *private;
548
549   g_return_if_fail (gc != NULL);
550
551   private = (GdkGCPrivate*) gc;
552
553   private->fill_style = fill;
554   private->values_mask |= GDK_GC_FILL;
555 }
556
557 void
558 gdk_gc_set_tile (GdkGC     *gc,
559                  GdkPixmap *tile)
560 {
561   GdkGCPrivate *private;
562   GdkPixmapPrivate *pixmap_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     {
573       pixmap_private = (GdkPixmapPrivate*) tile;
574       pixmap = pixmap_private->xwindow;
575     }
576
577   if (private->tile != NULL)
578     gdk_pixmap_unref (private->tile);
579   private->tile = tile;
580   if (tile)
581     gdk_pixmap_ref (tile);
582   if (pixmap != NULL)
583     private->values_mask |= GDK_GC_TILE;
584   else
585     private->values_mask &= ~GDK_GC_TILE;
586 }
587
588 void
589 gdk_gc_set_stipple (GdkGC     *gc,
590                     GdkPixmap *stipple)
591 {
592   GdkGCPrivate *private;
593   GdkPixmapPrivate *pixmap_private;
594   HBITMAP pixmap;
595
596   g_return_if_fail (gc != NULL);
597
598   private = (GdkGCPrivate*) gc;
599
600   pixmap = NULL;
601
602   if (stipple)
603     {
604       pixmap_private = (GdkPixmapPrivate*) stipple;
605       pixmap = pixmap_private->xwindow;
606     }
607
608   if (private->stipple != NULL)
609     gdk_pixmap_unref (private->stipple);
610   private->stipple = stipple;
611   if (stipple)
612     gdk_pixmap_ref (stipple);
613   if (pixmap != NULL)
614     private->values_mask |= GDK_GC_STIPPLE;
615   else
616     private->values_mask &= ~GDK_GC_STIPPLE;
617 }
618
619 void
620 gdk_gc_set_ts_origin (GdkGC *gc,
621                       gint   x,
622                       gint   y)
623 {
624   GdkGCPrivate *private;
625
626   g_return_if_fail (gc != NULL);
627
628   private = (GdkGCPrivate*) gc;
629
630   private->ts_x_origin = x;
631   private->ts_y_origin = y;
632   private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN;
633 }
634
635 void
636 gdk_gc_set_clip_origin (GdkGC *gc,
637                         gint   x,
638                         gint   y)
639 {
640   GdkGCPrivate *private;
641
642   g_return_if_fail (gc != NULL);
643
644   private = (GdkGCPrivate*) gc;
645
646   GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n",
647                            private, x, y));
648
649   private->clip_x_origin = x;
650   private->clip_y_origin = y;
651   private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN;
652 }
653
654 void
655 gdk_gc_set_clip_mask (GdkGC     *gc,
656                       GdkBitmap *mask)
657 {
658   GdkGCPrivate *private;
659   HBITMAP xmask;
660   
661   g_return_if_fail (gc != NULL);
662   
663   if (mask)
664     {
665       GdkWindowPrivate *mask_private;
666       
667       mask_private = (GdkWindowPrivate*) mask;
668       if (mask_private->destroyed)
669         return;
670       xmask = mask_private->xwindow;
671     }
672   else
673     xmask = NULL;
674
675   private = (GdkGCPrivate*) gc;
676
677   GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask));
678
679   if (private->clip_region != NULL)
680     if (!DeleteObject (private->clip_region))
681       g_warning ("gdk_gc_set_clip_mask: DeleteObject failed");
682   if (xmask != NULL)
683     {
684       private->clip_region = BitmapToRegion (xmask);
685       {
686         RECT rect;
687         GetRgnBox (private->clip_region, &rect);
688         GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n",
689                                  rect.right - rect.left, rect.bottom - rect.top,
690                                  rect.left, rect.top));
691       }
692 #if 0
693       /* Test code that sets clip region to whole of mask */
694       {
695         BITMAP bm;
696         GetObject (xmask, sizeof (bm), &bm);
697         private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight);
698       }
699 #endif
700       private->values_mask |= GDK_GC_CLIP_MASK;
701     }
702   else
703     {
704       private->values_mask &= ~GDK_GC_CLIP_MASK;
705       private->clip_region = NULL;
706     }
707 }
708
709 void
710 gdk_gc_set_clip_rectangle (GdkGC        *gc,
711                            GdkRectangle *rectangle)
712 {
713   GdkGCPrivate *private;
714    
715   g_return_if_fail (gc != NULL);
716
717   private = (GdkGCPrivate*) gc;
718
719   if (private->clip_region != NULL)
720     if (!DeleteObject (private->clip_region))
721       g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed");
722   if (rectangle)
723     {
724       GDK_NOTE (MISC,
725                 g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n",
726                          private,
727                          rectangle->width, rectangle->height,
728                          rectangle->x, rectangle->y));
729       if ((private->clip_region =
730            CreateRectRgn (rectangle->x, rectangle->y,
731                           rectangle->x + rectangle->width,
732                           rectangle->y + rectangle->height)) == NULL)
733         g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed");
734
735       private->values_mask |= GDK_GC_CLIP_MASK;
736     }
737   else
738     {
739       GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n",
740                                private));
741       private->clip_region = NULL;
742       private->values_mask &= ~GDK_GC_CLIP_MASK;
743     }
744     private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN);
745
746
747 void
748 gdk_gc_set_clip_region (GdkGC            *gc,
749                         GdkRegion        *region)
750 {
751   GdkGCPrivate *private;
752
753   g_return_if_fail (gc != NULL);
754
755   private = (GdkGCPrivate*) gc;
756
757   GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n",
758                            private, (region != NULL ? "xxx" : "None")));
759
760   if (private->clip_region != NULL)
761     if (!DeleteObject (private->clip_region))
762       g_warning ("gdk_gc_set_clip_region: DeleteObject failed");
763   if (region)
764     {
765       GdkRegionPrivate *region_private;
766
767       region_private = (GdkRegionPrivate*) region;
768       private->clip_region = CreateRectRgn (1, 1, 0, 0);
769       CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY);
770       private->values_mask |= GDK_GC_CLIP_MASK;
771     }
772   else
773     {
774       private->clip_region = NULL;
775       private->values_mask &= ~GDK_GC_CLIP_MASK;
776     }
777 }
778
779 void
780 gdk_gc_set_subwindow (GdkGC            *gc,
781                       GdkSubwindowMode  mode)
782 {
783   GdkGCPrivate *private;
784
785   g_return_if_fail (gc != NULL);
786
787   private = (GdkGCPrivate*) gc;
788
789   private->subwindow_mode = mode;
790   private->values_mask |= GDK_GC_SUBWINDOW;
791 }
792
793 void
794 gdk_gc_set_exposures (GdkGC *gc,
795                       gint   exposures)
796 {
797   GdkGCPrivate *private;
798
799   g_return_if_fail (gc != NULL);
800
801   private = (GdkGCPrivate*) gc;
802
803   private->graphics_exposures = exposures;
804   private->values_mask |= GDK_GC_EXPOSURES;;
805 }
806
807 void
808 gdk_gc_set_line_attributes (GdkGC       *gc,
809                             gint         line_width,
810                             GdkLineStyle line_style,
811                             GdkCapStyle  cap_style,
812                             GdkJoinStyle join_style)
813 {
814   GdkGCPrivate *private;
815   int xline_style;
816   int xcap_style;
817   int xjoin_style;
818
819   g_return_if_fail (gc != NULL);
820
821   private = (GdkGCPrivate*) gc;
822
823   GDK_NOTE (MISC,
824             g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n",
825                      private, line_width,
826                      (line_style == GDK_LINE_SOLID ? "SOLID" :
827                       (line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" :
828                        (line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" :
829                         "???"))),
830                      (cap_style == GDK_CAP_BUTT ? "BUTT" :
831                       (cap_style == GDK_CAP_ROUND ? "ROUND" :
832                        (cap_style == GDK_CAP_PROJECTING ? "PROJECTING" :
833                         "???"))),
834                      (join_style == GDK_JOIN_MITER ? "MITER" :
835                       (join_style == GDK_JOIN_ROUND ? "ROUND" :
836                        (join_style == GDK_JOIN_BEVEL ? "BEVEL" :
837                         "???")))));
838
839   private->pen_width = line_width;
840
841   /* Mask old style bits away */
842   private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK);
843
844   /* Add new bits */
845   switch (line_style)
846     {
847     case GDK_LINE_SOLID:
848       private->pen_style |= PS_SOLID; break;
849     case GDK_LINE_ON_OFF_DASH:
850     case GDK_LINE_DOUBLE_DASH: /* ??? */
851       private->pen_style |= PS_DASH; break;
852     }
853
854   switch (cap_style)
855     {
856     case GDK_CAP_NOT_LAST:
857       /* ??? */
858       break;
859     case GDK_CAP_BUTT:
860       private->pen_style |= PS_ENDCAP_FLAT; break;
861     case GDK_CAP_ROUND:
862       private->pen_style |= PS_ENDCAP_ROUND; break;
863     case GDK_CAP_PROJECTING:
864       private->pen_style |= PS_ENDCAP_SQUARE; break;
865     }
866
867   switch (join_style)
868     {
869     case GDK_JOIN_MITER:
870       private->pen_style |= PS_JOIN_MITER;
871       break;
872     case GDK_JOIN_ROUND:
873       private->pen_style |= PS_JOIN_ROUND;
874       break;
875     case GDK_JOIN_BEVEL:
876       private->pen_style |= PS_JOIN_BEVEL;
877       break;
878     }
879 }
880
881 void
882 gdk_gc_set_dashes (GdkGC *gc,
883                    gint   dash_offset,
884                    gchar  dash_list[],
885                    gint   n)
886 {
887   GdkGCPrivate *private;
888
889   g_return_if_fail (gc != NULL);
890   g_return_if_fail (dash_list != NULL);
891
892   /* XXX ??? */
893
894   private = (GdkGCPrivate *) gc;
895
896   private->pen_style &= ~(PS_STYLE_MASK);
897   private->pen_style |= PS_DASH;
898 }
899
900 void
901 gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
902 {
903   GdkGCPrivate *dst_private, *src_private;
904
905   src_private = (GdkGCPrivate *) src_gc;
906   dst_private = (GdkGCPrivate *) dst_gc;
907
908   *dst_private = *src_private;
909 }
910
911 HDC
912 gdk_gc_predraw (GdkWindowPrivate *window_private,
913                 GdkGCPrivate     *gc_private)
914 {
915   GdkColormapPrivate *colormap_private =
916     (GdkColormapPrivate *) window_private->colormap;
917   COLORREF bg;
918   COLORREF fg;
919   LOGBRUSH logbrush;
920   HPEN hpen;
921   HBRUSH hbr;
922
923   g_assert (gc_private->xgc == NULL);
924
925   if (window_private->window_type == GDK_WINDOW_PIXMAP)
926     {
927       if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL)
928         g_warning ("gdk_gc_predraw: CreateCompatibleDC failed");
929
930       if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
931         g_warning ("gdk_gc_predraw: SaveDC #1 failed");
932       
933       if (SelectObject (gc_private->xgc, window_private->xwindow) == NULL)
934         g_warning ("gdk_gc_predraw: SelectObject #1 failed");
935     }
936   else
937     {
938       if ((gc_private->xgc = GetDC (window_private->xwindow)) == NULL)
939         g_warning ("gdk_gc_predraw: GetDC failed");
940       
941       if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
942         g_warning ("gdk_gc_predraw: SaveDC #2 failed");
943     }
944   
945   gc_private->hwnd = window_private->xwindow;
946   
947   if (colormap_private == NULL)
948     {
949       /* A 1 bit deep bitmap */
950       struct
951       {
952         WORD palVersion;
953         WORD palNumEntries;
954         PALETTEENTRY palPalEntry[2];
955       } logpal;
956       static HPALETTE hpal = NULL;
957
958       if (hpal == NULL)
959         {
960           /* Create a b&w palette */
961           logpal.palVersion = 0x300;
962           logpal.palNumEntries = 2;
963           logpal.palPalEntry[0].peRed = 
964             logpal.palPalEntry[0].peGreen = 
965             logpal.palPalEntry[0].peBlue = 0x00;
966           logpal.palPalEntry[0].peFlags = 0x00;
967           logpal.palPalEntry[1].peRed = 
968             logpal.palPalEntry[1].peGreen = 
969             logpal.palPalEntry[1].peBlue = 0xFF;
970           logpal.palPalEntry[1].peFlags = 0x00;
971           if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
972             g_warning ("gdk_gc_predraw: CreatePalette failed");
973         }
974       SelectPalette (gc_private->xgc, hpal, FALSE);
975       RealizePalette (gc_private->xgc);
976       fg = PALETTEINDEX (gc_private->foreground.pixel);
977     }
978   else if (colormap_private != NULL
979            && colormap_private->xcolormap->rc_palette)
980     {
981       int k;
982       if (SelectPalette (gc_private->xgc,
983                          colormap_private->xcolormap->palette, FALSE) == NULL)
984         g_warning ("gdk_gc_predraw: SelectPalette failed");
985       if (TRUE || colormap_private->xcolormap->stale)
986         {
987           if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR)
988             g_warning ("gdk_gc_predraw: RealizePalette failed");
989           colormap_private->xcolormap->stale = FALSE;
990         }
991 #if 0
992       g_print ("Selected palette %#x for gc %#x, realized %d colors\n",
993                colormap_private->xcolormap->palette, gc_private->xgc, k);
994 #endif
995       fg = PALETTEINDEX (gc_private->foreground.pixel);
996     }
997   else
998     {
999       COLORREF foreground = RGB (gc_private->foreground.red >> 8,
1000                                  gc_private->foreground.green >> 8,
1001                                  gc_private->foreground.blue >> 8);
1002       fg = GetNearestColor (gc_private->xgc, foreground);
1003     }
1004   logbrush.lbStyle = BS_SOLID;
1005   logbrush.lbColor = fg;
1006   if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width,
1007                             &logbrush, 0, NULL)) == NULL)
1008     g_warning ("gdk_gc_predraw: CreatePen failed");
1009   
1010   if (SelectObject (gc_private->xgc, hpen) == NULL)
1011     g_warning ("gdk_gc_predraw: SelectObject #2 failed");
1012
1013   if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID)
1014     g_warning ("gdk_gc_predraw: SetTextColor failed");
1015
1016 #if 0
1017   switch (gc_private->fill_style)
1018     {
1019     case GDK_STIPPLED:
1020       {
1021         GdkPixmap *stipple = gc_private->stipple;
1022         GdkPixmapPrivate *stipple_private = (GdkPixmapPrivate *) stipple;
1023         HBITMAP hbm = stipple_private->xwindow;
1024         if (NULL == (hbr = CreatePatternBrush (hbm)))
1025           g_warning ("gdk_gc_predraw: CreatePatternBrush failed");
1026         
1027 #ifdef NATIVE_WIN16
1028         SetBrushOrg  (gc_private->xgc, gc_private->ts_x_origin,
1029                       gc_private->ts_y_origin);
1030 #else
1031         SetBrushOrgEx(gc_private->xgc, gc_private->ts_x_origin,
1032                       gc_private->ts_y_origin, NULL);
1033 #endif
1034       }
1035       break;
1036     case GDK_SOLID:
1037     default:
1038       if ((hbr = CreateSolidBrush (fg)) == NULL)
1039         g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
1040       break;
1041   }
1042 #else
1043   if ((hbr = CreateSolidBrush (fg)) == NULL)
1044     g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
1045 #endif
1046   if (SelectObject (gc_private->xgc, hbr) == NULL)
1047     g_warning ("gdk_gc_predraw: SelectObject #3 failed");
1048
1049   if (gc_private->values_mask & GDK_GC_BACKGROUND)
1050     {
1051       if (colormap_private == NULL)
1052         {
1053           /* a bitmap */
1054           bg = PALETTEINDEX (gc_private->background.pixel);
1055         }
1056       else if (colormap_private != NULL
1057           && colormap_private->xcolormap->rc_palette)
1058         {
1059           bg = PALETTEINDEX (gc_private->background.pixel);
1060         }
1061       else
1062         {
1063           COLORREF background = RGB (gc_private->background.red >> 8,
1064                                      gc_private->background.green >> 8,
1065                                      gc_private->background.blue >> 8);
1066           bg = GetNearestColor (gc_private->xgc, background);
1067         }
1068       if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID)
1069         g_warning ("gdk_gc_predraw: SetBkColor failed");
1070     }
1071   
1072   if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0)
1073     g_warning ("gdk_gc_predraw: SetBkMode failed");
1074   
1075   if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR)
1076     g_warning ("gdk_gc_predraw: SetTextAlign failed");
1077   
1078   if (gc_private->values_mask & GDK_GC_FONT)
1079     if (SelectObject (gc_private->xgc, gc_private->font) == NULL)
1080       g_warning ("gdk_gc_predraw: SelectObject #4 failed");
1081   
1082   if (gc_private->values_mask & GDK_GC_FUNCTION)
1083     if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0)
1084       g_warning ("gdk_gc_predraw: SetROP2 failed");
1085
1086   if (gc_private->values_mask & GDK_GC_CLIP_MASK
1087       && gc_private->clip_region != NULL)
1088     {
1089       if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
1090         OffsetRgn (gc_private->clip_region,
1091                    gc_private->clip_x_origin, gc_private->clip_y_origin);
1092       SelectClipRgn (gc_private->xgc, gc_private->clip_region);
1093     }
1094
1095   return gc_private->xgc;
1096 }
1097
1098 void
1099 gdk_gc_postdraw (GdkWindowPrivate *window_private,
1100                  GdkGCPrivate     *gc_private)
1101 {
1102   HGDIOBJ hpen;
1103   HGDIOBJ hbr;
1104   GdkColormapPrivate *colormap_private =
1105     (GdkColormapPrivate *) window_private->colormap;
1106
1107   if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL)
1108     g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
1109
1110   if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL)
1111     g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
1112
1113   if (!RestoreDC (gc_private->xgc, gc_private->saved_dc))
1114     g_warning ("gdk_gc_postdraw: RestoreDC failed");
1115 #if 0
1116   if (colormap_private != NULL
1117       && colormap_private->xcolormap->rc_palette
1118       && colormap_private->xcolormap->stale)
1119     {
1120       SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
1121       if (!UnrealizeObject (colormap_private->xcolormap->palette))
1122         g_warning ("gdk_gc_postraw: UnrealizeObject failed");
1123     }
1124 #endif
1125   if (window_private->window_type == GDK_WINDOW_PIXMAP)
1126     {
1127       if (!DeleteDC (gc_private->xgc))
1128         g_warning ("gdk_gc_postdraw: DeleteDC failed");
1129     }
1130   else
1131     {
1132       ReleaseDC (gc_private->hwnd, gc_private->xgc);
1133     }
1134
1135   if (hpen != NULL)
1136     if (!DeleteObject (hpen))
1137       g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
1138   
1139   if (hbr != NULL)
1140     if (!DeleteObject (hbr))
1141       g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
1142
1143   gc_private->xgc = NULL;
1144 }
1145
1146 /* This function originally from Jean-Edouard Lachand-Robert, and
1147  * available at www.codeguru.com. Simplified for our needs, now
1148  * handles just one-bit deep bitmaps (in Window parlance, ie those
1149  * that GDK calls bitmaps (and not pixmaps), with zero pixels being
1150  * transparent.
1151  */
1152
1153 /*
1154  *  BitmapToRegion :  Create a region from the "non-transparent" pixels of
1155  *  a bitmap
1156  *  Author :      Jean-Edouard Lachand-Robert
1157  *  (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
1158  */
1159
1160 HRGN
1161 BitmapToRegion (HBITMAP hBmp)
1162 {
1163   HRGN hRgn = NULL;
1164   HDC hMemDC;
1165   BITMAP bm;
1166
1167   struct
1168   {
1169     BITMAPINFOHEADER bmiHeader;
1170 #if 1
1171     WORD bmiColors[2];
1172 #else
1173     RGBQUAD bmiColors[2];
1174 #endif
1175   } bmi;
1176   VOID *pbits8; 
1177   HBITMAP hbm8;
1178   struct
1179   {
1180     WORD palVersion;
1181     WORD palNumEntries;
1182     PALETTEENTRY palPalEntry[2];
1183   } logpal;
1184   static HPALETTE bwPalette = NULL;
1185
1186   HBITMAP holdBmp;
1187   HDC hDC;
1188
1189   BITMAP bm8;
1190   HBITMAP holdBmp2;
1191   DWORD maxRects;
1192   RGNDATA *pData;
1193   BYTE *p8;
1194   int x, y;
1195   HRGN h;
1196
1197   /* Create a B&W palette */
1198   if (bwPalette == NULL)
1199     {
1200       /* Create a b&w palette */
1201       logpal.palVersion = 0x300;
1202       logpal.palNumEntries = 2;
1203       logpal.palPalEntry[0].peRed = 
1204         logpal.palPalEntry[0].peGreen = 
1205         logpal.palPalEntry[0].peBlue = 0;
1206       logpal.palPalEntry[0].peFlags = 0;
1207       logpal.palPalEntry[1].peRed = 
1208         logpal.palPalEntry[1].peGreen = 
1209         logpal.palPalEntry[1].peBlue = 0xFF;
1210       logpal.palPalEntry[1].peFlags = 0;
1211       if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
1212         g_warning ("BitmapToRegion: CreatePalette failed");
1213     }
1214
1215   /* Create a memory DC inside which we will scan the bitmap content */
1216   hMemDC = CreateCompatibleDC (NULL);
1217   if (!hMemDC)
1218     {
1219       g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
1220       return NULL;
1221     }
1222
1223   SelectPalette (hMemDC, bwPalette, FALSE);
1224   RealizePalette (hMemDC);
1225
1226   /* Get bitmap size */
1227   GetObject(hBmp, sizeof(bm), &bm);
1228   
1229   /* Create a 8 bits depth bitmap and select it into the memory DC */
1230   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
1231   bmi.bmiHeader.biWidth = bm.bmWidth;
1232   bmi.bmiHeader.biHeight = bm.bmHeight;
1233   bmi.bmiHeader.biPlanes = 1;
1234   bmi.bmiHeader.biBitCount = 8;
1235   bmi.bmiHeader.biCompression = BI_RGB;
1236   bmi.bmiHeader.biSizeImage = 0;
1237   bmi.bmiHeader.biXPelsPerMeter = 0;
1238   bmi.bmiHeader.biYPelsPerMeter = 0;
1239   bmi.bmiHeader.biClrUsed = 2;
1240   bmi.bmiHeader.biClrImportant = 2;
1241 #if 1
1242   bmi.bmiColors[0] = 0;
1243   bmi.bmiColors[1] = 1;
1244   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1245                             DIB_PAL_COLORS, &pbits8, NULL, 0);
1246 #else
1247   bmi.bmiColors[0].rgbBlue =
1248     bmi.bmiColors[0].rgbGreen =
1249     bmi.bmiColors[0].rgbRed = 0x00;
1250   bmi.bmiColors[0].rgbReserved = 0x00;
1251
1252   bmi.bmiColors[1].rgbBlue =
1253     bmi.bmiColors[1].rgbGreen =
1254     bmi.bmiColors[1].rgbRed = 0xFF;
1255   bmi.bmiColors[0].rgbReserved = 0x00;
1256
1257   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1258                             DIB_RGB_COLORS, &pbits8, NULL, 0);
1259 #endif
1260   if (!hbm8)
1261     {
1262       g_warning ("BitmapToRegion: CreateDIBSection failed");
1263       DeleteDC (hMemDC);
1264       return NULL;
1265     }
1266
1267   holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
1268
1269   /* Create a DC just to copy the bitmap into the memory DC*/
1270   hDC = CreateCompatibleDC (hMemDC);
1271   if (!hDC)
1272     {
1273       g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
1274       SelectObject (hMemDC, holdBmp);
1275       DeleteObject (hbm8);
1276       DeleteDC (hMemDC);
1277       return NULL;
1278     }
1279
1280   /* Get how many bytes per row we have for the bitmap bits */
1281   GetObject (hbm8, sizeof (bm8), &bm8);
1282
1283   /* Hans Breuer found a fix to the long-standing erroneous behaviour
1284    * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
1285    * in bitmaps are dword aligned on both Win95 and NT. In the case of
1286    * a bitmap with 22 bytes worth of width, GetObject above returns
1287    * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
1288    * but on NT is it 22. We need to correct this here.
1289    */
1290   bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
1291
1292   /* Copy the bitmap into the memory DC*/
1293   holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
1294
1295   if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
1296     {
1297       g_warning ("BitmapToRegion: BitBlt failed");
1298       SelectObject (hDC, holdBmp2);
1299       SelectObject (hMemDC, holdBmp);
1300       DeleteObject (hbm8);
1301       DeleteDC (hMemDC);
1302       return NULL;
1303     }
1304   SelectObject (hDC, holdBmp2);
1305   DeleteDC (hDC);
1306
1307   /* For better performances, we will use the ExtCreateRegion()
1308    * function to create the region. This function take a RGNDATA
1309    * structure on entry. We will add rectangles by amount of
1310    * ALLOC_UNIT number in this structure.
1311    */
1312   #define ALLOC_UNIT  100
1313   maxRects = ALLOC_UNIT;
1314
1315   pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
1316   pData->rdh.dwSize = sizeof (RGNDATAHEADER);
1317   pData->rdh.iType = RDH_RECTANGLES;
1318   pData->rdh.nCount = pData->rdh.nRgnSize = 0;
1319   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1320
1321   /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
1322   p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
1323   for (y = 0; y < bm.bmHeight; y++)
1324     {
1325       /* Scan each bitmap row from left to right*/
1326       for (x = 0; x < bm.bmWidth; x++)
1327         {
1328           /* Search for a continuous range of "non transparent pixels"*/
1329           int x0 = x;
1330           BYTE *p = p8 + x;
1331           while (x < bm.bmWidth)
1332             {
1333               if (*p == 0)
1334                 /* This pixel is "transparent"*/
1335                 break;
1336               p++;
1337               x++;
1338             }
1339           
1340           if (x > x0)
1341             {
1342               RECT *pr;
1343               /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
1344                * in the region
1345                */
1346               if (pData->rdh.nCount >= maxRects)
1347                 {
1348                   maxRects += ALLOC_UNIT;
1349                   pData = g_realloc (pData, sizeof(RGNDATAHEADER)
1350                                      + (sizeof(RECT) * maxRects));
1351                 }
1352               pr = (RECT *) &pData->Buffer;
1353               SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
1354               if (x0 < pData->rdh.rcBound.left)
1355                 pData->rdh.rcBound.left = x0;
1356               if (y < pData->rdh.rcBound.top)
1357                 pData->rdh.rcBound.top = y;
1358               if (x > pData->rdh.rcBound.right)
1359                 pData->rdh.rcBound.right = x;
1360               if (y+1 > pData->rdh.rcBound.bottom)
1361                 pData->rdh.rcBound.bottom = y+1;
1362               pData->rdh.nCount++;
1363               
1364               /* On Windows98, ExtCreateRegion() may fail if the
1365                * number of rectangles is too large (ie: >
1366                * 4000). Therefore, we have to create the region by
1367                * multiple steps.
1368                */
1369               if (pData->rdh.nCount == 2000)
1370                 {
1371                   HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
1372                   if (hRgn)
1373                     {
1374                       CombineRgn(hRgn, hRgn, h, RGN_OR);
1375                       DeleteObject(h);
1376                     }
1377                   else
1378                     hRgn = h;
1379                   pData->rdh.nCount = 0;
1380                   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1381                 }
1382             }
1383         }
1384       
1385       /* Go to next row (remember, the bitmap is inverted vertically)*/
1386       p8 -= bm8.bmWidthBytes;
1387     }
1388   
1389   /* Create or extend the region with the remaining rectangles*/
1390   h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
1391                        + (sizeof (RECT) * maxRects), pData);
1392   if (hRgn)
1393     {
1394       CombineRgn (hRgn, hRgn, h, RGN_OR);
1395       DeleteObject (h);
1396     }
1397   else
1398     hRgn = h;
1399
1400   /* Clean up*/
1401   SelectObject(hMemDC, holdBmp);
1402   DeleteObject (hbm8);
1403   DeleteDC (hMemDC);
1404
1405   return hRgn;
1406 }