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