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