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