]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Add gdk_draw_rectangle_alpha_libgtk_only which uses XRenderFillRectangle
[~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   glong 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_utf8_to_utf16 (text, text_length, NULL, &wlen, NULL);
1062       _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
1063       g_free (wcstr);
1064     }
1065
1066   gdk_win32_hdc_release (drawable, gc, mask);
1067 }
1068
1069 static void
1070 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
1071                         GdkFont          *font,
1072                         GdkGC            *gc,
1073                         gint              x,
1074                         gint              y,
1075                         const GdkWChar *text,
1076                         gint              text_length)
1077 {
1078   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
1079   gint i;
1080   wchar_t *wcstr;
1081   gdk_draw_text_arg arg;
1082
1083   if (text_length == 0)
1084     return;
1085
1086   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1087
1088   arg.x = x;
1089   arg.y = y;
1090   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
1091
1092   GDK_NOTE (MISC, g_print ("gdk_win32_draw_text_wc: %s (%d,%d) len: %d\n",
1093                            _gdk_win32_drawable_description (drawable),
1094                            x, y, text_length));
1095       
1096   if (sizeof (wchar_t) != sizeof (GdkWChar))
1097     {
1098       wcstr = g_new (wchar_t, text_length);
1099       for (i = 0; i < text_length; i++)
1100         wcstr[i] = text[i];
1101     }
1102   else
1103     wcstr = (wchar_t *) text;
1104
1105   _gdk_wchar_text_handle (font, wcstr, text_length,
1106                          gdk_draw_text_handler, &arg);
1107
1108   if (sizeof (wchar_t) != sizeof (GdkWChar))
1109     g_free (wcstr);
1110
1111   gdk_win32_hdc_release (drawable, gc, mask);
1112 }
1113
1114 static void
1115 gdk_win32_draw_drawable (GdkDrawable *drawable,
1116                          GdkGC       *gc,
1117                          GdkPixmap   *src,
1118                          gint         xsrc,
1119                          gint         ysrc,
1120                          gint         xdest,
1121                          gint         ydest,
1122                          gint         width,
1123                          gint         height)
1124 {
1125   g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1126
1127   _gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
1128                    gc, src, xsrc, ysrc,
1129                    xdest, ydest, width, height);
1130 }
1131
1132 static void
1133 gdk_win32_draw_points (GdkDrawable *drawable,
1134                        GdkGC       *gc,
1135                        GdkPoint    *points,
1136                        gint         npoints)
1137 {
1138   HDC hdc;
1139   HGDIOBJ old_pen;
1140   int i;
1141
1142   hdc = gdk_win32_hdc_get (drawable, gc, GDK_GC_FOREGROUND);
1143   
1144   GDK_NOTE (MISC, g_print ("gdk_win32_draw_points: %s %d points\n",
1145                            _gdk_win32_drawable_description (drawable),
1146                            npoints));
1147
1148   /* The X11 version uses XDrawPoint(), which doesn't use the fill
1149    * mode, so don't use generic_draw. But we should use the current
1150    * function, so we can't use SetPixel(). Draw single-pixel
1151    * rectangles (sigh).
1152    */
1153
1154   old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
1155   for (i = 0; i < npoints; i++)
1156     Rectangle (hdc, points[i].x, points[i].y,
1157                points[i].x + 2, points[i].y + 2);
1158
1159   SelectObject (hdc, old_pen);
1160   gdk_win32_hdc_release (drawable, gc, GDK_GC_FOREGROUND);
1161 }
1162
1163 static void
1164 draw_segments (GdkGCWin32 *gcwin32,
1165                HDC         hdc,
1166                gint        x_offset,
1167                gint        y_offset,
1168                va_list     args)
1169 {
1170   GdkSegment *segs;
1171   gint nsegs;
1172   gint i;
1173
1174   segs = va_arg (args, GdkSegment *);
1175   nsegs = va_arg (args, gint);
1176
1177   if (x_offset != 0 || y_offset != 0)
1178     {
1179       /* must not modify in place, but could splice in the offset all below */
1180       segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
1181       for (i = 0; i < nsegs; i++)
1182         {
1183           segs[i].x1 -= x_offset;
1184           segs[i].y1 -= y_offset;
1185           segs[i].x2 -= x_offset;
1186           segs[i].y2 -= y_offset;
1187         }
1188     }
1189
1190   if (gcwin32->pen_dashes && !IS_WIN_NT ())
1191     {
1192       for (i = 0; i < nsegs; i++)
1193         {
1194           if (segs[i].x1 == segs[i].x2)
1195             {
1196               int y1, y2;
1197               
1198               if (segs[i].y1 <= segs[i].y2)
1199                 y1 = segs[i].y1, y2 = segs[i].y2;
1200               else
1201                 y1 = segs[i].y2, y2 = segs[i].y1;
1202               
1203               render_line_vertical (hdc,
1204                                     segs[i].x1, y1, y2,
1205                                     gcwin32->pen_width,
1206                                     gcwin32->pen_dashes,
1207                                     gcwin32->pen_num_dashes);
1208             }
1209           else if (segs[i].y1 == segs[i].y2)
1210             {
1211               int x1, x2;
1212               
1213               if (segs[i].x1 <= segs[i].x2)
1214                 x1 = segs[i].x1, x2 = segs[i].x2;
1215               else
1216                 x1 = segs[i].x2, x2 = segs[i].x1;
1217               
1218               render_line_horizontal (hdc,
1219                                       x1, x2, segs[i].y1,
1220                                       gcwin32->pen_width,
1221                                       gcwin32->pen_dashes,
1222                                       gcwin32->pen_num_dashes);
1223             }
1224           else
1225             GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
1226               GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
1227
1228         }
1229     }
1230   else
1231     {
1232       for (i = 0; i < nsegs; i++)
1233         GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
1234           GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
1235
1236       /* not drawing the end pixel does produce a crippled mask, look 
1237        * e.g. at xpm icons produced with gdk_pixbuf_new_from_xpm_data trough
1238        * gdk_pixbuf_render_threshold_alpha (testgtk folder icon or
1239        * Dia's toolbox icons) but only on win9x ... --hb
1240        *
1241        * Update : see bug #81895 and bug #126710 why this is finally
1242        *          needed on any win32 platform ;-)
1243        */
1244       if (gcwin32->pen_width <= 1)
1245         {
1246           GdkSegment *ps = &segs[nsegs-1];
1247           int xc = 0, yc = 0;
1248
1249           if (ps->y2 == ps->y1 && ps->x2 == ps->x1)
1250             xc = 1; /* just a point */
1251           else if (ps->y2 == ps->y1)
1252             xc = (ps->x1 < ps->x2) ? 1 : -1; /* advance x only */
1253           else if (ps->x2 == ps->x1)
1254             yc = (ps->y1 < ps->y2) ? 1 : -1; /* advance y only */
1255           else
1256             {
1257               xc = (ps->x1 < ps->x2) ? 1 : -1;
1258               yc = (ps->y1 < ps->y2) ? 1 : -1;
1259             }
1260
1261           GDI_CALL (LineTo, (hdc, ps->x2 + xc, ps->y2 + yc));
1262         }
1263     }
1264   if (x_offset != 0 || y_offset != 0)
1265     g_free (segs);
1266 }
1267
1268 static void
1269 gdk_win32_draw_segments (GdkDrawable *drawable,
1270                          GdkGC       *gc,
1271                          GdkSegment  *segs,
1272                          gint         nsegs)
1273 {
1274   GdkRectangle bounds;
1275   GdkRegion *region;
1276   gint i;
1277
1278   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %s %d segs\n",
1279                            _gdk_win32_drawable_description (drawable),
1280                            nsegs));
1281
1282   bounds.x = G_MAXINT;
1283   bounds.y = G_MAXINT;
1284   bounds.width = 0;
1285   bounds.height = 0;
1286
1287   for (i = 0; i < nsegs; i++)
1288     {
1289       bounds.x = MIN (bounds.x, segs[i].x1);
1290       bounds.x = MIN (bounds.x, segs[i].x2);
1291       bounds.y = MIN (bounds.y, segs[i].y1);
1292       bounds.y = MIN (bounds.y, segs[i].y2);
1293     }
1294
1295   for (i = 0; i < nsegs; i++)
1296     {
1297       bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
1298       bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
1299       bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
1300       bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
1301     }
1302
1303   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1304
1305   generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
1306                 draw_segments, region, segs, nsegs);
1307
1308   gdk_region_destroy (region);
1309 }
1310
1311 static void
1312 draw_lines (GdkGCWin32 *gcwin32,
1313             HDC         hdc,
1314             gint        x_offset,
1315             gint        y_offset,
1316             va_list     args)
1317 {
1318   POINT *pts;
1319   gint npoints;
1320   gint i;
1321
1322   pts = va_arg (args, POINT *);
1323   npoints = va_arg (args, gint);
1324
1325   if (x_offset != 0 || y_offset != 0)
1326     for (i = 0; i < npoints; i++)
1327       {
1328         pts[i].x -= x_offset;
1329         pts[i].y -= y_offset;
1330       }
1331   
1332   if (gcwin32->pen_dashes && !IS_WIN_NT ())
1333     {
1334       for (i = 0; i < npoints - 1; i++)
1335         {
1336           if (pts[i].x == pts[i+1].x)
1337             {
1338               int y1, y2;
1339               if (pts[i].y > pts[i+1].y)
1340                 y1 = pts[i+1].y, y2 = pts[i].y;
1341               else
1342                 y1 = pts[i].y, y2 = pts[i+1].y;
1343               
1344               render_line_vertical (hdc, pts[i].x, y1, y2,
1345                                     gcwin32->pen_width,
1346                                     gcwin32->pen_dashes,
1347                                     gcwin32->pen_num_dashes);
1348             }
1349           else if (pts[i].y == pts[i+1].y)
1350             {
1351               int x1, x2;
1352               if (pts[i].x > pts[i+1].x)
1353                 x1 = pts[i+1].x, x2 = pts[i].x;
1354               else
1355                 x1 = pts[i].x, x2 = pts[i+1].x;
1356
1357               render_line_horizontal (hdc, x1, x2, pts[i].y,
1358                                       gcwin32->pen_width,
1359                                       gcwin32->pen_dashes,
1360                                       gcwin32->pen_num_dashes);
1361             }
1362           else
1363             GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
1364               GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
1365         }
1366     }
1367   else
1368     GDI_CALL (Polyline, (hdc, pts, npoints));
1369 }
1370
1371 static void
1372 gdk_win32_draw_lines (GdkDrawable *drawable,
1373                       GdkGC       *gc,
1374                       GdkPoint    *points,
1375                       gint         npoints)
1376 {
1377   GdkRectangle bounds;
1378   GdkRegion *region;
1379   POINT *pts;
1380   int i;
1381
1382   GDK_NOTE (MISC, g_print ("gdk_win32_draw_lines: %s %d points\n",
1383                            _gdk_win32_drawable_description (drawable),
1384                            npoints));
1385
1386   if (npoints < 2)
1387     return;
1388
1389   bounds.x = G_MAXINT;
1390   bounds.y = G_MAXINT;
1391   bounds.width = 0;
1392   bounds.height = 0;
1393
1394   pts = g_new (POINT, npoints);
1395
1396   for (i = 0; i < npoints; i++)
1397     {
1398       bounds.x = MIN (bounds.x, points[i].x);
1399       bounds.y = MIN (bounds.y, points[i].y);
1400       pts[i].x = points[i].x;
1401       pts[i].y = points[i].y;
1402     }
1403
1404   for (i = 0; i < npoints; i++)
1405     {
1406       bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1407       bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1408     }
1409
1410   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1411
1412   generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
1413                 draw_lines, region, pts, npoints);
1414
1415   gdk_region_destroy (region);
1416   g_free (pts);
1417 }
1418
1419 static void
1420 draw_glyphs (GdkGCWin32 *gcwin32,
1421              HDC         hdc,
1422              gint        x_offset,
1423              gint        y_offset,
1424              va_list     args)
1425 {
1426   PangoFont *font;
1427   gint x;
1428   gint y;
1429   PangoGlyphString *glyphs;
1430
1431   font = va_arg (args, PangoFont *);
1432   x = va_arg (args, gint);
1433   y = va_arg (args, gint);
1434   glyphs = va_arg (args, PangoGlyphString *);
1435
1436   x -= x_offset;
1437   y -= y_offset;
1438
1439   pango_win32_render (hdc, font, glyphs, x, y);
1440 }
1441
1442 static void
1443 gdk_win32_draw_glyphs (GdkDrawable      *drawable,
1444                        GdkGC            *gc,
1445                        PangoFont        *font,
1446                        gint              x,
1447                        gint              y,
1448                        PangoGlyphString *glyphs)
1449 {
1450   GdkRectangle bounds;
1451   GdkRegion *region;
1452   PangoRectangle ink_rect;
1453
1454   pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
1455
1456   bounds.x = x + PANGO_PIXELS (ink_rect.x) - 1;
1457   bounds.y = y + PANGO_PIXELS (ink_rect.y) - 1;
1458   bounds.width = PANGO_PIXELS (ink_rect.width) + 2;
1459   bounds.height = PANGO_PIXELS (ink_rect.height) + 2;
1460   region = gdk_region_rectangle (&bounds);
1461   
1462   generic_draw (drawable, gc, GDK_GC_FOREGROUND|GDK_GC_FONT,
1463                 draw_glyphs, region, font, x, y, glyphs);
1464
1465   gdk_region_destroy (region);
1466 }
1467
1468 static void
1469 blit_from_pixmap (gboolean              use_fg_bg,
1470                   GdkDrawableImplWin32 *dest,
1471                   HDC                   hdc,
1472                   GdkPixmapImplWin32   *src,
1473                   GdkGCWin32           *gcwin32,
1474                   gint                  xsrc,
1475                   gint                  ysrc,
1476                   gint                  xdest,
1477                   gint                  ydest,
1478                   gint                  width,
1479                   gint                  height)
1480 {
1481   HDC srcdc;
1482   HBITMAP holdbitmap;
1483   RGBQUAD oldtable[256], newtable[256];
1484   COLORREF bg, fg;
1485
1486   gint newtable_size = 0, oldtable_size = 0;
1487   gboolean ok = TRUE;
1488   
1489   GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
1490
1491   if (!(srcdc = CreateCompatibleDC (NULL)))
1492     {
1493       WIN32_GDI_FAILED ("CreateCompatibleDC");
1494       return;
1495     }
1496       
1497   if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
1498     WIN32_GDI_FAILED ("SelectObject");
1499   else
1500     {
1501       if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
1502         {
1503           /* Blitting from a 1, 4 or 8-bit pixmap */
1504
1505           if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
1506             WIN32_GDI_FAILED ("GetDIBColorTable");
1507           else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
1508             {
1509               /* Blitting from an 1-bit pixmap */
1510
1511               gint bgix, fgix;
1512               
1513               if (use_fg_bg)
1514                 {
1515                   bgix = gcwin32->background;
1516                   fgix = gcwin32->foreground;
1517                 }
1518               else
1519                 {
1520                   bgix = 0;
1521                   fgix = 1;
1522                 }
1523               
1524               if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
1525                   GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
1526                 {
1527                   /* Destination is also pixmap, get fg and bg from
1528                    * its palette. Either use the foreground and
1529                    * background pixel values in the GC (only in the
1530                    * case of gdk_image_put(), cf. XPutImage()), or 0
1531                    * and 1 to index the palette.
1532                    */
1533                   if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
1534                       !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
1535                     ok = FALSE;
1536                 }
1537               else
1538                 {
1539                   /* Destination is a window, get fg and bg from its
1540                    * colormap
1541                    */
1542
1543                   bg = _gdk_win32_colormap_color (dest->colormap, bgix);
1544                   fg = _gdk_win32_colormap_color (dest->colormap, fgix);
1545                   newtable[0].rgbBlue = GetBValue (bg);
1546                   newtable[0].rgbGreen = GetGValue (bg);
1547                   newtable[0].rgbRed = GetRValue (bg);
1548                   newtable[0].rgbReserved = 0;
1549                   newtable[1].rgbBlue = GetBValue (fg);
1550                   newtable[1].rgbGreen = GetGValue (fg);
1551                   newtable[1].rgbRed = GetRValue (fg);
1552                   newtable[1].rgbReserved = 0;
1553                 }
1554               if (ok)
1555                 GDK_NOTE (MISC, g_print ("bg: %02x %02x %02x "
1556                                          "fg: %02x %02x %02x\n",
1557                                          newtable[0].rgbRed,
1558                                          newtable[0].rgbGreen,
1559                                          newtable[0].rgbBlue,
1560                                          newtable[1].rgbRed,
1561                                          newtable[1].rgbGreen,
1562                                          newtable[1].rgbBlue));
1563               newtable_size = 2;
1564             }
1565           else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
1566             {
1567               /* Destination is pixmap, get its color table */
1568               
1569               if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
1570                 WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
1571             }
1572           
1573           /* If blitting between pixmaps, set source's color table */
1574           if (ok && newtable_size > 0)
1575             {
1576               GDK_NOTE (MISC_OR_COLORMAP,
1577                         g_print ("blit_from_pixmap: set color table"
1578                                  " hdc=%p count=%d\n",
1579                                  srcdc, newtable_size));
1580               if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
1581                 ok = FALSE;
1582             }
1583         }
1584       
1585       if (ok)
1586         GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1587                            srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1588       
1589       /* Restore source's color table if necessary */
1590       if (ok && newtable_size > 0 && oldtable_size > 0)
1591         {
1592           GDK_NOTE (MISC_OR_COLORMAP,
1593                     g_print ("blit_from_pixmap: reset color table"
1594                              " hdc=%p count=%d\n",
1595                              srcdc, oldtable_size));
1596           GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
1597         }
1598       
1599       GDI_CALL (SelectObject, (srcdc, holdbitmap));
1600     }
1601   GDI_CALL (DeleteDC, (srcdc));
1602 }
1603
1604 static void
1605 blit_inside_window (HDC         hdc,
1606                     GdkGCWin32 *gcwin32,
1607                     gint        xsrc,
1608                     gint        ysrc,
1609                     gint        xdest,
1610                     gint        ydest,
1611                     gint        width,
1612                     gint        height)
1613
1614 {
1615   GDK_NOTE (MISC, g_print ("blit_inside_window\n"));
1616
1617   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1618                      hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1619 }
1620
1621 static void
1622 blit_from_window (HDC                   hdc,
1623                   GdkGCWin32           *gcwin32,
1624                   GdkDrawableImplWin32 *src,
1625                   gint                  xsrc,
1626                   gint                  ysrc,
1627                   gint                  xdest,
1628                   gint                  ydest,
1629                   gint                  width,
1630                   gint                  height)
1631 {
1632   HDC srcdc;
1633   HPALETTE holdpal = NULL;
1634   GdkColormap *cmap = gdk_colormap_get_system ();
1635
1636   GDK_NOTE (MISC, g_print ("blit_from_window\n"));
1637
1638   if ((srcdc = GetDC (src->handle)) == NULL)
1639     {
1640       WIN32_GDI_FAILED ("GetDC");
1641       return;
1642     }
1643
1644   if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
1645       cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
1646     {
1647       gint k;
1648       
1649       if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
1650         WIN32_GDI_FAILED ("SelectPalette");
1651       else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
1652         WIN32_GDI_FAILED ("RealizePalette");
1653       else if (k > 0)
1654         GDK_NOTE (MISC_OR_COLORMAP,
1655                   g_print ("blit_from_window: realized %d\n", k));
1656     }
1657   
1658   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1659                      srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1660   
1661   if (holdpal != NULL)
1662     GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
1663   
1664   GDI_CALL (ReleaseDC, (src->handle, srcdc));
1665 }
1666
1667 void
1668 _gdk_win32_blit (gboolean              use_fg_bg,
1669                  GdkDrawableImplWin32 *drawable,
1670                  GdkGC                *gc,
1671                  GdkDrawable          *src,
1672                  gint                  xsrc,
1673                  gint                  ysrc,
1674                  gint                  xdest,
1675                  gint                  ydest,
1676                  gint                  width,
1677                  gint                  height)
1678 {
1679   HDC hdc;
1680   HRGN src_rgn, draw_rgn, outside_rgn;
1681   RECT r;
1682   GdkDrawableImplWin32 *draw_impl;
1683   GdkDrawableImplWin32 *src_impl = NULL;
1684   gint src_width, src_height;
1685   
1686   GDK_NOTE (MISC, g_print ("_gdk_win32_blit: src:%s %dx%d@+%d+%d\n"
1687                            "                 dst:%s @+%d+%d use_fg_bg=%d\n",
1688                            _gdk_win32_drawable_description (src),
1689                            width, height, xsrc, ysrc,
1690                            _gdk_win32_drawable_description ((GdkDrawable *) drawable),
1691                            xdest, ydest,
1692                            use_fg_bg));
1693
1694   draw_impl = (GdkDrawableImplWin32 *) drawable;
1695
1696   if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
1697     src_impl = (GdkDrawableImplWin32 *) src;
1698   else if (GDK_IS_WINDOW (src))
1699     src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
1700   else if (GDK_IS_PIXMAP (src))
1701     src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
1702   else
1703     g_assert_not_reached ();
1704
1705   hdc = gdk_win32_hdc_get ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
1706
1707   gdk_drawable_get_size (src, &src_width, &src_height);
1708
1709   if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
1710     WIN32_GDI_FAILED ("CreateRectRgn");
1711   else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
1712                                       xsrc + width + 1,
1713                                       ysrc + height + 1)) == NULL)
1714     WIN32_GDI_FAILED ("CreateRectRgn");
1715   else
1716     {
1717       if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
1718         {
1719           int comb;
1720           
1721           /* If we are drawing on a window, calculate the region that is
1722            * outside the source pixmap, and invalidate that, causing it to
1723            * be cleared. Not completely sure whether this is always needed. XXX
1724            */
1725           SetRectEmpty (&r);
1726           outside_rgn = CreateRectRgnIndirect (&r);
1727           
1728           if ((comb = CombineRgn (outside_rgn,
1729                                   draw_rgn, src_rgn,
1730                                   RGN_DIFF)) == ERROR)
1731             WIN32_GDI_FAILED ("CombineRgn");
1732           else if (comb != NULLREGION)
1733             {
1734               OffsetRgn (outside_rgn, xdest, ydest);
1735               GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
1736                                g_print ("...calling InvalidateRgn, "
1737                                         "bbox: %ldx%ld@+%ld+%ld\n",
1738                                         r.right - r.left - 1, r.bottom - r.top - 1,
1739                                         r.left, r.top)));
1740               InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
1741             }
1742           GDI_CALL (DeleteObject, (outside_rgn));
1743         }
1744
1745 #if 1 /* Don't know if this is necessary XXX */
1746       if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
1747         g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
1748       
1749       GetRgnBox (draw_rgn, &r);
1750       if (r.left != xsrc || r.top != ysrc ||
1751           r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
1752         {
1753           xdest += r.left - xsrc;
1754           xsrc = r.left;
1755           ydest += r.top - ysrc;
1756           ysrc = r.top;
1757           width = r.right - xsrc - 1;
1758           height = r.bottom - ysrc - 1;
1759           
1760           GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
1761                                    "dest: @+%d+%d\n",
1762                                    width, height, xsrc, ysrc,
1763                                    xdest, ydest));
1764         }
1765 #endif
1766
1767       GDI_CALL (DeleteObject, (src_rgn));
1768       GDI_CALL (DeleteObject, (draw_rgn));
1769     }
1770
1771   if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
1772     blit_from_pixmap (use_fg_bg, draw_impl, hdc,
1773                       (GdkPixmapImplWin32 *) src_impl, GDK_GC_WIN32 (gc),
1774                       xsrc, ysrc, xdest, ydest, width, height);
1775   else if (draw_impl->handle == src_impl->handle)
1776     blit_inside_window (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
1777   else
1778     blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
1779   gdk_win32_hdc_release ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
1780 }
1781
1782 static void
1783 gdk_win32_draw_image (GdkDrawable     *drawable,
1784                       GdkGC           *gc,
1785                       GdkImage        *image,
1786                       gint             xsrc,
1787                       gint             ysrc,
1788                       gint             xdest,
1789                       gint             ydest,
1790                       gint             width,
1791                       gint             height)
1792 {
1793   g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1794
1795   _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
1796                    gc, (GdkPixmap *) image->windowing_data,
1797                    xsrc, ysrc, xdest, ydest, width, height);
1798 }
1799
1800 static gint
1801 gdk_win32_get_depth (GdkDrawable *drawable)
1802 {
1803   /* This is a bit bogus but I'm not sure the other way is better */
1804
1805   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1806 }
1807
1808 static GdkScreen*
1809 gdk_win32_get_screen (GdkDrawable *drawable)
1810 {
1811   return gdk_screen_get_default ();
1812 }
1813  
1814 static GdkVisual*
1815 gdk_win32_get_visual (GdkDrawable *drawable)
1816 {
1817   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1818 }
1819
1820 HGDIOBJ
1821 gdk_win32_drawable_get_handle (GdkDrawable *drawable)
1822 {
1823   return GDK_DRAWABLE_HANDLE (drawable);
1824 }
1825
1826 gboolean
1827 gdk_draw_rectangle_alpha_libgtk_only (GdkDrawable *drawable,
1828                                       gint         x,
1829                                       gint         y,
1830                                       gint         width,
1831                                       gint         height,
1832                                       GdkColor    *color,
1833                                       guint16      alpha)
1834 {
1835   return FALSE;
1836 }