]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Build Wintab support always on Windows. Don't require the Wintab SDK.
[~andy/gtk] / gdk / win32 / gdkdrawable-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2004 Tor Lillqvist
4  * Copyright (C) 2001-2005 Hans Breuer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
24  * file for a list of people on the GTK+ Team.  See the ChangeLog
25  * files for a list of changes.  These files are distributed with
26  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
27  */
28
29 #include <config.h>
30 #include <math.h>
31 #include <stdio.h>
32 #include <glib.h>
33
34 #include <pango/pangowin32.h>
35 #include <cairo-win32.h>
36
37 #include "gdkscreen.h" /* gdk_screen_get_default() */
38 #include "gdkregion-generic.h"
39 #include "gdkprivate-win32.h"
40
41 #define ROP3_D 0x00AA0029
42 #define ROP3_DSna 0x00220326
43 #define ROP3_DSPDxax 0x00E20746
44
45 #define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
46                          GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
47
48 #define MUST_RENDER_DASHES_MANUALLY(gcwin32)                    \
49   (gcwin32->line_style == GDK_LINE_DOUBLE_DASH ||               \
50    (gcwin32->line_style == GDK_LINE_ON_OFF_DASH && gcwin32->pen_dash_offset))
51
52 static void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
53                                       GdkGC          *gc,
54                                       gboolean        filled,
55                                       gint            x,
56                                       gint            y,
57                                       gint            width,
58                                       gint            height);
59 static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
60                                       GdkGC          *gc,
61                                       gboolean        filled,
62                                       gint            x,
63                                       gint            y,
64                                       gint            width,
65                                       gint            height,
66                                       gint            angle1,
67                                       gint            angle2);
68 static void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
69                                       GdkGC          *gc,
70                                       gboolean        filled,
71                                       GdkPoint       *points,
72                                       gint            npoints);
73 static void gdk_win32_draw_text      (GdkDrawable    *drawable,
74                                       GdkFont        *font,
75                                       GdkGC          *gc,
76                                       gint            x,
77                                       gint            y,
78                                       const gchar    *text,
79                                       gint            text_length);
80 static void gdk_win32_draw_text_wc   (GdkDrawable    *drawable,
81                                       GdkFont        *font,
82                                       GdkGC          *gc,
83                                       gint            x,
84                                       gint            y,
85                                       const GdkWChar *text,
86                                       gint            text_length);
87 static void gdk_win32_draw_drawable  (GdkDrawable    *drawable,
88                                       GdkGC          *gc,
89                                       GdkPixmap      *src,
90                                       gint            xsrc,
91                                       gint            ysrc,
92                                       gint            xdest,
93                                       gint            ydest,
94                                       gint            width,
95                                       gint            height);
96 static void gdk_win32_draw_points    (GdkDrawable    *drawable,
97                                       GdkGC          *gc,
98                                       GdkPoint       *points,
99                                       gint            npoints);
100 static void gdk_win32_draw_segments  (GdkDrawable    *drawable,
101                                       GdkGC          *gc,
102                                       GdkSegment     *segs,
103                                       gint            nsegs);
104 static void gdk_win32_draw_lines     (GdkDrawable    *drawable,
105                                       GdkGC          *gc,
106                                       GdkPoint       *points,
107                                       gint            npoints);
108 static void gdk_win32_draw_image     (GdkDrawable     *drawable,
109                                       GdkGC           *gc,
110                                       GdkImage        *image,
111                                       gint             xsrc,
112                                       gint             ysrc,
113                                       gint             xdest,
114                                       gint             ydest,
115                                       gint             width,
116                                       gint             height);
117
118 static cairo_surface_t *gdk_win32_ref_cairo_surface (GdkDrawable *drawable);
119      
120 static void gdk_win32_set_colormap   (GdkDrawable    *drawable,
121                                       GdkColormap    *colormap);
122
123 static GdkColormap* gdk_win32_get_colormap   (GdkDrawable    *drawable);
124
125 static gint         gdk_win32_get_depth      (GdkDrawable    *drawable);
126
127 static GdkScreen *  gdk_win32_get_screen     (GdkDrawable    *drawable);
128
129 static GdkVisual*   gdk_win32_get_visual     (GdkDrawable    *drawable);
130
131 static void gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass);
132
133 static void gdk_drawable_impl_win32_finalize   (GObject *object);
134
135 static gpointer parent_class = NULL;
136 static const cairo_user_data_key_t gdk_win32_cairo_key;
137
138 GType
139 gdk_drawable_impl_win32_get_type (void)
140 {
141   static GType object_type = 0;
142
143   if (!object_type)
144     {
145       static const GTypeInfo object_info =
146       {
147         sizeof (GdkDrawableImplWin32Class),
148         (GBaseInitFunc) NULL,
149         (GBaseFinalizeFunc) NULL,
150         (GClassInitFunc) gdk_drawable_impl_win32_class_init,
151         NULL,           /* class_finalize */
152         NULL,           /* class_data */
153         sizeof (GdkDrawableImplWin32),
154         0,              /* n_preallocs */
155         (GInstanceInitFunc) NULL,
156       };
157       
158       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
159                                             "GdkDrawableImplWin32",
160                                             &object_info, 0);
161     }
162   
163   return object_type;
164 }
165
166 static void
167 gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
168 {
169   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
170   GObjectClass *object_class = G_OBJECT_CLASS (klass);
171
172   parent_class = g_type_class_peek_parent (klass);
173
174   object_class->finalize = gdk_drawable_impl_win32_finalize;
175
176   drawable_class->create_gc = _gdk_win32_gc_new;
177   drawable_class->draw_rectangle = gdk_win32_draw_rectangle;
178   drawable_class->draw_arc = gdk_win32_draw_arc;
179   drawable_class->draw_polygon = gdk_win32_draw_polygon;
180   drawable_class->draw_text = gdk_win32_draw_text;
181   drawable_class->draw_text_wc = gdk_win32_draw_text_wc;
182   drawable_class->draw_drawable = gdk_win32_draw_drawable;
183   drawable_class->draw_points = gdk_win32_draw_points;
184   drawable_class->draw_segments = gdk_win32_draw_segments;
185   drawable_class->draw_lines = gdk_win32_draw_lines;
186   drawable_class->draw_image = gdk_win32_draw_image;
187   
188   drawable_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
189   
190   drawable_class->set_colormap = gdk_win32_set_colormap;
191   drawable_class->get_colormap = gdk_win32_get_colormap;
192
193   drawable_class->get_depth = gdk_win32_get_depth;
194   drawable_class->get_screen = gdk_win32_get_screen;
195   drawable_class->get_visual = gdk_win32_get_visual;
196
197   drawable_class->_copy_to_image = _gdk_win32_copy_to_image;
198 }
199
200 static void
201 gdk_drawable_impl_win32_finalize (GObject *object)
202 {
203   gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
204
205   G_OBJECT_CLASS (parent_class)->finalize (object);
206 }
207
208 /*****************************************************
209  * Win32 specific implementations of generic functions *
210  *****************************************************/
211
212 static GdkColormap*
213 gdk_win32_get_colormap (GdkDrawable *drawable)
214 {
215   return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
216 }
217
218 static void
219 gdk_win32_set_colormap (GdkDrawable *drawable,
220                         GdkColormap *colormap)
221 {
222   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
223
224   if (impl->colormap == colormap)
225     return;
226   
227   if (impl->colormap)
228     gdk_colormap_unref (impl->colormap);
229   impl->colormap = colormap;
230   if (impl->colormap)
231     gdk_colormap_ref (impl->colormap);
232 }
233
234 /* Drawing
235  */
236
237 static int
238 rop2_to_rop3 (int rop2)
239 {
240   switch (rop2)
241     {
242     /* Oh, Microsoft's silly names for binary and ternary rops. */
243 #define CASE(rop2,rop3) case R2_##rop2: return rop3
244       CASE (BLACK, BLACKNESS);
245       CASE (NOTMERGEPEN, NOTSRCERASE);
246       CASE (MASKNOTPEN, 0x00220326);
247       CASE (NOTCOPYPEN, NOTSRCCOPY);
248       CASE (MASKPENNOT, SRCERASE);
249       CASE (NOT, DSTINVERT);
250       CASE (XORPEN, SRCINVERT);
251       CASE (NOTMASKPEN, 0x007700E6);
252       CASE (MASKPEN, SRCAND);
253       CASE (NOTXORPEN, 0x00990066);
254       CASE (NOP, 0x00AA0029);
255       CASE (MERGENOTPEN, MERGEPAINT);
256       CASE (COPYPEN, SRCCOPY);
257       CASE (MERGEPENNOT, 0x00DD0228);
258       CASE (MERGEPEN, SRCPAINT);
259       CASE (WHITE, WHITENESS);
260 #undef CASE
261     default: return SRCCOPY;
262     }
263 }
264
265 static int
266 rop2_to_patblt_rop (int rop2)
267 {
268   switch (rop2)
269     {
270 #define CASE(rop2,patblt_rop) case R2_##rop2: return patblt_rop
271       CASE (COPYPEN, PATCOPY);
272       CASE (XORPEN, PATINVERT);
273       CASE (NOT, DSTINVERT);
274       CASE (BLACK, BLACKNESS);
275       CASE (WHITE, WHITENESS);
276 #undef CASE
277     default:
278       g_warning ("Unhandled rop2 in GC to be used in PatBlt: %#x", rop2);
279       return PATCOPY;
280     }
281 }
282
283 static inline int
284 align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
285 {
286   int      n = 0;
287   int    len_sum = 0;
288   /* 
289    * We can't simply add the dashoffset, it can be an arbitrary larger
290    * or smaller value not even between x1 and x2. It just says use the
291    * dash pattern aligned to the offset. So ensure x1 is smaller _x1
292    * and we start with the appropriate dash.
293    */
294   for (n = 0; n < num_dashes; n++)
295     len_sum += dashes[n];
296   if (   len_sum > 0 /* pathological api usage? */
297       && gcwin32->pen_dash_offset > a)
298     a -= (((gcwin32->pen_dash_offset/len_sum - a/len_sum) + 1) * len_sum);
299   else
300     a = gcwin32->pen_dash_offset;
301
302   return a;
303 }
304  
305 /* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
306  * GDI is way too limited), and for double dashes on all Windowses.
307  */
308 static inline gboolean
309 render_line_horizontal (GdkGCWin32 *gcwin32,
310                         int         x1,
311                         int         x2,
312                         int         y)
313 {
314   int n = 0;
315   const int pen_width = MAX (gcwin32->pen_width, 1);
316   const int _x1 = x1;
317
318   g_assert (gcwin32->pen_dashes);
319
320   x1 = align_with_dash_offset (x1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
321
322   for (n = 0; x1 < x2; n++)
323     {
324       int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
325       if (x1 + len > x2)
326         len = x2 - x1;
327
328       if (n % 2 == 0 && x1 + len > _x1)
329         if (!GDI_CALL (PatBlt, (gcwin32->hdc, 
330                                 x1 < _x1 ? _x1 : x1, 
331                                 y - pen_width / 2, 
332                                 len, pen_width, 
333                                 rop2_to_patblt_rop (gcwin32->rop2))))
334           return FALSE;
335
336       x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
337     }
338
339   if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
340     {
341       HBRUSH hbr;
342
343       if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
344         return FALSE;
345       x1 = _x1;
346       x1 += gcwin32->pen_dash_offset;
347       for (n = 0; x1 < x2; n++)
348         {
349           int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
350           if (x1 + len > x2)
351             len = x2 - x1;
352
353           if (n % 2)
354             if (!GDI_CALL (PatBlt, (gcwin32->hdc, x1, y - pen_width / 2,
355                                     len, pen_width,
356                                     rop2_to_patblt_rop (gcwin32->rop2))))
357               return FALSE;
358
359           x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
360         }
361       if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
362         return FALSE;
363     }
364
365   return TRUE;
366 }
367
368 static inline gboolean
369 render_line_vertical (GdkGCWin32 *gcwin32,
370                       int         x,
371                       int         y1,
372                       int         y2)
373 {
374   int n;
375   const int pen_width = MAX (gcwin32->pen_width, 1);
376   const int _y1 = y1;
377
378   g_assert (gcwin32->pen_dashes);
379
380   y1 = align_with_dash_offset (y1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
381   for (n = 0; y1 < y2; n++)
382     {
383       int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
384       if (y1 + len > y2)
385         len = y2 - y1;
386       if (n % 2 == 0 && y1 + len > _y1)
387         if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, 
388                                 y1 < _y1 ? _y1 : y1, 
389                                 pen_width, len, 
390                                 rop2_to_patblt_rop (gcwin32->rop2))))
391           return FALSE;
392
393       y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
394     }
395
396   if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
397     {
398       HBRUSH hbr;
399
400       if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
401         return FALSE;
402       y1 = _y1;
403       y1 += gcwin32->pen_dash_offset;
404       for (n = 0; y1 < y2; n++)
405         {
406           int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
407           if (y1 + len > y2)
408             len = y2 - y1;
409           if (n % 2)
410             if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, y1,
411                                     pen_width, len,
412                                     rop2_to_patblt_rop (gcwin32->rop2))))
413               return FALSE;
414
415           y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
416         }
417       if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
418         return FALSE;
419     }
420
421   return TRUE;
422 }
423
424 static void
425 draw_tiles_lowlevel (HDC  dest,
426                      HDC  tile,
427                      int  rop3,
428                      gint dest_x,
429                      gint dest_y,
430                      gint tile_x_origin,
431                      gint tile_y_origin,
432                      gint width,
433                      gint height,
434                      gint tile_width,
435                      gint tile_height)
436 {
437   gint x, y;
438
439   GDK_NOTE (DRAW, g_print ("draw_tiles_lowlevel: %p %+d%+d tile=%p:%dx%d@%+d%+d %dx%d\n",
440                            dest,
441                            dest_x, dest_y,
442                            tile, tile_width, tile_height,
443                            tile_x_origin, tile_y_origin,
444                            width, height));
445
446   y = tile_y_origin % tile_height;
447   if (y > 0)
448     y -= tile_height;
449   while (y < dest_y + height)
450     {
451       if (y + tile_height >= dest_y)
452         {
453           x = tile_x_origin % tile_width;
454           if (x > 0)
455             x -= tile_width;
456           while (x < dest_x + width)
457             {
458               if (x + tile_width >= dest_x)
459                 {
460                   gint src_x = MAX (0, dest_x - x);
461                   gint src_y = MAX (0, dest_y - y);
462
463                   if (!GDI_CALL (BitBlt, (dest, x + src_x, y + src_y,
464                                           MIN (tile_width, dest_x + width - (x + src_x)),
465                                           MIN (tile_height, dest_y + height - (y + src_y)),
466                                           tile,
467                                           src_x, src_y,
468                                           rop3)))
469                     return;
470                 }
471               x += tile_width;
472             }
473         }
474       y += tile_height;
475     }
476 }
477
478 static void
479 draw_tiles (GdkDrawable *drawable,
480             GdkGC       *gc,
481             int          rop3,
482             GdkPixmap   *tile,
483             gint         dest_x,
484             gint         dest_y,
485             gint         tile_x_origin,
486             gint         tile_y_origin,
487             gint         width,
488             gint         height)
489 {
490   const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
491   gint tile_width, tile_height;
492   GdkGC *gc_copy;
493   HDC dest_hdc, tile_hdc;
494
495   gc_copy = gdk_gc_new (tile);
496   gdk_gc_copy (gc_copy, gc);
497   dest_hdc = gdk_win32_hdc_get (drawable, gc, mask);
498   tile_hdc = gdk_win32_hdc_get (tile, gc_copy, mask);
499
500   gdk_drawable_get_size (tile, &tile_width, &tile_height);
501
502   draw_tiles_lowlevel (dest_hdc, tile_hdc, rop3,
503                        dest_x, dest_y, tile_x_origin, tile_y_origin,
504                        width, height, tile_width, tile_height);
505
506   gdk_win32_hdc_release (drawable, gc, mask);
507   gdk_win32_hdc_release (tile, gc_copy, mask);
508   gdk_gc_unref (gc_copy);
509 }
510
511 static void
512 generic_draw (GdkDrawable    *drawable,
513               GdkGC          *gc,
514               GdkGCValuesMask mask,
515               void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
516               const GdkRegion *region,
517               ...)
518 {
519   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
520   GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
521   HDC hdc;
522   va_list args;
523   GdkFill fill_style = _gdk_gc_get_fill (gc);
524
525   va_start (args, region);
526
527   /* If tiled or stippled, draw to a temp pixmap and do blitting magic.
528    */
529
530   if (gcwin32->values_mask & GDK_GC_FILL &&
531       ((fill_style == GDK_TILED &&
532         gcwin32->values_mask & GDK_GC_TILE &&
533         _gdk_gc_get_tile (gc) != NULL)
534        ||
535        ((fill_style == GDK_OPAQUE_STIPPLED ||
536          fill_style == GDK_STIPPLED) &&
537         gcwin32->values_mask & GDK_GC_STIPPLE &&
538         _gdk_gc_get_stipple (gc) != NULL)))
539     {
540       const GdkGCValuesMask blitting_mask = 0;
541       GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
542       gint ts_x_origin = 0, ts_y_origin = 0;
543
544       gint width = region->extents.x2 - region->extents.x1;
545       gint height = region->extents.y2 - region->extents.y1;
546
547       GdkPixmap *mask_pixmap =
548         gdk_pixmap_new (drawable, width, height, 1);
549       GdkPixmap *tile_pixmap =
550         gdk_pixmap_new (drawable, width, height, -1);
551       GdkPixmap *stipple_bitmap = NULL;
552       GdkColor fg;
553       
554       GdkGC *mask_gc = gdk_gc_new (mask_pixmap);
555       GdkGC *tile_gc = gdk_gc_new (tile_pixmap);
556
557       HDC mask_hdc;
558       HDC tile_hdc;
559
560       HGDIOBJ old_mask_hbm;
561       HGDIOBJ old_tile_hbm;
562
563       GdkGCValues gcvalues;
564
565       hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
566       tile_hdc = CreateCompatibleDC (hdc);
567
568       if (gcwin32->values_mask & GDK_GC_TS_X_ORIGIN)
569         ts_x_origin = gc->ts_x_origin;
570       if (gcwin32->values_mask & GDK_GC_TS_Y_ORIGIN)
571         ts_y_origin = gc->ts_y_origin;
572
573       ts_x_origin -= region->extents.x1;
574       ts_y_origin -= region->extents.y1;
575
576       /* Fill mask bitmap with zeros */
577       gdk_gc_set_function (mask_gc, GDK_CLEAR);
578       gdk_draw_rectangle (mask_pixmap, mask_gc, TRUE,
579                           0, 0, width, height);
580
581       /* Paint into mask bitmap, drawing ones */
582       gdk_gc_set_function (mask_gc, GDK_COPY);
583       fg.pixel = 1;
584       gdk_gc_set_foreground (mask_gc, &fg);
585
586       /* If the drawing function uses line attributes, set them as in
587        * the real GC.
588        */
589       if (mask & LINE_ATTRIBUTES)
590         {
591           gdk_gc_get_values (gc, &gcvalues);
592           if (gcvalues.line_width != 0 ||
593               gcvalues.line_style != GDK_LINE_SOLID ||
594               gcvalues.cap_style != GDK_CAP_BUTT ||
595               gcvalues.join_style != GDK_JOIN_MITER)
596             gdk_gc_set_line_attributes (mask_gc,
597                                         gcvalues.line_width,
598                                         gcvalues.line_style,
599                                         gcvalues.cap_style,
600                                         gcvalues.join_style);
601           drawing_mask |= LINE_ATTRIBUTES;
602         }
603
604       /* Ditto, if the drawing function draws text, set up for that. */
605       if (mask & GDK_GC_FONT)
606         drawing_mask |= GDK_GC_FONT;
607
608       mask_hdc = gdk_win32_hdc_get (mask_pixmap, mask_gc, drawing_mask);
609       (*function) (GDK_GC_WIN32 (mask_gc), mask_hdc,
610                    region->extents.x1, region->extents.y1, args);
611       gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
612
613       if (fill_style == GDK_TILED)
614         {
615           /* Tile pixmap with tile */
616           draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
617                       _gdk_gc_get_tile (gc),
618                       0, 0, ts_x_origin, ts_y_origin,
619                       width, height);
620         }
621       else
622         {
623           /* Tile with stipple */
624           GdkGC *stipple_gc;
625
626           stipple_bitmap = gdk_pixmap_new (NULL, width, height, 1);
627           stipple_gc = gdk_gc_new (stipple_bitmap);
628
629           /* Tile stipple bitmap */
630           draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
631                       _gdk_gc_get_stipple (gc),
632                       0, 0, ts_x_origin, ts_y_origin,
633                       width, height);
634
635           if (fill_style == GDK_OPAQUE_STIPPLED)
636             {
637               /* Fill tile pixmap with background */
638               fg.pixel = _gdk_gc_get_bg_pixel (gc);
639               gdk_gc_set_foreground (tile_gc, &fg);
640               gdk_draw_rectangle (tile_pixmap, tile_gc, TRUE,
641                                   0, 0, width, height);
642             }
643           gdk_gc_unref (stipple_gc);
644         }
645
646       gdk_gc_unref (mask_gc);
647       gdk_gc_unref (tile_gc);
648
649       mask_hdc = CreateCompatibleDC (hdc);
650
651       if ((old_mask_hbm = SelectObject (mask_hdc, GDK_PIXMAP_HBITMAP (mask_pixmap))) == NULL)
652         WIN32_GDI_FAILED ("SelectObject");
653
654       if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
655         WIN32_GDI_FAILED ("SelectObject");
656
657       if (fill_style == GDK_STIPPLED ||
658           fill_style == GDK_OPAQUE_STIPPLED)
659         {
660           HDC stipple_hdc;
661           HGDIOBJ old_stipple_hbm;
662           HBRUSH fg_brush;
663           HGDIOBJ old_tile_brush;
664
665           if ((stipple_hdc = CreateCompatibleDC (hdc)) == NULL)
666             WIN32_GDI_FAILED ("CreateCompatibleDC");
667
668           if ((old_stipple_hbm =
669                SelectObject (stipple_hdc,
670                              GDK_PIXMAP_HBITMAP (stipple_bitmap))) == NULL)
671             WIN32_GDI_FAILED ("SelectObject");
672
673           if ((fg_brush = CreateSolidBrush
674                (_gdk_win32_colormap_color (impl->colormap,
675                                            _gdk_gc_get_fg_pixel (gc)))) == NULL)
676             WIN32_GDI_FAILED ("CreateSolidBrush");
677
678           if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
679             WIN32_GDI_FAILED ("SelectObject");
680
681           /* Paint tile with foreround where stipple is one
682            *
683            *  Desired ternary ROP: (P=foreground, S=stipple, D=destination)
684            *   P   S   D   ?
685            *   0   0   0   0
686            *   0   0   1   1
687            *   0   1   0   0
688            *   0   1   1   0
689            *   1   0   0   0
690            *   1   0   1   1
691            *   1   1   0   1
692            *   1   1   1   1
693            *
694            * Reading bottom-up: 11100010 = 0xE2. PSDK docs say this is
695            * known as DSPDxax, with hex value 0x00E20746.
696            */
697           GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
698                              stipple_hdc, 0, 0, ROP3_DSPDxax));
699
700           if (fill_style == GDK_STIPPLED)
701             {
702               /* Punch holes in mask where stipple is zero */
703               GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
704                                  stipple_hdc, 0, 0, SRCAND));
705             }
706
707           GDI_CALL (SelectObject, (tile_hdc, old_tile_brush));
708           GDI_CALL (DeleteObject, (fg_brush));
709           GDI_CALL (SelectObject, (stipple_hdc, old_stipple_hbm));
710           GDI_CALL (DeleteDC, (stipple_hdc));
711           g_object_unref (stipple_bitmap);
712         }
713
714       /* Tile pixmap now contains the pattern that we should paint in
715        * the areas where mask is one. (It is filled with said pattern.)
716        */
717
718       GDI_CALL (MaskBlt, (hdc, region->extents.x1, region->extents.y1,
719                           width, height,
720                           tile_hdc, 0, 0,
721                           GDK_PIXMAP_HBITMAP (mask_pixmap), 0, 0,
722                           MAKEROP4 (rop2_to_rop3 (gcwin32->rop2), ROP3_D)));
723
724       /* Cleanup */
725       GDI_CALL (SelectObject, (mask_hdc, old_mask_hbm));
726       GDI_CALL (SelectObject, (tile_hdc, old_tile_hbm));
727       GDI_CALL (DeleteDC, (mask_hdc));
728       GDI_CALL (DeleteDC, (tile_hdc));
729       g_object_unref (mask_pixmap);
730       g_object_unref (tile_pixmap);
731
732       gdk_win32_hdc_release (drawable, gc, blitting_mask);
733     }
734   else
735     {
736       hdc = gdk_win32_hdc_get (drawable, gc, mask);
737       (*function) (gcwin32, hdc, 0, 0, args);
738       gdk_win32_hdc_release (drawable, gc, mask);
739     }
740   va_end (args);
741 }
742
743 static GdkRegion *
744 widen_bounds (GdkRectangle *bounds,
745               gint          pen_width)
746 {
747   if (pen_width == 0)
748     pen_width = 1;
749
750   bounds->x -= pen_width;
751   bounds->y -= pen_width;
752   bounds->width += 2 * pen_width;
753   bounds->height += 2 * pen_width;
754
755   return gdk_region_rectangle (bounds);
756 }
757
758 static void
759 draw_rectangle (GdkGCWin32 *gcwin32,
760                 HDC         hdc,
761                 gint        x_offset,
762                 gint        y_offset,
763                 va_list     args)
764 {
765   HGDIOBJ old_pen_or_brush;
766   gboolean filled;
767   gint x;
768   gint y;
769   gint width;
770   gint height;
771
772   filled = va_arg (args, gboolean);
773   x = va_arg (args, gint);
774   y = va_arg (args, gint);
775   width = va_arg (args, gint);
776   height = va_arg (args, gint);
777   
778   x -= x_offset;
779   y -= y_offset;
780
781   if (!filled && MUST_RENDER_DASHES_MANUALLY (gcwin32))
782     {
783       render_line_vertical (gcwin32, x, y, y+height+1) &&
784       render_line_horizontal (gcwin32, x, x+width+1, y) &&
785       render_line_vertical (gcwin32, x+width+1, y, y+height+1) &&
786       render_line_horizontal (gcwin32, x, x+width+1, y+height+1);
787     }
788   else
789     {
790       if (filled)
791         old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
792       else
793         old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
794       if (old_pen_or_brush == NULL)
795         WIN32_GDI_FAILED ("SelectObject");
796       else
797         GDI_CALL (Rectangle, (hdc, x, y, x+width+1, y+height+1));
798
799       if (old_pen_or_brush != NULL)
800         GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
801     }
802 }
803
804 static void
805 gdk_win32_draw_rectangle (GdkDrawable *drawable,
806                           GdkGC       *gc,
807                           gboolean     filled,
808                           gint         x,
809                           gint         y,
810                           gint         width,
811                           gint         height)
812 {
813   GdkRectangle bounds;
814   GdkRegion *region;
815
816   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_rectangle: %s (%p) %s%dx%d@%+d%+d\n",
817                            _gdk_win32_drawable_description (drawable),
818                            gc,
819                            (filled ? "fill " : ""),
820                            width, height, x, y));
821     
822   bounds.x = x;
823   bounds.y = y;
824   bounds.width = width;
825   bounds.height = height;
826   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
827
828   generic_draw (drawable, gc,
829                 GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
830                 (filled ? 0 : LINE_ATTRIBUTES),
831                 draw_rectangle, region, filled, x, y, width, height);
832
833   gdk_region_destroy (region);
834 }
835
836 static void
837 draw_arc (GdkGCWin32 *gcwin32,
838           HDC         hdc,
839           gint        x_offset,
840           gint        y_offset,
841           va_list     args)
842 {
843   HGDIOBJ old_pen;
844   gboolean filled;
845   gint x, y;
846   gint width, height;
847   gint angle1, angle2;
848   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
849
850   filled = va_arg (args, gboolean);
851   x = va_arg (args, gint);
852   y = va_arg (args, gint);
853   width = va_arg (args, gint);
854   height = va_arg (args, gint);
855   angle1 = va_arg (args, gint);
856   angle2 = va_arg (args, gint);
857
858   x -= x_offset;
859   y -= y_offset;
860   
861   if (angle2 >= 360*64)
862     {
863       nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
864     }
865   else if (angle2 > 0)
866     {
867       nXStartArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
868       nYStartArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
869       nXEndArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
870       nYEndArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
871     }
872   else
873     {
874       nXEndArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
875       nYEndArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
876       nXStartArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
877       nYStartArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
878     }
879   
880   if (filled)
881     {
882       old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
883       GDK_NOTE (DRAW, g_print ("... Pie(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
884                                hdc, x, y, x+width, y+height,
885                                nXStartArc, nYStartArc, nXEndArc, nYEndArc));
886       GDI_CALL (Pie, (hdc, x, y, x+width, y+height,
887                       nXStartArc, nYStartArc, nXEndArc, nYEndArc));
888       GDI_CALL (SelectObject, (hdc, old_pen));
889     }
890   else
891     {
892       GDK_NOTE (DRAW, g_print ("... Arc(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
893                                hdc, x, y, x+width, y+height,
894                                nXStartArc, nYStartArc, nXEndArc, nYEndArc));
895       GDI_CALL (Arc, (hdc, x, y, x+width, y+height,
896                       nXStartArc, nYStartArc, nXEndArc, nYEndArc));
897     }
898 }
899
900 static void
901 gdk_win32_draw_arc (GdkDrawable *drawable,
902                     GdkGC       *gc,
903                     gboolean     filled,
904                     gint         x,
905                     gint         y,
906                     gint         width,
907                     gint         height,
908                     gint         angle1,
909                     gint         angle2)
910 {
911   GdkRectangle bounds;
912   GdkRegion *region;
913
914   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_arc: %s  %d,%d,%d,%d  %d %d\n",
915                            _gdk_win32_drawable_description (drawable),
916                            x, y, width, height, angle1, angle2));
917
918   if (width <= 2 || height <= 2 || angle2 == 0)
919     return;
920
921   bounds.x = x;
922   bounds.y = y;
923   bounds.width = width;
924   bounds.height = height;
925   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
926
927   generic_draw (drawable, gc,
928                 GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
929                 draw_arc, region, filled, x, y, width, height, angle1, angle2);
930
931   gdk_region_destroy (region);
932 }
933
934 static void
935 draw_polygon (GdkGCWin32 *gcwin32,
936               HDC         hdc,
937               gint        x_offset,
938               gint        y_offset,
939               va_list     args)
940 {
941   gboolean filled;
942   POINT *pts;
943   HGDIOBJ old_pen_or_brush;
944   gint npoints;
945   gint i;
946
947   filled = va_arg (args, gboolean);
948   pts = va_arg (args, POINT *);
949   npoints = va_arg (args, gint);
950
951   if (x_offset != 0 || y_offset != 0)
952     for (i = 0; i < npoints; i++)
953       {
954         pts[i].x -= x_offset;
955         pts[i].y -= y_offset;
956       }
957
958   if (filled)
959     old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
960   else
961     old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
962   if (old_pen_or_brush == NULL)
963     WIN32_GDI_FAILED ("SelectObject");
964   GDI_CALL (Polygon, (hdc, pts, npoints));
965   if (old_pen_or_brush != NULL)
966     GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
967 }
968
969 static void
970 gdk_win32_draw_polygon (GdkDrawable *drawable,
971                         GdkGC       *gc,
972                         gboolean     filled,
973                         GdkPoint    *points,
974                         gint         npoints)
975 {
976   GdkRectangle bounds;
977   GdkRegion *region;
978   POINT *pts;
979   int i;
980
981   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_polygon: %s %d points\n",
982                            _gdk_win32_drawable_description (drawable),
983                            npoints));
984
985   if (npoints < 2)
986     return;
987
988   bounds.x = G_MAXINT;
989   bounds.y = G_MAXINT;
990   bounds.width = 0;
991   bounds.height = 0;
992
993   pts = g_new (POINT, npoints);
994
995   for (i = 0; i < npoints; i++)
996     {
997       bounds.x = MIN (bounds.x, points[i].x);
998       bounds.y = MIN (bounds.y, points[i].y);
999       pts[i].x = points[i].x;
1000       pts[i].y = points[i].y;
1001     }
1002
1003   for (i = 0; i < npoints; i++)
1004     {
1005       bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1006       bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1007     }
1008
1009   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1010
1011   generic_draw (drawable, gc,
1012                 GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
1013                 draw_polygon, region, filled, pts, npoints);
1014
1015   gdk_region_destroy (region);
1016   g_free (pts);
1017 }
1018
1019 typedef struct
1020 {
1021   gint x, y;
1022   HDC hdc;
1023 } gdk_draw_text_arg;
1024
1025 static void
1026 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
1027                        const wchar_t      *wcstr,
1028                        int                 wclen,
1029                        void               *arg)
1030 {
1031   HGDIOBJ oldfont;
1032   SIZE size;
1033   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
1034
1035   if (!singlefont)
1036     return;
1037
1038   if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
1039     {
1040       WIN32_GDI_FAILED ("SelectObject");
1041       return;
1042     }
1043   
1044   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
1045     WIN32_GDI_FAILED ("TextOutW");
1046   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
1047   argp->x += size.cx;
1048
1049   SelectObject (argp->hdc, oldfont);
1050 }
1051
1052 static void
1053 gdk_win32_draw_text (GdkDrawable *drawable,
1054                      GdkFont     *font,
1055                      GdkGC       *gc,
1056                      gint         x,
1057                      gint         y,
1058                      const gchar *text,
1059                      gint         text_length)
1060 {
1061   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
1062   wchar_t *wcstr, wc;
1063   glong wlen;
1064   gdk_draw_text_arg arg;
1065
1066   if (text_length == 0)
1067     return;
1068
1069   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1070
1071   arg.x = x;
1072   arg.y = y;
1073   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
1074
1075   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_text: %s (%d,%d) \"%.*s\" (len %d)\n",
1076                            _gdk_win32_drawable_description (drawable),
1077                            x, y,
1078                            (text_length > 10 ? 10 : text_length),
1079                            text, text_length));
1080   
1081   if (text_length == 1)
1082     {
1083       /* For single characters, don't try to interpret as UTF-8. */
1084       wc = (guchar) text[0];
1085       _gdk_wchar_text_handle (font, &wc, 1, gdk_draw_text_handler, &arg);
1086     }
1087   else
1088     {
1089       wcstr = g_utf8_to_utf16 (text, text_length, NULL, &wlen, NULL);
1090       _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
1091       g_free (wcstr);
1092     }
1093
1094   gdk_win32_hdc_release (drawable, gc, mask);
1095 }
1096
1097 static void
1098 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
1099                         GdkFont          *font,
1100                         GdkGC            *gc,
1101                         gint              x,
1102                         gint              y,
1103                         const GdkWChar *text,
1104                         gint              text_length)
1105 {
1106   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
1107   gint i;
1108   wchar_t *wcstr;
1109   gdk_draw_text_arg arg;
1110
1111   if (text_length == 0)
1112     return;
1113
1114   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1115
1116   arg.x = x;
1117   arg.y = y;
1118   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
1119
1120   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_text_wc: %s (%d,%d) len: %d\n",
1121                            _gdk_win32_drawable_description (drawable),
1122                            x, y, text_length));
1123       
1124   if (sizeof (wchar_t) != sizeof (GdkWChar))
1125     {
1126       wcstr = g_new (wchar_t, text_length);
1127       for (i = 0; i < text_length; i++)
1128         wcstr[i] = text[i];
1129     }
1130   else
1131     wcstr = (wchar_t *) text;
1132
1133   _gdk_wchar_text_handle (font, wcstr, text_length,
1134                          gdk_draw_text_handler, &arg);
1135
1136   if (sizeof (wchar_t) != sizeof (GdkWChar))
1137     g_free (wcstr);
1138
1139   gdk_win32_hdc_release (drawable, gc, mask);
1140 }
1141
1142 static void
1143 gdk_win32_draw_drawable (GdkDrawable *drawable,
1144                          GdkGC       *gc,
1145                          GdkPixmap   *src,
1146                          gint         xsrc,
1147                          gint         ysrc,
1148                          gint         xdest,
1149                          gint         ydest,
1150                          gint         width,
1151                          gint         height)
1152 {
1153   g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1154
1155   _gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
1156                    gc, src, xsrc, ysrc,
1157                    xdest, ydest, width, height);
1158 }
1159
1160 static void
1161 gdk_win32_draw_points (GdkDrawable *drawable,
1162                        GdkGC       *gc,
1163                        GdkPoint    *points,
1164                        gint         npoints)
1165 {
1166   HDC hdc;
1167   HGDIOBJ old_pen;
1168   int i;
1169
1170   hdc = gdk_win32_hdc_get (drawable, gc, GDK_GC_FOREGROUND);
1171   
1172   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_points: %s %d points\n",
1173                            _gdk_win32_drawable_description (drawable),
1174                            npoints));
1175
1176   /* The X11 version uses XDrawPoint(), which doesn't use the fill
1177    * mode, so don't use generic_draw. But we should use the current
1178    * function, so we can't use SetPixel(). Draw single-pixel
1179    * rectangles (sigh).
1180    */
1181
1182   old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
1183   for (i = 0; i < npoints; i++)
1184     Rectangle (hdc, points[i].x, points[i].y,
1185                points[i].x + 2, points[i].y + 2);
1186
1187   SelectObject (hdc, old_pen);
1188   gdk_win32_hdc_release (drawable, gc, GDK_GC_FOREGROUND);
1189 }
1190
1191 static void
1192 draw_segments (GdkGCWin32 *gcwin32,
1193                HDC         hdc,
1194                gint        x_offset,
1195                gint        y_offset,
1196                va_list     args)
1197 {
1198   GdkSegment *segs;
1199   gint nsegs;
1200   gint i;
1201
1202   segs = va_arg (args, GdkSegment *);
1203   nsegs = va_arg (args, gint);
1204
1205   if (x_offset != 0 || y_offset != 0)
1206     {
1207       /* must not modify in place, but could splice in the offset all below */
1208       segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
1209       for (i = 0; i < nsegs; i++)
1210         {
1211           segs[i].x1 -= x_offset;
1212           segs[i].y1 -= y_offset;
1213           segs[i].x2 -= x_offset;
1214           segs[i].y2 -= y_offset;
1215         }
1216     }
1217
1218   if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
1219     {
1220       for (i = 0; i < nsegs; i++)
1221         {
1222           if (segs[i].x1 == segs[i].x2)
1223             {
1224               int y1, y2;
1225               
1226               if (segs[i].y1 <= segs[i].y2)
1227                 y1 = segs[i].y1, y2 = segs[i].y2;
1228               else
1229                 y1 = segs[i].y2, y2 = segs[i].y1;
1230               
1231               render_line_vertical (gcwin32, segs[i].x1, y1, y2);
1232             }
1233           else if (segs[i].y1 == segs[i].y2)
1234             {
1235               int x1, x2;
1236               
1237               if (segs[i].x1 <= segs[i].x2)
1238                 x1 = segs[i].x1, x2 = segs[i].x2;
1239               else
1240                 x1 = segs[i].x2, x2 = segs[i].x1;
1241               
1242               render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
1243             }
1244           else
1245             GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
1246               GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
1247         }
1248     }
1249   else
1250     {
1251       for (i = 0; i < nsegs; i++)
1252         {
1253           const GdkSegment *ps = &segs[i];
1254           const int x1 = ps->x1, y1 = ps->y1;
1255           int x2 = ps->x2, y2 = ps->y2;
1256
1257           GDK_NOTE (DRAW, g_print (" +%d+%d..+%d+%d", x1, y1, x2, y2));
1258           GDI_CALL (MoveToEx, (hdc, x1, y1, NULL)) &&
1259             GDI_CALL (LineTo, (hdc, x2, y2));
1260         }
1261
1262       GDK_NOTE (DRAW, g_print ("\n"));
1263     }
1264   if (x_offset != 0 || y_offset != 0)
1265     g_free (segs);
1266 }
1267
1268 static void
1269 gdk_win32_draw_segments (GdkDrawable *drawable,
1270                          GdkGC       *gc,
1271                          GdkSegment  *segs,
1272                          gint         nsegs)
1273 {
1274   GdkRectangle bounds;
1275   GdkRegion *region;
1276   gint i;
1277
1278   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_segments: %s %d segs\n",
1279                            _gdk_win32_drawable_description (drawable),
1280                            nsegs));
1281
1282   bounds.x = G_MAXINT;
1283   bounds.y = G_MAXINT;
1284   bounds.width = 0;
1285   bounds.height = 0;
1286
1287   for (i = 0; i < nsegs; i++)
1288     {
1289       bounds.x = MIN (bounds.x, segs[i].x1);
1290       bounds.x = MIN (bounds.x, segs[i].x2);
1291       bounds.y = MIN (bounds.y, segs[i].y1);
1292       bounds.y = MIN (bounds.y, segs[i].y2);
1293     }
1294
1295   for (i = 0; i < nsegs; i++)
1296     {
1297       bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
1298       bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
1299       bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
1300       bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
1301     }
1302
1303   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1304
1305   generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
1306                 draw_segments, region, segs, nsegs);
1307
1308   gdk_region_destroy (region);
1309 }
1310
1311 static void
1312 draw_lines (GdkGCWin32 *gcwin32,
1313             HDC         hdc,
1314             gint        x_offset,
1315             gint        y_offset,
1316             va_list     args)
1317 {
1318   POINT *pts;
1319   gint npoints;
1320   gint i;
1321
1322   pts = va_arg (args, POINT *);
1323   npoints = va_arg (args, gint);
1324
1325   if (x_offset != 0 || y_offset != 0)
1326     for (i = 0; i < npoints; i++)
1327       {
1328         pts[i].x -= x_offset;
1329         pts[i].y -= y_offset;
1330       }
1331   
1332   if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
1333     {
1334       for (i = 0; i < npoints - 1; i++)
1335         {
1336           if (pts[i].x == pts[i+1].x)
1337             {
1338               int y1, y2;
1339               if (pts[i].y > pts[i+1].y)
1340                 y1 = pts[i+1].y, y2 = pts[i].y;
1341               else
1342                 y1 = pts[i].y, y2 = pts[i+1].y;
1343               
1344               render_line_vertical (gcwin32, pts[i].x, y1, y2);
1345             }
1346           else if (pts[i].y == pts[i+1].y)
1347             {
1348               int x1, x2;
1349               if (pts[i].x > pts[i+1].x)
1350                 x1 = pts[i+1].x, x2 = pts[i].x;
1351               else
1352                 x1 = pts[i].x, x2 = pts[i+1].x;
1353
1354               render_line_horizontal (gcwin32, x1, x2, pts[i].y);
1355             }
1356           else
1357             GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
1358               GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
1359         }
1360     }
1361   else
1362     GDI_CALL (Polyline, (hdc, pts, npoints));
1363 }
1364
1365 static void
1366 gdk_win32_draw_lines (GdkDrawable *drawable,
1367                       GdkGC       *gc,
1368                       GdkPoint    *points,
1369                       gint         npoints)
1370 {
1371   GdkRectangle bounds;
1372   GdkRegion *region;
1373   POINT *pts;
1374   int i;
1375
1376   GDK_NOTE (DRAW, g_print ("gdk_win32_draw_lines: %s %d points\n",
1377                            _gdk_win32_drawable_description (drawable),
1378                            npoints));
1379
1380   if (npoints < 2)
1381     return;
1382
1383   bounds.x = G_MAXINT;
1384   bounds.y = G_MAXINT;
1385   bounds.width = 0;
1386   bounds.height = 0;
1387
1388   pts = g_new (POINT, npoints);
1389
1390   for (i = 0; i < npoints; i++)
1391     {
1392       bounds.x = MIN (bounds.x, points[i].x);
1393       bounds.y = MIN (bounds.y, points[i].y);
1394       pts[i].x = points[i].x;
1395       pts[i].y = points[i].y;
1396     }
1397
1398   for (i = 0; i < npoints; i++)
1399     {
1400       bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1401       bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1402     }
1403
1404   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1405
1406   generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
1407                               LINE_ATTRIBUTES,
1408                 draw_lines, region, pts, npoints);
1409
1410   gdk_region_destroy (region);
1411   g_free (pts);
1412 }
1413
1414 static void
1415 blit_from_pixmap (gboolean              use_fg_bg,
1416                   GdkDrawableImplWin32 *dest,
1417                   HDC                   hdc,
1418                   GdkPixmapImplWin32   *src,
1419                   GdkGC                *gc,
1420                   gint                  xsrc,
1421                   gint                  ysrc,
1422                   gint                  xdest,
1423                   gint                  ydest,
1424                   gint                  width,
1425                   gint                  height)
1426 {
1427   GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
1428   HDC srcdc;
1429   HBITMAP holdbitmap;
1430   RGBQUAD oldtable[256], newtable[256];
1431   COLORREF bg, fg;
1432
1433   gint newtable_size = 0, oldtable_size = 0;
1434   gboolean ok = TRUE;
1435   
1436   GDK_NOTE (DRAW, g_print ("blit_from_pixmap\n"));
1437
1438   srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
1439   if (!srcdc)
1440     return;
1441   
1442   if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
1443     WIN32_GDI_FAILED ("SelectObject");
1444   else
1445     {
1446       if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
1447         {
1448           /* Blitting from a 1, 4 or 8-bit pixmap */
1449
1450           if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
1451             WIN32_GDI_FAILED ("GetDIBColorTable");
1452           else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
1453             {
1454               /* Blitting from an 1-bit pixmap */
1455
1456               gint bgix, fgix;
1457               
1458               if (use_fg_bg)
1459                 {
1460                   bgix = _gdk_gc_get_bg_pixel (gc);
1461                   fgix = _gdk_gc_get_fg_pixel (gc);
1462                 }
1463               else
1464                 {
1465                   bgix = 0;
1466                   fgix = 1;
1467                 }
1468               
1469               if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
1470                   GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
1471                 {
1472                   /* Destination is also pixmap, get fg and bg from
1473                    * its palette. Either use the foreground and
1474                    * background pixel values in the GC (only in the
1475                    * case of gdk_image_put(), cf. XPutImage()), or 0
1476                    * and 1 to index the palette.
1477                    */
1478                   if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
1479                       !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
1480                     ok = FALSE;
1481                 }
1482               else
1483                 {
1484                   /* Destination is a window, get fg and bg from its
1485                    * colormap
1486                    */
1487
1488                   bg = _gdk_win32_colormap_color (dest->colormap, bgix);
1489                   fg = _gdk_win32_colormap_color (dest->colormap, fgix);
1490                   newtable[0].rgbBlue = GetBValue (bg);
1491                   newtable[0].rgbGreen = GetGValue (bg);
1492                   newtable[0].rgbRed = GetRValue (bg);
1493                   newtable[0].rgbReserved = 0;
1494                   newtable[1].rgbBlue = GetBValue (fg);
1495                   newtable[1].rgbGreen = GetGValue (fg);
1496                   newtable[1].rgbRed = GetRValue (fg);
1497                   newtable[1].rgbReserved = 0;
1498                 }
1499               if (ok)
1500                 GDK_NOTE (DRAW, g_print ("bg: %02x %02x %02x "
1501                                          "fg: %02x %02x %02x\n",
1502                                          newtable[0].rgbRed,
1503                                          newtable[0].rgbGreen,
1504                                          newtable[0].rgbBlue,
1505                                          newtable[1].rgbRed,
1506                                          newtable[1].rgbGreen,
1507                                          newtable[1].rgbBlue));
1508               newtable_size = 2;
1509             }
1510           else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
1511             {
1512               /* Destination is pixmap, get its color table */
1513               
1514               if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
1515                 WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
1516             }
1517           
1518           /* If blitting between pixmaps, set source's color table */
1519           if (ok && newtable_size > 0)
1520             {
1521               GDK_NOTE (MISC_OR_COLORMAP,
1522                         g_print ("blit_from_pixmap: set color table"
1523                                  " hdc=%p count=%d\n",
1524                                  srcdc, newtable_size));
1525               if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
1526                 ok = FALSE;
1527             }
1528         }
1529       
1530       if (ok)
1531         if (!BitBlt (hdc, xdest, ydest, width, height,
1532                      srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)) &&
1533             GetLastError () != ERROR_INVALID_HANDLE)
1534           WIN32_GDI_FAILED ("BitBlt");
1535       
1536       /* Restore source's color table if necessary */
1537       if (ok && newtable_size > 0 && oldtable_size > 0)
1538         {
1539           GDK_NOTE (MISC_OR_COLORMAP,
1540                     g_print ("blit_from_pixmap: reset color table"
1541                              " hdc=%p count=%d\n",
1542                              srcdc, oldtable_size));
1543           GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
1544         }
1545       
1546       GDI_CALL (SelectObject, (srcdc, holdbitmap));
1547     }
1548   
1549   _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
1550 }
1551
1552 static void
1553 blit_inside_drawable (HDC       hdc,
1554                       GdkGCWin32 *gcwin32,
1555                       gint      xsrc,
1556                       gint      ysrc,
1557                       gint      xdest,
1558                       gint      ydest,
1559                       gint      width,
1560                       gint      height)
1561
1562 {
1563   GDK_NOTE (DRAW, g_print ("blit_inside_drawable\n"));
1564
1565   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1566                      hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1567 }
1568
1569 static void
1570 blit_from_window (HDC                   hdc,
1571                   GdkGCWin32           *gcwin32,
1572                   GdkDrawableImplWin32 *src,
1573                   gint                  xsrc,
1574                   gint                  ysrc,
1575                   gint                  xdest,
1576                   gint                  ydest,
1577                   gint                  width,
1578                   gint                  height)
1579 {
1580   HDC srcdc;
1581   HPALETTE holdpal = NULL;
1582   GdkColormap *cmap = gdk_colormap_get_system ();
1583
1584   GDK_NOTE (DRAW, g_print ("blit_from_window\n"));
1585
1586   if ((srcdc = GetDC (src->handle)) == NULL)
1587     {
1588       WIN32_GDI_FAILED ("GetDC");
1589       return;
1590     }
1591
1592   if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
1593       cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
1594     {
1595       gint k;
1596       
1597       if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
1598         WIN32_GDI_FAILED ("SelectPalette");
1599       else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
1600         WIN32_GDI_FAILED ("RealizePalette");
1601       else if (k > 0)
1602         GDK_NOTE (MISC_OR_COLORMAP,
1603                   g_print ("blit_from_window: realized %d\n", k));
1604     }
1605   
1606   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1607                      srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1608   
1609   if (holdpal != NULL)
1610     GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
1611   
1612   GDI_CALL (ReleaseDC, (src->handle, srcdc));
1613 }
1614
1615 void
1616 _gdk_win32_blit (gboolean              use_fg_bg,
1617                  GdkDrawableImplWin32 *draw_impl,
1618                  GdkGC                *gc,
1619                  GdkDrawable          *src,
1620                  gint                  xsrc,
1621                  gint                  ysrc,
1622                  gint                  xdest,
1623                  gint                  ydest,
1624                  gint                  width,
1625                  gint                  height)
1626 {
1627   HDC hdc;
1628   HRGN src_rgn, draw_rgn, outside_rgn;
1629   RECT r;
1630   GdkDrawableImplWin32 *src_impl = NULL;
1631   gint src_width, src_height;
1632   
1633   GDK_NOTE (DRAW, g_print ("_gdk_win32_blit: src:%s %dx%d@%+d%+d\n"
1634                            "                 dst:%s @%+d%+d use_fg_bg=%d\n",
1635                            _gdk_win32_drawable_description (src),
1636                            width, height, xsrc, ysrc,
1637                            _gdk_win32_drawable_description (&draw_impl->parent_instance),
1638                            xdest, ydest,
1639                            use_fg_bg));
1640
1641   /* If blitting from the root window, take the multi-monitor offset
1642    * into account.
1643    */
1644   if (src == ((GdkWindowObject *)_gdk_root)->impl)
1645     {
1646       GDK_NOTE (DRAW, g_print ("... offsetting src coords\n"));
1647       xsrc -= _gdk_offset_x;
1648       ysrc -= _gdk_offset_y;
1649     }
1650
1651   if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
1652     src_impl = (GdkDrawableImplWin32 *) src;
1653   else if (GDK_IS_WINDOW (src))
1654     src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
1655   else if (GDK_IS_PIXMAP (src))
1656     src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
1657   else
1658     g_assert_not_reached ();
1659
1660   hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
1661
1662   gdk_drawable_get_size (src, &src_width, &src_height);
1663
1664   if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
1665     WIN32_GDI_FAILED ("CreateRectRgn");
1666   else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
1667                                       xsrc + width + 1,
1668                                       ysrc + height + 1)) == NULL)
1669     WIN32_GDI_FAILED ("CreateRectRgn");
1670   else
1671     {
1672       if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
1673         {
1674           int comb;
1675           
1676           /* If we are drawing on a window, calculate the region that is
1677            * outside the source pixmap, and invalidate that, causing it to
1678            * be cleared. Not completely sure whether this is always needed. XXX
1679            */
1680           SetRectEmpty (&r);
1681           outside_rgn = CreateRectRgnIndirect (&r);
1682           
1683           if ((comb = CombineRgn (outside_rgn,
1684                                   draw_rgn, src_rgn,
1685                                   RGN_DIFF)) == ERROR)
1686             WIN32_GDI_FAILED ("CombineRgn");
1687           else if (comb != NULLREGION)
1688             {
1689               OffsetRgn (outside_rgn, xdest, ydest);
1690               GDK_NOTE (DRAW, (GetRgnBox (outside_rgn, &r),
1691                                g_print ("... InvalidateRgn "
1692                                         "bbox: %ldx%ld@%+ld%+ld\n",
1693                                         r.right - r.left - 1, r.bottom - r.top - 1,
1694                                         r.left, r.top)));
1695               InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
1696             }
1697           GDI_CALL (DeleteObject, (outside_rgn));
1698         }
1699
1700 #if 1 /* Don't know if this is necessary XXX */
1701       if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
1702         g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
1703       
1704       GetRgnBox (draw_rgn, &r);
1705       if (r.left != xsrc || r.top != ysrc ||
1706           r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
1707         {
1708           xdest += r.left - xsrc;
1709           xsrc = r.left;
1710           ydest += r.top - ysrc;
1711           ysrc = r.top;
1712           width = r.right - xsrc - 1;
1713           height = r.bottom - ysrc - 1;
1714           
1715           GDK_NOTE (DRAW, g_print ("... restricted to src: %dx%d@%+d%+d, "
1716                                    "dest: @%+d%+d\n",
1717                                    width, height, xsrc, ysrc,
1718                                    xdest, ydest));
1719         }
1720 #endif
1721
1722       GDI_CALL (DeleteObject, (src_rgn));
1723       GDI_CALL (DeleteObject, (draw_rgn));
1724     }
1725
1726   if (draw_impl->handle == src_impl->handle)
1727     blit_inside_drawable (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
1728   else if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
1729     blit_from_pixmap (use_fg_bg, draw_impl, hdc,
1730                       (GdkPixmapImplWin32 *) src_impl, gc,
1731                       xsrc, ysrc, xdest, ydest, width, height);
1732   else
1733     blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
1734   gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
1735 }
1736
1737 static void
1738 gdk_win32_draw_image (GdkDrawable     *drawable,
1739                       GdkGC           *gc,
1740                       GdkImage        *image,
1741                       gint             xsrc,
1742                       gint             ysrc,
1743                       gint             xdest,
1744                       gint             ydest,
1745                       gint             width,
1746                       gint             height)
1747 {
1748   g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1749
1750   _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
1751                    gc, (GdkPixmap *) image->windowing_data,
1752                    xsrc, ysrc, xdest, ydest, width, height);
1753 }
1754
1755 /**
1756  * _gdk_win32_drawable_acquire_dc
1757  * @drawable: a Win32 #GdkDrawable implementation
1758  * 
1759  * Gets a DC with the given drawable selected into
1760  * it.
1761  *
1762  * Return value: The DC, on success. Otherwise
1763  *  %NULL. If this function succeeded
1764  *  _gdk_win32_drawable_release_dc()  must be called
1765  *  release the DC when you are done using it.
1766  **/
1767 HDC 
1768 _gdk_win32_drawable_acquire_dc (GdkDrawable *drawable)
1769 {
1770   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1771   
1772   if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
1773       GDK_WINDOW_DESTROYED (impl->wrapper))
1774     return NULL;
1775
1776   if (!impl->hdc)
1777     {
1778       if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1779         {
1780           impl->hdc = CreateCompatibleDC (NULL);
1781           if (!impl->hdc)
1782             WIN32_GDI_FAILED ("CreateCompatibleDC");
1783           
1784           if (impl->hdc)
1785             {
1786               impl->saved_dc_bitmap = SelectObject (impl->hdc,
1787                                                     impl->handle);
1788               if (!impl->saved_dc_bitmap)
1789                 {
1790                   WIN32_GDI_FAILED ("CreateCompatibleDC");
1791                   DeleteDC (impl->hdc);
1792                   impl->hdc = NULL;
1793                 }
1794             }
1795         }
1796       else
1797         {
1798           impl->hdc = GetDC (impl->handle);
1799           if (!impl->hdc)
1800             WIN32_GDI_FAILED ("GetDC");
1801         }
1802     }
1803
1804   if (impl->hdc)
1805     {
1806       impl->hdc_count++;
1807       return impl->hdc;
1808     }
1809   else
1810     return NULL;
1811 }
1812
1813 /**
1814  * _gdk_win32_drawable_release_dc
1815  * @drawable: a Win32 #GdkDrawable implementation
1816  * 
1817  * Releases the reference count for the DC
1818  * from _gdk_win32_drawable_acquire_dc()
1819  **/
1820 void
1821 _gdk_win32_drawable_release_dc (GdkDrawable *drawable)
1822 {
1823   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1824   
1825   g_return_if_fail (impl->hdc_count > 0);
1826
1827   impl->hdc_count--;
1828   if (impl->hdc_count == 0)
1829     {
1830       if (impl->saved_dc_bitmap)
1831         {
1832           GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
1833           impl->saved_dc_bitmap = NULL;
1834         }
1835       
1836       if (impl->hdc)
1837         {
1838           if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1839             GDI_CALL (DeleteDC, (impl->hdc));
1840           else
1841             GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
1842           impl->hdc = NULL;
1843         }
1844     }
1845 }
1846
1847 static void
1848 gdk_win32_cairo_surface_destroy (void *data)
1849 {
1850   GdkDrawableImplWin32 *impl = data;
1851
1852   _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
1853   impl->cairo_surface = NULL;
1854 }
1855
1856 static cairo_surface_t *
1857 gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
1858 {
1859   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1860
1861   if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
1862       GDK_WINDOW_DESTROYED (impl->wrapper))
1863     return NULL;
1864
1865   if (!impl->cairo_surface)
1866     {
1867       HDC hdc = _gdk_win32_drawable_acquire_dc (drawable);
1868       if (!hdc)
1869         return NULL;
1870
1871       impl->cairo_surface = cairo_win32_surface_create (hdc);
1872
1873       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
1874                                    drawable, gdk_win32_cairo_surface_destroy);
1875     }
1876   else
1877     cairo_surface_reference (impl->cairo_surface);
1878
1879   return impl->cairo_surface;
1880 }
1881
1882 static gint
1883 gdk_win32_get_depth (GdkDrawable *drawable)
1884 {
1885   /* This is a bit bogus but I'm not sure the other way is better */
1886
1887   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1888 }
1889
1890 static GdkScreen*
1891 gdk_win32_get_screen (GdkDrawable *drawable)
1892 {
1893   return gdk_screen_get_default ();
1894 }
1895  
1896 static GdkVisual*
1897 gdk_win32_get_visual (GdkDrawable *drawable)
1898 {
1899   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1900 }
1901
1902 HGDIOBJ
1903 gdk_win32_drawable_get_handle (GdkDrawable *drawable)
1904 {
1905   return GDK_DRAWABLE_HANDLE (drawable);
1906 }
1907
1908 /**
1909  * _gdk_win32_drawable_finish
1910  * @drawable: a Win32 #GdkDrawable implementation
1911  * 
1912  * Releases any resources allocated internally for the drawable.
1913  * This is called when the drawable becomes unusable
1914  * (gdk_window_destroy() for a window, or the refcount going to
1915  * zero for a pixmap.)
1916  **/
1917 void
1918 _gdk_win32_drawable_finish (GdkDrawable *drawable)
1919 {
1920   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1921
1922   if (impl->cairo_surface)
1923     {
1924       cairo_surface_finish (impl->cairo_surface);
1925       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
1926                                    NULL, NULL);
1927     }
1928   
1929   g_assert (impl->hdc_count == 0);
1930 }
1931