]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgc-win32.c
Fix a cut&paste error that caused crashes.
[~andy/gtk] / gdk / win32 / gdkgc-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <string.h>
29
30 #include <gdk/gdk.h>
31 #include "gdkprivate.h"
32
33 GdkGC*
34 gdk_gc_new (GdkWindow *window)
35 {
36   return gdk_gc_new_with_values (window, NULL, 0);
37 }
38
39 GdkGC*
40 gdk_gc_new_with_values (GdkWindow       *window,
41                         GdkGCValues     *values,
42                         GdkGCValuesMask  values_mask)
43 {
44   GdkWindowPrivate *window_private;
45   GdkGC *gc;
46   GdkGCPrivate *private;
47   static GdkColor black;
48   static GdkColor white;
49   static gboolean beenhere = FALSE;
50
51   if (!beenhere)
52     {
53       gdk_color_black (gdk_colormap_get_system (), &black);
54       gdk_color_white (gdk_colormap_get_system (), &white);
55       beenhere = TRUE;
56     }
57
58   g_return_val_if_fail (window != NULL, NULL);
59
60   window_private = (GdkWindowPrivate*) window;
61   if (window_private->destroyed)
62     return NULL;
63
64   private = g_new (GdkGCPrivate, 1);
65   gc = (GdkGC*) private;
66
67   private->ref_count = 1;
68   private->rop2 = R2_COPYPEN;
69   private->fill_style = GDK_SOLID;
70   private->values_mask = values_mask;
71   private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL;
72
73   GDK_NOTE (MISC, g_print ("gdk_gc_new: {"));
74
75   if (values_mask & GDK_GC_FOREGROUND)
76     {
77       private->foreground = values->foreground;
78     }
79   else
80     private->foreground = black;
81   
82   if (values_mask & GDK_GC_BACKGROUND)
83     {
84       private->background = values->background;
85     }
86   else
87     private->background = white;
88
89   if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
90     {
91       private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont;
92       GDK_NOTE (MISC, g_print (" font=%#x", private->font));
93     }
94
95   if (values_mask & GDK_GC_FUNCTION)
96     {
97       switch (values->function)
98         {
99         case GDK_COPY:
100           private->rop2 = R2_COPYPEN; break;
101         case GDK_INVERT:
102           private->rop2 = R2_NOT; break;
103         case GDK_XOR:
104           private->rop2 = R2_XORPEN; break;
105         case GDK_CLEAR:
106           private->rop2 = R2_BLACK; break;
107         case GDK_AND:
108           private->rop2 = R2_MASKPEN; break;
109         case GDK_AND_REVERSE:
110           private->rop2 = R2_MASKPENNOT; break;
111         case GDK_AND_INVERT:
112           private->rop2 = R2_MASKNOTPEN; break;
113         case GDK_NOOP:
114           private->rop2 = R2_NOP; break;
115         case GDK_OR:
116           private->rop2 = R2_MERGEPEN; break;
117         case GDK_EQUIV:
118           private->rop2 = R2_NOTXORPEN; break;
119         case GDK_OR_REVERSE:
120           private->rop2 = R2_MERGEPENNOT; break;
121         case GDK_COPY_INVERT:
122           private->rop2 = R2_NOTCOPYPEN; break;
123         case GDK_OR_INVERT:
124           private->rop2 = R2_MERGENOTPEN; break;
125         case GDK_NAND:
126           private->rop2 = R2_NOTMASKPEN; break;
127         case GDK_SET:
128           private->rop2 = R2_WHITE; break;
129         }
130       GDK_NOTE (MISC, g_print (" function=%d", private->rop2));
131     }
132
133   if (values_mask & GDK_GC_FILL)
134     {
135       private->fill_style = values->fill;
136       GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style));
137     }
138
139   if (values_mask & GDK_GC_TILE)
140     {
141       private->tile = values->tile;
142       gdk_pixmap_ref (private->tile);
143       GDK_NOTE (MISC, g_print (" tile=%#x", ((GdkPixmapPrivate *)private->tile)->xwindow));
144     }
145   else
146     private->tile = NULL;
147
148   if (values_mask & GDK_GC_STIPPLE)
149     {
150       private->stipple = values->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 ((hbr = CreateSolidBrush (fg)) == NULL)
1017     g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
1018
1019   if (SelectObject (gc_private->xgc, hbr) == NULL)
1020     g_warning ("gdk_gc_predraw: SelectObject #3 failed");
1021
1022   if (gc_private->values_mask & GDK_GC_BACKGROUND)
1023     {
1024       if (colormap_private == NULL)
1025         {
1026           /* a bitmap */
1027           bg = PALETTEINDEX (gc_private->background.pixel);
1028         }
1029       else if (colormap_private != NULL
1030           && colormap_private->xcolormap->rc_palette)
1031         {
1032           bg = PALETTEINDEX (gc_private->background.pixel);
1033         }
1034       else
1035         {
1036           COLORREF background = RGB (gc_private->background.red >> 8,
1037                                      gc_private->background.green >> 8,
1038                                      gc_private->background.blue >> 8);
1039           bg = GetNearestColor (gc_private->xgc, background);
1040         }
1041       if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID)
1042         g_warning ("gdk_gc_predraw: SetBkColor failed");
1043     }
1044   
1045   if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0)
1046     g_warning ("gdk_gc_predraw: SetBkMode failed");
1047   
1048   if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR)
1049     g_warning ("gdk_gc_predraw: SetTextAlign failed");
1050   
1051   if (gc_private->values_mask & GDK_GC_FONT)
1052     if (SelectObject (gc_private->xgc, gc_private->font) == NULL)
1053       g_warning ("gdk_gc_predraw: SelectObject #4 failed");
1054   
1055   if (gc_private->values_mask & GDK_GC_FUNCTION)
1056     if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0)
1057       g_warning ("gdk_gc_predraw: SetROP2 failed");
1058
1059   if (gc_private->values_mask & GDK_GC_CLIP_MASK
1060       && gc_private->clip_region != NULL)
1061     {
1062       if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
1063         OffsetRgn (gc_private->clip_region,
1064                    gc_private->clip_x_origin, gc_private->clip_y_origin);
1065       SelectClipRgn (gc_private->xgc, gc_private->clip_region);
1066     }
1067
1068   return gc_private->xgc;
1069 }
1070
1071 void
1072 gdk_gc_postdraw (GdkWindowPrivate *window_private,
1073                  GdkGCPrivate     *gc_private)
1074 {
1075   HGDIOBJ hpen;
1076   HGDIOBJ hbr;
1077   GdkColormapPrivate *colormap_private =
1078     (GdkColormapPrivate *) window_private->colormap;
1079
1080   if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL)
1081     g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
1082
1083   if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL)
1084     g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
1085
1086   if (!RestoreDC (gc_private->xgc, gc_private->saved_dc))
1087     g_warning ("gdk_gc_postdraw: RestoreDC failed");
1088 #if 0
1089   if (colormap_private != NULL
1090       && colormap_private->xcolormap->rc_palette
1091       && colormap_private->xcolormap->stale)
1092     {
1093       SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
1094       if (!UnrealizeObject (colormap_private->xcolormap->palette))
1095         g_warning ("gdk_gc_postraw: UnrealizeObject failed");
1096     }
1097 #endif
1098   if (window_private->window_type == GDK_WINDOW_PIXMAP)
1099     {
1100       if (!DeleteDC (gc_private->xgc))
1101         g_warning ("gdk_gc_postdraw: DeleteDC failed");
1102     }
1103   else
1104     {
1105       ReleaseDC (gc_private->hwnd, gc_private->xgc);
1106     }
1107
1108   if (hpen != NULL)
1109     if (!DeleteObject (hpen))
1110       g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
1111   
1112   if (hbr != NULL)
1113     if (!DeleteObject (hbr))
1114       g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
1115
1116   gc_private->xgc = NULL;
1117 }
1118
1119 /* This function originally from Jean-Edouard Lachand-Robert, and
1120  * available at www.codeguru.com. Simplified for our needs, now
1121  * handles just one-bit deep bitmaps (in Window parlance, ie those
1122  * that GDK calls bitmaps (and not pixmaps), with zero pixels being
1123  * transparent.
1124  */
1125
1126 /*
1127  *  BitmapToRegion :  Create a region from the "non-transparent" pixels of
1128  *  a bitmap
1129  *  Author :      Jean-Edouard Lachand-Robert
1130  *  (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
1131  */
1132
1133 HRGN
1134 BitmapToRegion (HBITMAP hBmp)
1135 {
1136   HRGN hRgn = NULL;
1137   HDC hMemDC;
1138   BITMAP bm;
1139
1140   struct
1141   {
1142     BITMAPINFOHEADER bmiHeader;
1143 #if 1
1144     WORD bmiColors[2];
1145 #else
1146     RGBQUAD bmiColors[2];
1147 #endif
1148   } bmi;
1149   VOID *pbits8; 
1150   HBITMAP hbm8;
1151   struct
1152   {
1153     WORD palVersion;
1154     WORD palNumEntries;
1155     PALETTEENTRY palPalEntry[2];
1156   } logpal;
1157   static HPALETTE bwPalette = NULL;
1158
1159   HBITMAP holdBmp;
1160   HDC hDC;
1161
1162   BITMAP bm8;
1163   HBITMAP holdBmp2;
1164   DWORD maxRects;
1165   RGNDATA *pData;
1166   BYTE *p8;
1167   int x, y;
1168   HRGN h;
1169
1170   /* Create a B&W palette */
1171   if (bwPalette == NULL)
1172     {
1173       /* Create a b&w palette */
1174       logpal.palVersion = 0x300;
1175       logpal.palNumEntries = 2;
1176       logpal.palPalEntry[0].peRed = 
1177         logpal.palPalEntry[0].peGreen = 
1178         logpal.palPalEntry[0].peBlue = 0;
1179       logpal.palPalEntry[0].peFlags = 0;
1180       logpal.palPalEntry[1].peRed = 
1181         logpal.palPalEntry[1].peGreen = 
1182         logpal.palPalEntry[1].peBlue = 0xFF;
1183       logpal.palPalEntry[1].peFlags = 0;
1184       if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
1185         g_warning ("BitmapToRegion: CreatePalette failed");
1186     }
1187
1188   /* Create a memory DC inside which we will scan the bitmap content */
1189   hMemDC = CreateCompatibleDC (NULL);
1190   if (!hMemDC)
1191     {
1192       g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
1193       return NULL;
1194     }
1195
1196   SelectPalette (hMemDC, bwPalette, FALSE);
1197   RealizePalette (hMemDC);
1198
1199   /* Get bitmap size */
1200   GetObject(hBmp, sizeof(bm), &bm);
1201   
1202   /* Create a 8 bits depth bitmap and select it into the memory DC */
1203   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
1204   bmi.bmiHeader.biWidth = bm.bmWidth;
1205   bmi.bmiHeader.biHeight = bm.bmHeight;
1206   bmi.bmiHeader.biPlanes = 1;
1207   bmi.bmiHeader.biBitCount = 8;
1208   bmi.bmiHeader.biCompression = BI_RGB;
1209   bmi.bmiHeader.biSizeImage = 0;
1210   bmi.bmiHeader.biXPelsPerMeter = 0;
1211   bmi.bmiHeader.biYPelsPerMeter = 0;
1212   bmi.bmiHeader.biClrUsed = 2;
1213   bmi.bmiHeader.biClrImportant = 2;
1214 #if 1
1215   bmi.bmiColors[0] = 0;
1216   bmi.bmiColors[1] = 1;
1217   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1218                             DIB_PAL_COLORS, &pbits8, NULL, 0);
1219 #else
1220   bmi.bmiColors[0].rgbBlue =
1221     bmi.bmiColors[0].rgbGreen =
1222     bmi.bmiColors[0].rgbRed = 0x00;
1223   bmi.bmiColors[0].rgbReserved = 0x00;
1224
1225   bmi.bmiColors[1].rgbBlue =
1226     bmi.bmiColors[1].rgbGreen =
1227     bmi.bmiColors[1].rgbRed = 0xFF;
1228   bmi.bmiColors[0].rgbReserved = 0x00;
1229
1230   hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
1231                             DIB_RGB_COLORS, &pbits8, NULL, 0);
1232 #endif
1233   if (!hbm8)
1234     {
1235       g_warning ("BitmapToRegion: CreateDIBSection failed");
1236       DeleteDC (hMemDC);
1237       return NULL;
1238     }
1239
1240   holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
1241
1242   /* Create a DC just to copy the bitmap into the memory DC*/
1243   hDC = CreateCompatibleDC (hMemDC);
1244   if (!hDC)
1245     {
1246       g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
1247       SelectObject (hMemDC, holdBmp);
1248       DeleteObject (hbm8);
1249       DeleteDC (hMemDC);
1250       return NULL;
1251     }
1252
1253   /* Get how many bytes per row we have for the bitmap bits */
1254   GetObject (hbm8, sizeof (bm8), &bm8);
1255
1256   /* Hans Breuer found a fix to the long-standing erroneous behaviour
1257    * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
1258    * in bitmaps are dword aligned on both Win95 and NT. In the case of
1259    * a bitmap with 22 bytes worth of width, GetObject above returns
1260    * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
1261    * but on NT is it 22. We need to correct this here.
1262    */
1263   bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
1264
1265   /* Copy the bitmap into the memory DC*/
1266   holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
1267
1268   if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
1269     {
1270       g_warning ("BitmapToRegion: BitBlt failed");
1271       SelectObject (hDC, holdBmp2);
1272       SelectObject (hMemDC, holdBmp);
1273       DeleteObject (hbm8);
1274       DeleteDC (hMemDC);
1275       return NULL;
1276     }
1277   SelectObject (hDC, holdBmp2);
1278   DeleteDC (hDC);
1279
1280   /* For better performances, we will use the ExtCreateRegion()
1281    * function to create the region. This function take a RGNDATA
1282    * structure on entry. We will add rectangles by amount of
1283    * ALLOC_UNIT number in this structure.
1284    */
1285   #define ALLOC_UNIT  100
1286   maxRects = ALLOC_UNIT;
1287
1288   pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
1289   pData->rdh.dwSize = sizeof (RGNDATAHEADER);
1290   pData->rdh.iType = RDH_RECTANGLES;
1291   pData->rdh.nCount = pData->rdh.nRgnSize = 0;
1292   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1293
1294   /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
1295   p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
1296   for (y = 0; y < bm.bmHeight; y++)
1297     {
1298       /* Scan each bitmap row from left to right*/
1299       for (x = 0; x < bm.bmWidth; x++)
1300         {
1301           /* Search for a continuous range of "non transparent pixels"*/
1302           int x0 = x;
1303           BYTE *p = p8 + x;
1304           while (x < bm.bmWidth)
1305             {
1306               if (*p == 0)
1307                 /* This pixel is "transparent"*/
1308                 break;
1309               p++;
1310               x++;
1311             }
1312           
1313           if (x > x0)
1314             {
1315               RECT *pr;
1316               /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
1317                * in the region
1318                */
1319               if (pData->rdh.nCount >= maxRects)
1320                 {
1321                   maxRects += ALLOC_UNIT;
1322                   pData = g_realloc (pData, sizeof(RGNDATAHEADER)
1323                                      + (sizeof(RECT) * maxRects));
1324                 }
1325               pr = (RECT *) &pData->Buffer;
1326               SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
1327               if (x0 < pData->rdh.rcBound.left)
1328                 pData->rdh.rcBound.left = x0;
1329               if (y < pData->rdh.rcBound.top)
1330                 pData->rdh.rcBound.top = y;
1331               if (x > pData->rdh.rcBound.right)
1332                 pData->rdh.rcBound.right = x;
1333               if (y+1 > pData->rdh.rcBound.bottom)
1334                 pData->rdh.rcBound.bottom = y+1;
1335               pData->rdh.nCount++;
1336               
1337               /* On Windows98, ExtCreateRegion() may fail if the
1338                * number of rectangles is too large (ie: >
1339                * 4000). Therefore, we have to create the region by
1340                * multiple steps.
1341                */
1342               if (pData->rdh.nCount == 2000)
1343                 {
1344                   HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
1345                   if (hRgn)
1346                     {
1347                       CombineRgn(hRgn, hRgn, h, RGN_OR);
1348                       DeleteObject(h);
1349                     }
1350                   else
1351                     hRgn = h;
1352                   pData->rdh.nCount = 0;
1353                   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1354                 }
1355             }
1356         }
1357       
1358       /* Go to next row (remember, the bitmap is inverted vertically)*/
1359       p8 -= bm8.bmWidthBytes;
1360     }
1361   
1362   /* Create or extend the region with the remaining rectangles*/
1363   h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
1364                        + (sizeof (RECT) * maxRects), pData);
1365   if (hRgn)
1366     {
1367       CombineRgn (hRgn, hRgn, h, RGN_OR);
1368       DeleteObject (h);
1369     }
1370   else
1371     hRgn = h;
1372
1373   /* Clean up*/
1374   SelectObject(hMemDC, holdBmp);
1375   DeleteObject (hbm8);
1376   DeleteDC (hMemDC);
1377
1378   return hRgn;
1379 }