]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgc-win32.c
a5efc8b2c9c39b8638f541b4d3110cd237a2dbc5
[~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  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <string.h>
29
30 #include "gdkgc.h"
31 #include "gdkfont.h"
32 #include "gdkpixmap.h"
33 #include "gdkregion-generic.h"
34 #include "gdkprivate-win32.h"
35
36 static void gdk_win32_gc_get_values (GdkGC           *gc,
37                                      GdkGCValues     *values);
38 static void gdk_win32_gc_set_values (GdkGC           *gc,
39                                      GdkGCValues     *values,
40                                      GdkGCValuesMask  values_mask);
41 static void gdk_win32_gc_set_dashes (GdkGC           *gc,
42                                      gint             dash_offset,
43                                      gint8            dash_list[],
44                                      gint             n);
45
46 static void gdk_gc_win32_class_init (GdkGCWin32Class *klass);
47 static void gdk_gc_win32_finalize   (GObject         *object);
48
49 static gpointer parent_class = NULL;
50
51 GType
52 _gdk_gc_win32_get_type (void)
53 {
54   static GType object_type = 0;
55
56   if (!object_type)
57     {
58       static const GTypeInfo object_info =
59       {
60         sizeof (GdkGCWin32Class),
61         (GBaseInitFunc) NULL,
62         (GBaseFinalizeFunc) NULL,
63         (GClassInitFunc) gdk_gc_win32_class_init,
64         NULL,           /* class_finalize */
65         NULL,           /* class_data */
66         sizeof (GdkGCWin32),
67         0,              /* n_preallocs */
68         (GInstanceInitFunc) NULL,
69       };
70       
71       object_type = g_type_register_static (GDK_TYPE_GC,
72                                             "GdkGCWin32",
73                                             &object_info, 0);
74     }
75   
76   return object_type;
77 }
78
79 static void
80 gdk_gc_win32_class_init (GdkGCWin32Class *klass)
81 {
82   GObjectClass *object_class = G_OBJECT_CLASS (klass);
83   GdkGCClass *gc_class = GDK_GC_CLASS (klass);
84   
85   parent_class = g_type_class_peek_parent (klass);
86
87   object_class->finalize = gdk_gc_win32_finalize;
88
89   gc_class->get_values = gdk_win32_gc_get_values;
90   gc_class->set_values = gdk_win32_gc_set_values;
91   gc_class->set_dashes = gdk_win32_gc_set_dashes;
92 }
93
94 static void
95 gdk_gc_win32_finalize (GObject *object)
96 {
97   GdkGCWin32 *win32_gc = GDK_GC_WIN32 (object);
98   
99   if (win32_gc->clip_region)
100     gdk_region_destroy (win32_gc->clip_region);
101   
102   if (win32_gc->values_mask & GDK_GC_FONT)
103     gdk_font_unref (win32_gc->font);
104   
105   if (win32_gc->values_mask & GDK_GC_TILE)
106     gdk_drawable_unref (win32_gc->tile);
107   
108   if (win32_gc->values_mask & GDK_GC_STIPPLE)
109     gdk_drawable_unref (win32_gc->stipple);
110   
111   G_OBJECT_CLASS (parent_class)->finalize (object);
112 }
113
114 static void
115 gdk_win32_gc_values_to_win32values (GdkGCValues    *values,
116                                     GdkGCValuesMask mask,
117                                     GdkGCWin32     *win32_gc)
118 {                                   
119   char *s = "";
120   gint sw, sh;
121
122   GDK_NOTE (GC, g_print ("{"));
123
124   if (mask & GDK_GC_FOREGROUND)
125     {
126       win32_gc->foreground = values->foreground.pixel;
127       win32_gc->values_mask |= GDK_GC_FOREGROUND;
128       GDK_NOTE (GC, (g_print ("fg=%.06lx", win32_gc->foreground),
129                      s = ","));
130     }
131   
132   if (mask & GDK_GC_BACKGROUND)
133     {
134       win32_gc->background = values->background.pixel;
135       win32_gc->values_mask |= GDK_GC_BACKGROUND;
136       GDK_NOTE (GC, (g_print ("%sbg=%.06lx", s, win32_gc->background),
137                      s = ","));
138     }
139
140   if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT
141                                || values->font->type == GDK_FONT_FONTSET))
142     {
143       if (win32_gc->font != NULL)
144         gdk_font_unref (win32_gc->font);
145       win32_gc->font = values->font;
146       if (win32_gc->font != NULL)
147         {
148           gchar *xlfd;
149
150           gdk_font_ref (win32_gc->font);
151           win32_gc->values_mask |= GDK_GC_FONT;
152           GDK_NOTE (GC, (xlfd = gdk_font_full_name_get (win32_gc->font),
153                          g_print ("%sfont=%s", s, xlfd),
154                          s = ",",
155                          gdk_font_full_name_free (xlfd)));
156         }
157       else
158         {
159           win32_gc->values_mask &= ~GDK_GC_FONT;
160           GDK_NOTE (GC, (g_print ("%sfont=NULL", s),
161                          s = ","));
162         }
163     }
164
165   if (mask & GDK_GC_FUNCTION)
166     {
167       GDK_NOTE (GC, (g_print ("%srop2=", s),
168                      s = ","));
169       switch (values->function)
170         {
171 #define CASE(x,y) case GDK_##x: win32_gc->rop2 = R2_##y; GDK_NOTE (GC, g_print (#y)); break
172         CASE (COPY, COPYPEN);
173         CASE (INVERT, NOT);
174         CASE (XOR, XORPEN);
175         CASE (CLEAR, BLACK);
176         CASE (AND, MASKPEN);
177         CASE (AND_REVERSE, MASKPENNOT);
178         CASE (AND_INVERT, MASKNOTPEN);
179         CASE (NOOP, NOP);
180         CASE (OR, MERGEPEN);
181         CASE (EQUIV, NOTXORPEN);
182         CASE (OR_REVERSE, MERGEPENNOT);
183         CASE (COPY_INVERT, NOTCOPYPEN);
184         CASE (OR_INVERT, MERGENOTPEN);
185         CASE (NAND, NOTMASKPEN);
186         CASE (NOR, NOTMERGEPEN);
187         CASE (SET, WHITE);
188 #undef CASE
189         }
190       win32_gc->values_mask |= GDK_GC_FUNCTION;
191     }
192
193   if (mask & GDK_GC_FILL)
194     {
195       win32_gc->fill_style = values->fill;
196       win32_gc->values_mask |= GDK_GC_FILL;
197       GDK_NOTE (GC, (g_print ("%sfill=%d", s, win32_gc->fill_style),
198                      s = ","));
199     }
200
201   if (mask & GDK_GC_TILE)
202     {
203       if (win32_gc->tile != NULL)
204         gdk_drawable_unref (win32_gc->tile);
205       win32_gc->tile = values->tile;
206       if (win32_gc->tile != NULL)
207         {
208           gdk_drawable_ref (win32_gc->tile);
209           win32_gc->values_mask |= GDK_GC_TILE;
210           GDK_NOTE (GC,
211                     (g_print ("%stile=%p", s,
212                               GDK_PIXMAP_HBITMAP (win32_gc->tile)),
213                      s = ","));
214         }
215       else
216         {
217           win32_gc->values_mask &= ~GDK_GC_TILE;
218           GDK_NOTE (GC, (g_print ("%stile=NULL", s),
219                          s = ","));
220         }
221     }
222
223   if (mask & GDK_GC_STIPPLE)
224     {
225       if (win32_gc->stipple != NULL)
226         gdk_drawable_unref (win32_gc->stipple);
227       win32_gc->stipple = values->stipple;
228       if (win32_gc->stipple != NULL)
229         {
230           gdk_drawable_get_size (win32_gc->stipple, &sw, &sh);
231
232 #if 0 /* HB: this size limitation is disabled to make radio and check
233        * buttons work. I got the impression from the API docs, that
234        * it shouldn't be necessary at all, but win9x would do the clipping
235        */
236           if (   (sw != 8 || sh != 8)
237               && !IS_WIN_NT ()) /* HB: the MSDN says it's a Win95 limitation */
238             {
239               /* It seems that it *must* be 8x8, at least on my machine. 
240                * Thus, tile an 8x8 bitmap with the stipple in case it is
241                * smaller, or simply use just the top left 8x8 in case it is
242                * larger.
243                */
244               gchar dummy[8];
245               GdkPixmap *bm = gdk_bitmap_create_from_data (NULL, dummy, 8, 8);
246               GdkGC *gc = gdk_gc_new (bm);
247               gint i, j;
248
249               i = 0;
250               while (i < 8)
251                 {
252                   j = 0;
253                   while (j < 8)
254                     {
255                       gdk_draw_drawable (bm, gc, win32_gc->stipple, 0, 0, i, j, sw, sh);
256                       j += sh;
257                     }
258                   i += sw;
259                 }
260               win32_gc->stipple = bm;
261               gdk_gc_unref (gc);
262             }
263           else
264 #endif
265             gdk_drawable_ref (win32_gc->stipple);
266           win32_gc->values_mask |= GDK_GC_STIPPLE;
267           GDK_NOTE (GC,
268                     (g_print ("%sstipple=%p", s,
269                               GDK_PIXMAP_HBITMAP (win32_gc->stipple)),
270                      s = ","));
271         }
272       else
273         {
274           win32_gc->values_mask &= ~GDK_GC_STIPPLE;
275           GDK_NOTE (GC, (g_print ("%sstipple=NULL", s),
276                          s = ","));
277         }
278     }
279
280   if (mask & GDK_GC_CLIP_MASK)
281     {
282       if (win32_gc->clip_region != NULL)
283         {
284           gdk_region_destroy (win32_gc->clip_region);
285           win32_gc->clip_region = NULL;
286         }
287
288       if (win32_gc->hcliprgn != NULL)
289         {
290           DeleteObject (win32_gc->hcliprgn);
291           win32_gc->hcliprgn = NULL;
292         }
293
294       if (values->clip_mask != NULL)
295         {
296           win32_gc->hcliprgn =
297             _gdk_win32_bitmap_to_region (values->clip_mask);
298           win32_gc->values_mask |= GDK_GC_CLIP_MASK;
299         }
300       else
301         {
302           win32_gc->hcliprgn = NULL;
303           win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
304         }
305       GDK_NOTE (GC, (g_print ("%sclip=%p", s, win32_gc->hcliprgn),
306                      s = ","));
307     }
308
309   if (mask & GDK_GC_SUBWINDOW)
310     {
311       win32_gc->subwindow_mode = values->subwindow_mode;
312       win32_gc->values_mask |= GDK_GC_SUBWINDOW;
313       GDK_NOTE (GC, (g_print ("%ssubw=%d", s, win32_gc->subwindow_mode),
314                      s = ","));
315     }
316
317   if (mask & GDK_GC_TS_X_ORIGIN)
318     {
319       win32_gc->values_mask |= GDK_GC_TS_X_ORIGIN;
320       GDK_NOTE (GC, (g_print ("%sts_x=%d", s, values->ts_x_origin),
321                      s = ","));
322     }
323
324   if (mask & GDK_GC_TS_Y_ORIGIN)
325     {
326       win32_gc->values_mask |= GDK_GC_TS_Y_ORIGIN;
327       GDK_NOTE (GC, (g_print ("%sts_y=%d", s, values->ts_y_origin),
328                      s = ","));
329     }
330
331   if (mask & GDK_GC_CLIP_X_ORIGIN)
332     {
333       win32_gc->values_mask |= GDK_GC_CLIP_X_ORIGIN;
334       GDK_NOTE (GC, (g_print ("%sclip_x=%d", s, values->clip_x_origin),
335                      s = ","));
336     }
337
338   if (mask & GDK_GC_CLIP_Y_ORIGIN)
339     {
340       win32_gc->values_mask |= GDK_GC_CLIP_Y_ORIGIN;
341       GDK_NOTE (GC, (g_print ("%sclip_y=%d", s, values->clip_y_origin),
342                      s = ","));
343     }
344
345   if (mask & GDK_GC_EXPOSURES)
346     {
347       win32_gc->graphics_exposures = values->graphics_exposures;
348       win32_gc->values_mask |= GDK_GC_EXPOSURES;
349       GDK_NOTE (GC, (g_print ("%sexp=%d", s, win32_gc->graphics_exposures),
350                      s = ","));
351     }
352
353   if (mask & GDK_GC_LINE_WIDTH)
354     {
355       win32_gc->pen_width = values->line_width;
356       win32_gc->values_mask |= GDK_GC_LINE_WIDTH;
357       GDK_NOTE (GC, (g_print ("%spw=%d", s, win32_gc->pen_width),
358                      s = ","));
359     }
360
361   if (mask & GDK_GC_LINE_STYLE)
362     {
363       switch (values->line_style)
364         {
365         case GDK_LINE_SOLID:
366         win32_gc->pen_style &= ~(PS_STYLE_MASK);
367           GDK_NOTE (GC, (g_print ("%sps|=LINE_SOLID", s),
368                          s = ","));
369           win32_gc->pen_style |= PS_SOLID;
370           break;
371         case GDK_LINE_ON_OFF_DASH:
372         case GDK_LINE_DOUBLE_DASH: /* ??? */
373           /* Only set the linestyle here, if it isn't already set
374            * gdk_win32_gc_set_dashes () knows better
375            */
376           if (0 == (win32_gc->values_mask & GDK_GC_LINE_STYLE))
377             {
378             win32_gc->pen_style &= ~(PS_STYLE_MASK);
379               GDK_NOTE (GC, (g_print ("%sps|=DASH", s),
380                              s = ","));
381               win32_gc->pen_style |= PS_DASH;
382             }
383           break;
384         }
385       win32_gc->values_mask |= GDK_GC_LINE_STYLE;
386     }
387
388   if (mask & GDK_GC_CAP_STYLE)
389     {
390       win32_gc->pen_style &= ~(PS_ENDCAP_MASK);
391       switch (values->cap_style)
392         {
393         case GDK_CAP_NOT_LAST:  /* ??? */
394         case GDK_CAP_BUTT:
395           GDK_NOTE (GC, (g_print ("%sps|=ENDCAP_FLAT", s),
396                          s = ","));
397           win32_gc->pen_style |= PS_ENDCAP_FLAT;
398           break;
399         case GDK_CAP_ROUND:
400           GDK_NOTE (GC, (g_print ("%sps|=ENDCAP_ROUND", s),
401                          s = ","));
402           win32_gc->pen_style |= PS_ENDCAP_ROUND;
403           break;
404         case GDK_CAP_PROJECTING:
405           GDK_NOTE (GC, (g_print ("%sps|=ENDCAP_SQUARE", s),
406                          s = ","));
407           win32_gc->pen_style |= PS_ENDCAP_SQUARE;
408           break;
409         }
410       win32_gc->values_mask |= GDK_GC_CAP_STYLE;
411     }
412
413   if (mask & GDK_GC_JOIN_STYLE)
414     {
415       win32_gc->pen_style &= ~(PS_JOIN_MASK);
416       switch (values->join_style)
417         {
418         case GDK_JOIN_MITER:
419           GDK_NOTE (GC, (g_print ("%sps|=JOIN_MITER", s),
420                          s = ","));
421           win32_gc->pen_style |= PS_JOIN_MITER;
422           break;
423         case GDK_JOIN_ROUND:
424           GDK_NOTE (GC, (g_print ("%sps|=JOIN_ROUND", s),
425                          s = ","));
426           win32_gc->pen_style |= PS_JOIN_ROUND;
427           break;
428         case GDK_JOIN_BEVEL:
429           GDK_NOTE (GC, (g_print ("%sps|=JOIN_BEVEL", s),
430                          s = ","));
431           win32_gc->pen_style |= PS_JOIN_BEVEL;
432           break;
433         }
434       win32_gc->values_mask |= GDK_GC_JOIN_STYLE;
435     }
436   GDK_NOTE (GC, g_print ("}\n"));
437 }
438
439 GdkGC*
440 _gdk_win32_gc_new (GdkDrawable    *drawable,
441                    GdkGCValues    *values,
442                    GdkGCValuesMask mask)
443 {
444   GdkGC *gc;
445   GdkGCWin32 *win32_gc;
446
447   /* NOTICE that the drawable here has to be the impl drawable,
448    * not the publically-visible drawables.
449    */
450   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable), NULL);
451
452   gc = g_object_new (_gdk_gc_win32_get_type (), NULL);
453   win32_gc = GDK_GC_WIN32 (gc);
454
455   win32_gc->hdc = NULL;
456   win32_gc->clip_region = NULL;
457   win32_gc->hcliprgn = NULL;
458
459   /* Use the same default values as X11 does, even if they don't make
460    * sense per se. But apps always set fg and bg anyway.
461    */
462   win32_gc->foreground = 0;
463   win32_gc->background = 1;
464   win32_gc->font = NULL;
465   win32_gc->rop2 = R2_COPYPEN;
466   win32_gc->fill_style = GDK_SOLID;
467   win32_gc->tile = NULL;
468   win32_gc->stipple = NULL;
469   win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_MITER;
470   win32_gc->pen_width = 0;
471
472   win32_gc->values_mask = GDK_GC_FUNCTION | GDK_GC_FILL;
473
474   GDK_NOTE (GC, g_print ("_gdk_win32_gc_new: "));
475   gdk_win32_gc_values_to_win32values (values, mask, win32_gc);
476
477   win32_gc->hwnd = NULL;
478
479   GDK_NOTE (GC, g_print (" = %p\n", gc));
480
481   return gc;
482 }
483
484 static void
485 gdk_win32_gc_get_values (GdkGC       *gc,
486                          GdkGCValues *values)
487 {
488   GdkGCWin32 *win32_gc = GDK_GC_WIN32 (gc);
489
490   values->foreground.pixel = win32_gc->foreground;
491   values->background.pixel = win32_gc->background;
492   values->font = win32_gc->font;
493
494   switch (win32_gc->rop2)
495     {
496     case R2_COPYPEN:
497       values->function = GDK_COPY; break;
498     case R2_NOT:
499       values->function = GDK_INVERT; break;
500     case R2_XORPEN:
501       values->function = GDK_XOR; break;
502     case R2_BLACK:
503       values->function = GDK_CLEAR; break;
504     case R2_MASKPEN:
505       values->function = GDK_AND; break;
506     case R2_MASKPENNOT:
507       values->function = GDK_AND_REVERSE; break;
508     case R2_MASKNOTPEN:
509       values->function = GDK_AND_INVERT; break;
510     case R2_NOP:
511       values->function = GDK_NOOP; break;
512     case R2_MERGEPEN:
513       values->function = GDK_OR; break;
514     case R2_NOTXORPEN:
515       values->function = GDK_EQUIV; break;
516     case R2_MERGEPENNOT:
517       values->function = GDK_OR_REVERSE; break;
518     case R2_NOTCOPYPEN:
519       values->function = GDK_COPY_INVERT; break;
520     case R2_MERGENOTPEN:
521       values->function = GDK_OR_INVERT; break;
522     case R2_NOTMASKPEN:
523       values->function = GDK_NAND; break;
524     case R2_NOTMERGEPEN:
525       values->function = GDK_NOR; break;
526     case R2_WHITE:
527       values->function = GDK_SET; break;
528     }
529
530   values->fill = win32_gc->fill_style;
531
532   values->tile = win32_gc->tile;
533   values->stipple = win32_gc->stipple;
534
535   /* Also the X11 backend always returns a NULL clip_mask */
536   values->clip_mask = NULL;
537
538   values->subwindow_mode = win32_gc->subwindow_mode;
539   values->ts_x_origin = win32_gc->parent_instance.ts_x_origin;
540   values->ts_y_origin = win32_gc->parent_instance.ts_y_origin;
541   values->clip_x_origin = win32_gc->parent_instance.clip_x_origin;
542   values->clip_y_origin = win32_gc->parent_instance.clip_y_origin;
543   values->graphics_exposures = win32_gc->graphics_exposures;
544   values->line_width = win32_gc->pen_width;
545   
546   if (win32_gc->pen_style & PS_SOLID)
547     values->line_style = GDK_LINE_SOLID;
548   else if (win32_gc->pen_style & PS_DASH)
549     values->line_style = GDK_LINE_ON_OFF_DASH;
550   else
551     values->line_style = GDK_LINE_SOLID;
552
553   /* PS_ENDCAP_ROUND is zero */
554   if (win32_gc->pen_style & PS_ENDCAP_FLAT)
555     values->cap_style = GDK_CAP_BUTT;
556   else if (win32_gc->pen_style & PS_ENDCAP_SQUARE)
557     values->cap_style = GDK_CAP_PROJECTING;
558   else
559     values->cap_style = GDK_CAP_ROUND;
560     
561   /* PS_JOIN_ROUND is zero */
562   if (win32_gc->pen_style & PS_JOIN_MITER)
563     values->join_style = GDK_JOIN_MITER;
564   else if (win32_gc->pen_style & PS_JOIN_BEVEL)
565     values->join_style = GDK_JOIN_BEVEL;
566   else
567     values->join_style = GDK_JOIN_ROUND;
568 }
569
570 static void
571 gdk_win32_gc_set_values (GdkGC           *gc,
572                          GdkGCValues     *values,
573                          GdkGCValuesMask  mask)
574 {
575   g_return_if_fail (GDK_IS_GC (gc));
576
577   GDK_NOTE (GC, g_print ("gdk_win32_gc_set_values: "));
578
579   gdk_win32_gc_values_to_win32values (values, mask, GDK_GC_WIN32 (gc));
580 }
581
582 static void
583 gdk_win32_gc_set_dashes (GdkGC *gc,
584                          gint   dash_offset,
585                          gint8  dash_list[],
586                          gint   n)
587 {
588   GdkGCWin32 *win32_gc;
589
590   g_return_if_fail (GDK_IS_GC (gc));
591   g_return_if_fail (dash_list != NULL);
592
593   win32_gc = GDK_GC_WIN32 (gc);
594
595   /* mark as set, see gdk_win32_gc_values_to_win32values () for the reason */
596   win32_gc->values_mask |= GDK_GC_LINE_STYLE;
597
598   win32_gc->pen_style &= ~(PS_STYLE_MASK);
599
600   /* 
601    * Set the extended line style. This could be done by 
602    * PS_USERSTYLE and ExtCreatePen; but ONLY on WinNT, 
603    * so let's make a guess (based on the implementation 
604    * in DIA). On Win9x this does only work for lines
605    * with width one ...
606    *
607    * More workarounds for Win9x descibed at:
608    * http://www.codeguru.com/gdi/dashed.shtml
609    */
610   if (!IS_WIN_NT () && win32_gc->pen_width > 1)
611     {
612       GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: not fully supported\n"));
613       win32_gc->pen_style |= PS_SOLID;
614       return;
615     }
616   
617   win32_gc->pen_style = PS_COSMETIC; /* ??? */
618   switch (n)
619     {
620     case 2:
621       if ((dash_list[0] == dash_list[1]) && (dash_list[0] > 2))
622         {
623           win32_gc->pen_style |= PS_DASH;
624           GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: PS_DASH (%d,%d)\n", 
625                                  dash_list[0], dash_list[1]));
626         }
627       else
628         {
629           win32_gc->pen_style |= PS_DOT;
630           GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: PS_DOT (%d,%d)\n", 
631                                  dash_list[0], dash_list[1]));
632         }
633       break;
634
635     case 4:
636       win32_gc->pen_style |= PS_DASHDOT; 
637       GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: PS_DASHDOT (%d,%d,%d,%d)\n", 
638                              dash_list[0], dash_list[1],
639                              dash_list[2], dash_list[3]));
640       break;
641
642     case 6:
643       win32_gc->pen_style |= PS_DASHDOTDOT; 
644       GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: PS_DASHDOTDOT (%d,%d,%d,%d,%d,%d)\n", 
645                              dash_list[0], dash_list[1],
646                              dash_list[2], dash_list[3],
647                              dash_list[4], dash_list[5]));
648       break;
649
650     default:
651       win32_gc->pen_style |= PS_DASH;
652       GDK_NOTE (GC, g_print ("gdk_win32_gc_set_dashes: no guess for %d dashes\n", n));
653       break;
654     }
655 }
656
657 void
658 gdk_gc_set_clip_rectangle (GdkGC        *gc,
659                            GdkRectangle *rectangle)
660 {
661   GdkGCWin32 *win32_gc;
662
663   g_return_if_fail (GDK_IS_GC (gc));
664
665   win32_gc = GDK_GC_WIN32 (gc);
666
667   if (win32_gc->hcliprgn)
668     {
669       DeleteObject (win32_gc->hcliprgn);
670       win32_gc->hcliprgn = NULL;
671     }
672
673   if (win32_gc->clip_region)
674     gdk_region_destroy (win32_gc->clip_region);
675
676   if (rectangle)
677     {
678       GDK_NOTE (GC,
679                 g_print ("gdk_gc_set_clip_rectangle: %dx%d@+%d+%d\n",
680                          rectangle->width, rectangle->height,
681                          rectangle->x, rectangle->y));
682       win32_gc->clip_region = gdk_region_rectangle (rectangle);
683       win32_gc->values_mask |= GDK_GC_CLIP_MASK;
684     }
685   else
686     {
687       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_rectangle: NULL\n"));
688
689       win32_gc->clip_region = NULL;
690       win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
691     }
692     win32_gc->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
693
694
695 void
696 gdk_gc_set_clip_region (GdkGC            *gc,
697                         GdkRegion        *region)
698 {
699   GdkGCWin32 *win32_gc;
700
701   g_return_if_fail (GDK_IS_GC (gc));
702
703   win32_gc = GDK_GC_WIN32 (gc);
704
705   if (win32_gc->clip_region)
706     gdk_region_destroy (win32_gc->clip_region);
707
708   if (region)
709     {
710       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_region: %dx%d+%d+%d\n",
711                                region->extents.x2 - region->extents.x1,
712                                region->extents.y2 - region->extents.y1,
713                                region->extents.x1, region->extents.y1));
714
715       win32_gc->clip_region = gdk_region_copy (region);
716       win32_gc->values_mask |= GDK_GC_CLIP_MASK;
717     }
718   else
719     {
720       GDK_NOTE (GC, g_print ("gdk_gc_set_clip_region: NULL\n"));
721
722       win32_gc->clip_region = NULL;
723       win32_gc->values_mask &= ~GDK_GC_CLIP_MASK;
724     }
725
726   gc->clip_x_origin = 0;
727   gc->clip_y_origin = 0;
728
729   win32_gc->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
730 }
731
732 void
733 gdk_gc_copy (GdkGC *dst_gc,
734              GdkGC *src_gc)
735 {
736   GdkGCWin32 *dst_win32_gc;
737   GdkGCWin32 *src_win32_gc;
738
739   g_return_if_fail (GDK_IS_GC_WIN32 (dst_gc));
740   g_return_if_fail (GDK_IS_GC_WIN32 (src_gc));
741   
742   dst_win32_gc = GDK_GC_WIN32 (dst_gc);
743   src_win32_gc = GDK_GC_WIN32 (src_gc);
744
745   if (dst_win32_gc->font != NULL)
746     gdk_font_unref (dst_win32_gc->font);
747   if (dst_win32_gc->tile != NULL)
748     gdk_drawable_unref (dst_win32_gc->tile);
749   if (dst_win32_gc->stipple != NULL)
750     gdk_drawable_unref (dst_win32_gc->stipple);
751   if (dst_win32_gc->clip_region != NULL)
752     gdk_region_destroy (dst_win32_gc->clip_region);
753   if (dst_win32_gc->hcliprgn != NULL)
754     DeleteObject (dst_win32_gc->hcliprgn);
755   
756   *dst_win32_gc = *src_win32_gc;
757
758   if (dst_win32_gc->hcliprgn)
759     {
760       /* create a new region, to copy to */
761       dst_win32_gc->hcliprgn = CreateRectRgn (0,0,1,1);
762       /* overwrite from source */
763       CombineRgn (dst_win32_gc->hcliprgn, src_win32_gc->hcliprgn,
764                   NULL, RGN_COPY);
765     }
766   if (dst_win32_gc->clip_region != NULL)
767     dst_win32_gc->clip_region = gdk_region_copy (dst_win32_gc->clip_region);
768   if (dst_win32_gc->font != NULL)
769     gdk_font_ref (dst_win32_gc->font);
770   if (dst_win32_gc->tile != NULL)
771     gdk_drawable_ref (dst_win32_gc->tile);
772   if (dst_win32_gc->stipple != NULL)
773     gdk_drawable_ref (dst_win32_gc->stipple);
774 }
775
776 static guint bitmask[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
777
778 COLORREF
779 _gdk_win32_colormap_color (GdkColormap *colormap,
780                            gulong       pixel)
781 {
782   const GdkVisual *visual;
783   GdkColormapPrivateWin32 *colormap_private;
784   guchar r, g, b;
785
786   if (colormap == NULL)
787     return DIBINDEX (pixel);
788
789   colormap_private = GDK_WIN32_COLORMAP_DATA (colormap);
790
791   g_assert (colormap_private != NULL);
792
793   visual = colormap->visual;
794   switch (visual->type)
795     {
796     case GDK_VISUAL_GRAYSCALE:
797     case GDK_VISUAL_PSEUDO_COLOR:
798     case GDK_VISUAL_STATIC_COLOR:
799       return PALETTEINDEX (pixel);
800
801     case GDK_VISUAL_TRUE_COLOR:
802       r = (pixel & visual->red_mask) >> visual->red_shift;
803       r = (r * 255) / bitmask[visual->red_prec];
804       g = (pixel & visual->green_mask) >> visual->green_shift;
805       g = (g * 255) / bitmask[visual->green_prec];
806       b = (pixel & visual->blue_mask) >> visual->blue_shift;
807       b = (b * 255) / bitmask[visual->blue_prec];
808       return RGB (r, g, b);
809
810     default:
811       g_assert_not_reached ();
812       return 0;
813     }
814 }
815
816 static void
817 predraw_set_foreground (GdkGC       *gc,
818                         GdkColormap *colormap,
819                         gboolean    *ok)
820 {
821   COLORREF fg;
822   LOGBRUSH logbrush;
823   HPEN hpen;
824   HBRUSH hbr;
825   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
826   GdkColormapPrivateWin32 *colormap_private;
827   gint k;
828
829   if (colormap &&
830       (colormap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
831        colormap->visual->type == GDK_VISUAL_STATIC_COLOR))
832     {
833       colormap_private = GDK_WIN32_COLORMAP_DATA (colormap);
834
835       g_assert (colormap_private != NULL);
836
837       if (!(win32_gc->holdpal = SelectPalette (win32_gc->hdc, colormap_private->hpal, FALSE)))
838         WIN32_GDI_FAILED ("SelectPalette"), *ok = FALSE;
839       else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR)
840         WIN32_GDI_FAILED ("RealizePalette"), *ok = FALSE;
841       else if (k > 0)
842         GDK_NOTE (COLORMAP, g_print ("predraw_set_foreground: realized %p: %d colors\n",
843                                      colormap_private->hpal, k));
844     }
845
846   fg = _gdk_win32_colormap_color (colormap, win32_gc->foreground);
847
848   GDK_NOTE (GC, g_print ("predraw_set_foreground: fg=%06lx\n", fg));
849
850   if (SetTextColor (win32_gc->hdc, fg) == CLR_INVALID)
851     WIN32_GDI_FAILED ("SetTextColor"), *ok = FALSE;
852
853   /* Create and select pen and brush. */
854
855   logbrush.lbStyle = BS_SOLID;
856   logbrush.lbColor = fg;
857   logbrush.lbHatch = 0;
858
859   if (*ok && (hpen = ExtCreatePen (win32_gc->pen_style,
860                                    (win32_gc->pen_width > 0 ? win32_gc->pen_width : 1),
861                                    &logbrush, 0, NULL)) == NULL)
862     WIN32_GDI_FAILED ("ExtCreatePen"), *ok = FALSE;
863   
864   if (*ok && SelectObject (win32_gc->hdc, hpen) == NULL)
865     WIN32_GDI_FAILED ("SelectObject"), *ok = FALSE;
866
867   switch (win32_gc->fill_style)
868     {
869     case GDK_OPAQUE_STIPPLED:
870       if (*ok && (hbr = CreatePatternBrush (GDK_PIXMAP_HBITMAP (win32_gc->stipple))) == NULL)
871         WIN32_GDI_FAILED ("CreatePatternBrush"), *ok = FALSE;
872       if (*ok && !SetBrushOrgEx(win32_gc->hdc, gc->ts_x_origin,
873                                 gc->ts_y_origin, NULL))
874         WIN32_GDI_FAILED ("SetBrushOrgEx"), *ok = FALSE;
875         
876       break;
877
878     case GDK_SOLID:
879     default:
880       if (*ok && (hbr = CreateSolidBrush (fg)) == NULL)
881         WIN32_GDI_FAILED ("CreateSolidBrush"), *ok = FALSE;
882       break;
883   }
884   if (*ok)
885     {
886       HBRUSH old_hbr = SelectObject (win32_gc->hdc, hbr);
887       if (old_hbr == NULL)
888         WIN32_GDI_FAILED ("SelectObject"), *ok = FALSE;
889     }
890 }  
891
892 static void
893 predraw_set_background (GdkGC       *gc,
894                         GdkColormap *colormap,
895                         gboolean    *ok)
896 {
897   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
898
899   if (win32_gc->values_mask & GDK_GC_BACKGROUND)
900     {
901       COLORREF bg = _gdk_win32_colormap_color (colormap, win32_gc->background);
902
903       if (SetBkColor (win32_gc->hdc, bg) == CLR_INVALID)
904         WIN32_GDI_FAILED ("SetBkColor"), *ok = FALSE;
905     }
906   else
907     {
908       if (!SetBkMode (win32_gc->hdc, TRANSPARENT))
909         WIN32_GDI_FAILED ("SetBkMode"), *ok = FALSE;
910     }
911 }
912
913 HDC
914 gdk_win32_hdc_get (GdkDrawable    *drawable,
915                    GdkGC          *gc,
916                    GdkGCValuesMask usage)
917 {
918   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
919   GdkDrawableImplWin32 *impl = NULL;
920   gboolean ok = TRUE;
921   int flag;
922
923   g_assert (win32_gc->hdc == NULL);
924
925   if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable))
926     impl = GDK_DRAWABLE_IMPL_WIN32(drawable);
927   else if (GDK_IS_WINDOW (drawable))
928     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_WINDOW_OBJECT (drawable))->impl);
929   else if (GDK_IS_PIXMAP (drawable))
930     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_PIXMAP_OBJECT (drawable))->impl);
931   else
932     g_assert_not_reached ();
933
934   win32_gc->hwnd = impl->handle;
935
936   if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
937     {
938       if ((win32_gc->hdc = CreateCompatibleDC (NULL)) == NULL)
939         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
940
941       if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0)
942         WIN32_GDI_FAILED ("SaveDC"), ok = FALSE;
943       
944       if (ok && SelectObject (win32_gc->hdc, win32_gc->hwnd) == NULL)
945         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
946     }
947   else
948     {
949       if ((win32_gc->hdc = GetDC (win32_gc->hwnd)) == NULL)
950         WIN32_GDI_FAILED ("GetDC");
951       
952       if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0)
953         WIN32_GDI_FAILED ("SaveDC");
954     }
955   
956   if (ok && (usage & GDK_GC_FOREGROUND))
957     predraw_set_foreground (gc, impl->colormap, &ok);
958
959   if (ok && (usage & GDK_GC_BACKGROUND))
960     predraw_set_background (gc, impl->colormap, &ok);
961   
962   if (ok && (usage & GDK_GC_FONT))
963     {
964       if (SetBkMode (win32_gc->hdc, TRANSPARENT) == 0)
965         WIN32_GDI_FAILED ("SetBkMode"), ok = FALSE;
966   
967       if (ok && SetTextAlign (win32_gc->hdc, TA_BASELINE) == GDI_ERROR)
968         WIN32_GDI_FAILED ("SetTextAlign"), ok = FALSE;
969     }
970   
971   if (ok && (win32_gc->values_mask & GDK_GC_FUNCTION))
972     if (SetROP2 (win32_gc->hdc, win32_gc->rop2) == 0)
973       WIN32_GDI_FAILED ("SetROP2"), ok = FALSE;
974
975   if (win32_gc->values_mask & GDK_GC_CLIP_MASK)
976     g_assert ((win32_gc->clip_region != NULL) != (win32_gc->hcliprgn != NULL));
977
978   if (ok
979       && (win32_gc->values_mask & GDK_GC_CLIP_MASK)
980       && win32_gc->clip_region != NULL)
981     {
982       HRGN hrgn;
983       RGNDATA *rgndata;
984       RECT *rect;
985       GdkRegionBox *boxes = win32_gc->clip_region->rects;
986       guint nbytes =
987         sizeof (RGNDATAHEADER) + (sizeof (RECT) * win32_gc->clip_region->numRects);
988       int i;
989
990       rgndata = g_malloc (nbytes);
991       rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
992       rgndata->rdh.iType = RDH_RECTANGLES;
993       rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
994       SetRect (&rgndata->rdh.rcBound,
995                G_MAXSHORT, G_MAXSHORT, G_MINSHORT, G_MINSHORT);
996
997       for (i = 0; i < win32_gc->clip_region->numRects; i++)
998         {
999           rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
1000
1001           rect->left = CLAMP (boxes[i].x1 + gc->clip_x_origin,
1002                               G_MINSHORT, G_MAXSHORT);
1003           rect->right = CLAMP (boxes[i].x2 + gc->clip_x_origin,
1004                                G_MINSHORT, G_MAXSHORT);
1005           rect->top = CLAMP (boxes[i].y1 + gc->clip_y_origin,
1006                              G_MINSHORT, G_MAXSHORT);
1007           rect->bottom = CLAMP (boxes[i].y2 + gc->clip_y_origin,
1008                                 G_MINSHORT, G_MAXSHORT);
1009
1010           GDK_NOTE (GC, g_print ("clip rgn box %d: %ldx%ld@+%ld+%ld\n",
1011                                  i,
1012                                  rect->right-rect->left,
1013                                  rect->bottom-rect->top,
1014                                  rect->left, rect->top));
1015
1016           if (rect->left < rgndata->rdh.rcBound.left)
1017             rgndata->rdh.rcBound.left = rect->left;
1018           if (rect->right > rgndata->rdh.rcBound.right)
1019             rgndata->rdh.rcBound.right = rect->right;
1020           if (rect->top < rgndata->rdh.rcBound.top)
1021             rgndata->rdh.rcBound.top = rect->top;
1022           if (rect->bottom > rgndata->rdh.rcBound.bottom)
1023             rgndata->rdh.rcBound.bottom = rect->bottom;
1024         }
1025       if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
1026         WIN32_API_FAILED ("ExtCreateRegion"), ok = FALSE;
1027
1028       /*
1029        * XXX: combine the fillmode-stipple with the clip region possibly 
1030        *  this needs to be done with the hcliprgn below as well, but 
1031        *  the test case here were check boxes and radio buttons ...
1032        */
1033       if (   (win32_gc->values_mask & GDK_GC_STIPPLE)
1034           && (win32_gc->values_mask & GDK_GC_FILL) && (win32_gc->fill_style == GDK_STIPPLED))
1035         {
1036           HRGN hstipplergn = _gdk_win32_bitmap_to_region (win32_gc->stipple);
1037
1038           if (OffsetRgn (hstipplergn, 
1039              win32_gc->values_mask & GDK_GC_TS_X_ORIGIN ? gc->ts_x_origin : 0,
1040              win32_gc->values_mask & GDK_GC_TS_Y_ORIGIN ? gc->ts_y_origin : 0) == ERROR)
1041             WIN32_API_FAILED ("OffsetRgn"), ok = FALSE;
1042           if (CombineRgn (hrgn, hrgn, hstipplergn, RGN_AND) == ERROR)
1043             WIN32_API_FAILED ("CombineRgn"), ok = FALSE;
1044           if (!DeleteObject (hstipplergn))
1045             WIN32_API_FAILED ("DeleteObject");
1046         }
1047       if (ok && SelectClipRgn (win32_gc->hdc, hrgn) == ERROR)
1048         WIN32_API_FAILED ("SelectClipRgn"), ok = FALSE;
1049
1050       if (hrgn != NULL)
1051         DeleteObject (hrgn);
1052     }
1053   else if (ok
1054            && (win32_gc->values_mask & GDK_GC_CLIP_MASK)
1055            && win32_gc->hcliprgn != NULL)
1056     {
1057       if (SelectClipRgn (win32_gc->hdc, win32_gc->hcliprgn) == ERROR)
1058         WIN32_API_FAILED ("SelectClipRgn"), ok = FALSE;
1059       if (ok && !OffsetClipRgn (win32_gc->hdc,
1060                  win32_gc->values_mask & GDK_GC_CLIP_X_ORIGIN ? gc->clip_x_origin : 0,
1061                  win32_gc->values_mask & GDK_GC_CLIP_Y_ORIGIN ? gc->clip_y_origin : 0))
1062         WIN32_API_FAILED ("OffsetClipRgn"), ok = FALSE;
1063     }
1064 #ifdef G_ENABLE_DEBUG
1065   if (_gdk_debug_flags & GDK_DEBUG_GC)
1066     {
1067       HGDIOBJ obj;
1068       LOGBRUSH logbrush;
1069       EXTLOGPEN extlogpen;
1070       HRGN hrgn;
1071       RECT rect;
1072
1073       g_print ("gdk_win32_hdc_get: %p\n", win32_gc->hdc);
1074       obj = GetCurrentObject (win32_gc->hdc, OBJ_BRUSH);
1075       GetObject (obj, sizeof (LOGBRUSH), &logbrush);
1076       g_print ("brush: style: %s color: %06lx hatch: %#lx\n",
1077                (logbrush.lbStyle == BS_HOLLOW ? "HOLLOW" :
1078                 (logbrush.lbStyle == BS_PATTERN ? "PATTERN" :
1079                  (logbrush.lbStyle == BS_SOLID ? "SOLID" :
1080                   "???"))),
1081                logbrush.lbColor,
1082                logbrush.lbHatch);
1083       obj = GetCurrentObject (win32_gc->hdc, OBJ_PEN);
1084       GetObject (obj, sizeof (EXTLOGPEN), &extlogpen);
1085       g_print ("pen: type: %s style: %s endcap: %s join: %s width: %d brush: %s\n",
1086                ((extlogpen.elpPenStyle & PS_TYPE_MASK) ==
1087                 PS_GEOMETRIC ? "GEOMETRIC" : "COSMETIC"),
1088                ((extlogpen.elpPenStyle & PS_STYLE_MASK) ==
1089                 PS_NULL ? "NULL" :
1090                 ((extlogpen.elpPenStyle & PS_STYLE_MASK) == PS_SOLID ? "SOLID" :
1091                  ((extlogpen.elpPenStyle & PS_STYLE_MASK) == PS_DOT ? "DOT" :
1092                   ((extlogpen.elpPenStyle & PS_STYLE_MASK) == PS_DASH ? "DASH" :
1093                    "???")))),
1094                ((extlogpen.elpPenStyle & PS_ENDCAP_MASK) ==
1095                 PS_ENDCAP_FLAT ? "FLAT" :
1096                 ((extlogpen.elpPenStyle & PS_ENDCAP_MASK) ==
1097                  PS_ENDCAP_ROUND ? "ROUND" :
1098                  ((extlogpen.elpPenStyle & PS_ENDCAP_MASK) ==
1099                   PS_ENDCAP_SQUARE ? "ROUND" :
1100                   ((extlogpen.elpPenStyle & PS_ENDCAP_MASK) ==
1101                    PS_ENDCAP_SQUARE ? "ROUND" : "???")))),
1102                ((extlogpen.elpPenStyle & PS_JOIN_MASK) ==
1103                 PS_JOIN_BEVEL ? "BEVEL" :
1104                 ((extlogpen.elpPenStyle & PS_JOIN_MASK) ==
1105                  PS_JOIN_MITER ? "MITER" :
1106                  ((extlogpen.elpPenStyle & PS_JOIN_MASK) ==
1107                   PS_JOIN_ROUND ? "ROUND" : "???"))),
1108                extlogpen.elpWidth,
1109                (extlogpen.elpBrushStyle == BS_DIBPATTERN ? "DIBPATTERN" :
1110                 (extlogpen.elpBrushStyle == BS_DIBPATTERNPT ? "DIBPATTERNPT" :
1111                  (extlogpen.elpBrushStyle == BS_HATCHED ? "HATCHED" :
1112                   (extlogpen.elpBrushStyle == BS_HOLLOW ? "HOLLOW" :
1113                    (extlogpen.elpBrushStyle == BS_PATTERN ? "PATTERN" :
1114                     (extlogpen.elpBrushStyle == BS_SOLID ? "SOLID" : "???")))))));
1115       hrgn = CreateRectRgn (0, 0, 0, 0);
1116       if ((flag = GetClipRgn (win32_gc->hdc, hrgn)) == -1)
1117         WIN32_API_FAILED ("GetClipRgn");
1118       else if (flag == 0)
1119         g_print ("no clip region\n");
1120       else if (flag == 1)
1121         {
1122           GetRgnBox (hrgn, &rect);
1123           g_print ("clip region bbox: %ldx%ld@+%ld+%ld\n",
1124                    rect.right - rect.left,
1125                    rect.bottom - rect.top,
1126                    rect.left, rect.top);
1127         }
1128       DeleteObject (hrgn);
1129     }
1130 #endif
1131   return win32_gc->hdc;
1132 }
1133
1134 void
1135 gdk_win32_hdc_release (GdkDrawable    *drawable,
1136                        GdkGC          *gc,
1137                        GdkGCValuesMask usage)
1138 {
1139   GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
1140   GdkDrawableImplWin32 *impl = NULL;
1141   HGDIOBJ hpen = NULL;
1142   HGDIOBJ hbr = NULL;
1143
1144   GDK_NOTE (GC, g_print ("gdk_win32_hdc_release: %p\n", win32_gc->hdc));
1145
1146   if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable))
1147     impl = GDK_DRAWABLE_IMPL_WIN32(drawable);
1148   else if (GDK_IS_WINDOW (drawable))
1149     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_WINDOW_OBJECT (drawable))->impl);
1150   else if (GDK_IS_PIXMAP (drawable))
1151     impl = GDK_DRAWABLE_IMPL_WIN32 ((GDK_PIXMAP_OBJECT (drawable))->impl);
1152   else
1153     g_assert_not_reached ();
1154
1155   if (win32_gc->holdpal != NULL)
1156     {
1157       gint k;
1158       
1159       if (!SelectPalette (win32_gc->hdc, win32_gc->holdpal, FALSE))
1160         WIN32_GDI_FAILED ("SelectPalette");
1161       else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR)
1162         WIN32_GDI_FAILED ("RealizePalette");
1163       else if (k > 0)
1164         GDK_NOTE (COLORMAP, g_print ("gdk_win32_hdc_release: realized %p: %d colors\n",
1165                                      win32_gc->holdpal, k));
1166       win32_gc->holdpal = NULL;
1167     }
1168
1169   if (usage & GDK_GC_FOREGROUND)
1170     {
1171       if ((hpen = GetCurrentObject (win32_gc->hdc, OBJ_PEN)) == NULL)
1172         WIN32_GDI_FAILED ("GetCurrentObject");
1173
1174       if ((hbr = GetCurrentObject (win32_gc->hdc, OBJ_BRUSH)) == NULL)
1175         WIN32_GDI_FAILED ("GetCurrentObject");
1176     }
1177
1178   if (!RestoreDC (win32_gc->hdc, win32_gc->saved_dc))
1179     WIN32_GDI_FAILED ("RestoreDC");
1180
1181   if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1182     {
1183       if (!DeleteDC (win32_gc->hdc))
1184         WIN32_GDI_FAILED ("DeleteDC");
1185     }
1186   else
1187     {
1188       if (!ReleaseDC (win32_gc->hwnd, win32_gc->hdc))
1189         WIN32_GDI_FAILED ("ReleaseDC");
1190     }
1191
1192   if (hpen != NULL)
1193     if (!DeleteObject (hpen))
1194       WIN32_GDI_FAILED ("DeleteObject");
1195   
1196   if (hbr != NULL)
1197     if (!DeleteObject (hbr))
1198       WIN32_GDI_FAILED ("DeleteObject");
1199
1200   win32_gc->hdc = NULL;
1201 }
1202
1203 /* This function originally from Jean-Edouard Lachand-Robert, and
1204  * available at www.codeguru.com. Simplified for our needs, not sure
1205  * how much of the original code left any longer. Now handles just
1206  * one-bit deep bitmaps (in Window parlance, ie those that GDK calls
1207  * bitmaps (and not pixmaps), with zero pixels being transparent.
1208  */
1209
1210 /* _gdk_win32_bitmap_to_region : Create a region from the
1211  * "non-transparent" pixels of a bitmap.
1212  */
1213
1214 HRGN
1215 _gdk_win32_bitmap_to_region (GdkPixmap *pixmap)
1216 {
1217   HRGN hRgn = NULL;
1218   HRGN h;
1219   DWORD maxRects;
1220   RGNDATA *pData;
1221   GdkImage *image;
1222   guchar *p;
1223   gint x, y;
1224
1225   image = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl)->image;
1226   g_assert (image->depth == 1);
1227
1228   /* For better performances, we will use the ExtCreateRegion()
1229    * function to create the region. This function take a RGNDATA
1230    * structure on entry. We will add rectangles by amount of
1231    * ALLOC_UNIT number in this structure.
1232    */
1233   #define ALLOC_UNIT  100
1234   maxRects = ALLOC_UNIT;
1235
1236   pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
1237   pData->rdh.dwSize = sizeof (RGNDATAHEADER);
1238   pData->rdh.iType = RDH_RECTANGLES;
1239   pData->rdh.nCount = pData->rdh.nRgnSize = 0;
1240   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1241
1242   for (y = 0; y < image->height; y++)
1243     {
1244       /* Scan each bitmap row from left to right*/
1245       p = (guchar *) image->mem + y * image->bpl;
1246       for (x = 0; x < image->width; x++)
1247         {
1248           /* Search for a continuous range of "non transparent pixels"*/
1249           gint x0 = x;
1250           while (x < image->width)
1251             {
1252               if ((((p[x/8])>>(7-(x%8)))&1) == 0)
1253                 /* This pixel is "transparent"*/
1254                 break;
1255               x++;
1256             }
1257           
1258           if (x > x0)
1259             {
1260               RECT *pr;
1261               /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
1262                * in the region
1263                */
1264               if (pData->rdh.nCount >= maxRects)
1265                 {
1266                   maxRects += ALLOC_UNIT;
1267                   pData = g_realloc (pData, sizeof(RGNDATAHEADER)
1268                                      + (sizeof(RECT) * maxRects));
1269                 }
1270               pr = (RECT *) &pData->Buffer;
1271               SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
1272               if (x0 < pData->rdh.rcBound.left)
1273                 pData->rdh.rcBound.left = x0;
1274               if (y < pData->rdh.rcBound.top)
1275                 pData->rdh.rcBound.top = y;
1276               if (x > pData->rdh.rcBound.right)
1277                 pData->rdh.rcBound.right = x;
1278               if (y+1 > pData->rdh.rcBound.bottom)
1279                 pData->rdh.rcBound.bottom = y+1;
1280               pData->rdh.nCount++;
1281               
1282               /* On Windows98, ExtCreateRegion() may fail if the
1283                * number of rectangles is too large (ie: >
1284                * 4000). Therefore, we have to create the region by
1285                * multiple steps.
1286                */
1287               if (pData->rdh.nCount == 2000)
1288                 {
1289                   HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
1290                   if (hRgn)
1291                     {
1292                       CombineRgn(hRgn, hRgn, h, RGN_OR);
1293                       DeleteObject(h);
1294                     }
1295                   else
1296                     hRgn = h;
1297                   pData->rdh.nCount = 0;
1298                   SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
1299                 }
1300             }
1301         }
1302     }
1303   
1304   /* Create or extend the region with the remaining rectangles*/
1305   h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
1306                        + (sizeof (RECT) * maxRects), pData);
1307   if (hRgn)
1308     {
1309       CombineRgn (hRgn, hRgn, h, RGN_OR);
1310       DeleteObject (h);
1311     }
1312   else
1313     hRgn = h;
1314
1315   /* Clean up*/
1316   g_free (pData);
1317
1318   return hRgn;
1319 }
1320
1321 #ifdef G_ENABLE_DEBUG
1322
1323 gchar *
1324 gdk_win32_cap_style_to_string (GdkCapStyle cap_style)
1325 {
1326   switch (cap_style)
1327     {
1328 #define CASE(x) case x: return #x + strlen ("GDK_CAP_")
1329     CASE (GDK_CAP_NOT_LAST);
1330     CASE (GDK_CAP_BUTT);
1331     CASE (GDK_CAP_ROUND);
1332     CASE (GDK_CAP_PROJECTING);
1333 #undef CASE
1334     default: return ("illegal GdkCapStyle value");
1335     }
1336   /* NOTREACHED */
1337   return NULL;
1338 }
1339
1340 gchar *
1341 gdk_win32_fill_style_to_string (GdkFill fill)
1342 {
1343   switch (fill)
1344     {
1345 #define CASE(x) case x: return #x + strlen ("GDK_")
1346     CASE (GDK_SOLID);
1347     CASE (GDK_TILED);
1348     CASE (GDK_STIPPLED);
1349     CASE (GDK_OPAQUE_STIPPLED);
1350 #undef CASE
1351     default: return ("illegal GdkFill value");
1352     }
1353   /* NOTREACHED */
1354   return NULL;
1355 }
1356
1357 gchar *
1358 gdk_win32_function_to_string (GdkFunction function)
1359 {
1360   switch (function)
1361     {
1362 #define CASE(x) case x: return #x + strlen ("GDK_")
1363     CASE (GDK_COPY);
1364     CASE (GDK_INVERT);
1365     CASE (GDK_XOR);
1366     CASE (GDK_CLEAR);
1367     CASE (GDK_AND);
1368     CASE (GDK_AND_REVERSE);
1369     CASE (GDK_AND_INVERT);
1370     CASE (GDK_NOOP);
1371     CASE (GDK_OR);
1372     CASE (GDK_EQUIV);
1373     CASE (GDK_OR_REVERSE);
1374     CASE (GDK_COPY_INVERT);
1375     CASE (GDK_OR_INVERT);
1376     CASE (GDK_NAND);
1377     CASE (GDK_SET);
1378 #undef CASE
1379     default: return ("illegal GdkFunction value");
1380     }
1381   /* NOTREACHED */
1382   return NULL; 
1383 }
1384
1385 gchar *
1386 gdk_win32_join_style_to_string (GdkJoinStyle join_style)
1387 {
1388   switch (join_style)
1389     {
1390 #define CASE(x) case x: return #x + strlen ("GDK_JOIN_")
1391     CASE (GDK_JOIN_MITER);
1392     CASE (GDK_JOIN_ROUND);
1393     CASE (GDK_JOIN_BEVEL);
1394 #undef CASE
1395     default: return ("illegal GdkJoinStyle value");
1396     }
1397   /* NOTREACHED */
1398   return NULL; 
1399 }
1400
1401 gchar *
1402 gdk_win32_line_style_to_string (GdkLineStyle line_style)
1403 {
1404   switch (line_style)
1405     {
1406 #define CASE(x) case x: return #x + strlen ("GDK_LINE_")
1407     CASE(GDK_LINE_SOLID);
1408     CASE(GDK_LINE_ON_OFF_DASH);  
1409     CASE(GDK_LINE_DOUBLE_DASH);  
1410 #undef CASE
1411     default: return ("illegal GdkLineStyle value");
1412     }
1413   /* NOTREACHED */
1414   return NULL; 
1415 }
1416
1417 #endif