]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Use X11 semantics for angles. Thanks to Tim Newsham.
[~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     for (i = 0; i < nsegs; i++)
1183       {
1184         segs[i].x1 -= x_offset;
1185         segs[i].y1 -= y_offset;
1186         segs[i].x2 -= x_offset;
1187         segs[i].y2 -= y_offset;
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       if (gcwin32->pen_width <= 1 && !IS_WIN_NT())
1242         {
1243           GdkSegment *ps = &segs[nsegs-1];
1244           int xc = (ps->y2 == ps->y1) ? 0 : ((ps->x1 < ps->x2) ? 1 : -1);
1245           int yc = (ps->x2 == ps->x1) ? 0 : ((ps->y1 < ps->y2) ? 1 : -1);
1246         /* don't forget single point lines */
1247         xc = (0 == xc && 0 == yc) ? 1 : xc;
1248
1249           GDI_CALL (LineTo, (hdc, ps->x2 + xc, ps->y2 + yc));
1250         }
1251     }
1252 }
1253
1254 static void
1255 gdk_win32_draw_segments (GdkDrawable *drawable,
1256                          GdkGC       *gc,
1257                          GdkSegment  *segs,
1258                          gint         nsegs)
1259 {
1260   GdkRectangle bounds;
1261   GdkRegion *region;
1262   gint i;
1263
1264   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %s %d segs\n",
1265                            _gdk_win32_drawable_description (drawable),
1266                            nsegs));
1267
1268   bounds.x = G_MAXINT;
1269   bounds.y = G_MAXINT;
1270   bounds.width = 0;
1271   bounds.height = 0;
1272
1273   for (i = 0; i < nsegs; i++)
1274     {
1275       bounds.x = MIN (bounds.x, segs[i].x1);
1276       bounds.x = MIN (bounds.x, segs[i].x2);
1277       bounds.y = MIN (bounds.y, segs[i].y1);
1278       bounds.y = MIN (bounds.y, segs[i].y2);
1279     }
1280
1281   for (i = 0; i < nsegs; i++)
1282     {
1283       bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
1284       bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
1285       bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
1286       bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
1287     }
1288
1289   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1290
1291   generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
1292                 draw_segments, region, segs, nsegs);
1293
1294   gdk_region_destroy (region);
1295 }
1296
1297 static void
1298 draw_lines (GdkGCWin32 *gcwin32,
1299             HDC         hdc,
1300             gint        x_offset,
1301             gint        y_offset,
1302             va_list     args)
1303 {
1304   POINT *pts;
1305   gint npoints;
1306   gint i;
1307
1308   pts = va_arg (args, POINT *);
1309   npoints = va_arg (args, gint);
1310
1311   if (x_offset != 0 || y_offset != 0)
1312     for (i = 0; i < npoints; i++)
1313       {
1314         pts[i].x -= x_offset;
1315         pts[i].y -= y_offset;
1316       }
1317   
1318   if (gcwin32->pen_dashes && !IS_WIN_NT ())
1319     {
1320       for (i = 0; i < npoints - 1; i++)
1321         {
1322           if (pts[i].x == pts[i+1].x)
1323             {
1324               int y1, y2;
1325               if (pts[i].y > pts[i+1].y)
1326                 y1 = pts[i+1].y, y2 = pts[i].y;
1327               else
1328                 y1 = pts[i].y, y2 = pts[i+1].y;
1329               
1330               render_line_vertical (hdc, pts[i].x, y1, y2,
1331                                     gcwin32->pen_width,
1332                                     gcwin32->pen_dashes,
1333                                     gcwin32->pen_num_dashes);
1334             }
1335           else if (pts[i].y == pts[i+1].y)
1336             {
1337               int x1, x2;
1338               if (pts[i].x > pts[i+1].x)
1339                 x1 = pts[i+1].x, x2 = pts[i].x;
1340               else
1341                 x1 = pts[i].x, x2 = pts[i+1].x;
1342
1343               render_line_horizontal (hdc, x1, x2, pts[i].y,
1344                                       gcwin32->pen_width,
1345                                       gcwin32->pen_dashes,
1346                                       gcwin32->pen_num_dashes);
1347             }
1348           else
1349             GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
1350               GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
1351         }
1352     }
1353   else
1354     GDI_CALL (Polyline, (hdc, pts, npoints));
1355 }
1356
1357 static void
1358 gdk_win32_draw_lines (GdkDrawable *drawable,
1359                       GdkGC       *gc,
1360                       GdkPoint    *points,
1361                       gint         npoints)
1362 {
1363   GdkRectangle bounds;
1364   GdkRegion *region;
1365   POINT *pts;
1366   int i;
1367
1368   GDK_NOTE (MISC, g_print ("gdk_win32_draw_lines: %s %d points\n",
1369                            _gdk_win32_drawable_description (drawable),
1370                            npoints));
1371
1372   if (npoints < 2)
1373     return;
1374
1375   bounds.x = G_MAXINT;
1376   bounds.y = G_MAXINT;
1377   bounds.width = 0;
1378   bounds.height = 0;
1379
1380   pts = g_new (POINT, npoints);
1381
1382   for (i = 0; i < npoints; i++)
1383     {
1384       bounds.x = MIN (bounds.x, points[i].x);
1385       bounds.y = MIN (bounds.y, points[i].y);
1386       pts[i].x = points[i].x;
1387       pts[i].y = points[i].y;
1388     }
1389
1390   for (i = 0; i < npoints; i++)
1391     {
1392       bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1393       bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1394     }
1395
1396   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1397
1398   generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
1399                 draw_lines, region, pts, npoints);
1400
1401   gdk_region_destroy (region);
1402   g_free (pts);
1403 }
1404
1405 static void
1406 draw_glyphs (GdkGCWin32 *gcwin32,
1407              HDC         hdc,
1408              gint        x_offset,
1409              gint        y_offset,
1410              va_list     args)
1411 {
1412   PangoFont *font;
1413   gint x;
1414   gint y;
1415   PangoGlyphString *glyphs;
1416
1417   font = va_arg (args, PangoFont *);
1418   x = va_arg (args, gint);
1419   y = va_arg (args, gint);
1420   glyphs = va_arg (args, PangoGlyphString *);
1421
1422   x -= x_offset;
1423   y -= y_offset;
1424
1425   pango_win32_render (hdc, font, glyphs, x, y);
1426 }
1427
1428 static void
1429 gdk_win32_draw_glyphs (GdkDrawable      *drawable,
1430                        GdkGC            *gc,
1431                        PangoFont        *font,
1432                        gint              x,
1433                        gint              y,
1434                        PangoGlyphString *glyphs)
1435 {
1436   GdkRectangle bounds;
1437   GdkRegion *region;
1438   PangoRectangle ink_rect;
1439
1440   pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
1441
1442   bounds.x = x + PANGO_PIXELS (ink_rect.x) - 1;
1443   bounds.y = y + PANGO_PIXELS (ink_rect.y) - 1;
1444   bounds.width = PANGO_PIXELS (ink_rect.width) + 2;
1445   bounds.height = PANGO_PIXELS (ink_rect.height) + 2;
1446   region = gdk_region_rectangle (&bounds);
1447   
1448   generic_draw (drawable, gc, GDK_GC_FOREGROUND|GDK_GC_FONT,
1449                 draw_glyphs, region, font, x, y, glyphs);
1450
1451   gdk_region_destroy (region);
1452 }
1453
1454 static void
1455 blit_from_pixmap (gboolean              use_fg_bg,
1456                   GdkDrawableImplWin32 *dest,
1457                   HDC                   hdc,
1458                   GdkPixmapImplWin32   *src,
1459                   GdkGCWin32           *gcwin32,
1460                   gint                  xsrc,
1461                   gint                  ysrc,
1462                   gint                  xdest,
1463                   gint                  ydest,
1464                   gint                  width,
1465                   gint                  height)
1466 {
1467   HDC srcdc;
1468   HBITMAP holdbitmap;
1469   RGBQUAD oldtable[256], newtable[256];
1470   COLORREF bg, fg;
1471
1472   gint newtable_size = 0, oldtable_size = 0;
1473   gboolean ok = TRUE;
1474   
1475   GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
1476
1477   if (!(srcdc = CreateCompatibleDC (NULL)))
1478     {
1479       WIN32_GDI_FAILED ("CreateCompatibleDC");
1480       return;
1481     }
1482       
1483   if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
1484     WIN32_GDI_FAILED ("SelectObject");
1485   else
1486     {
1487       if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
1488         {
1489           /* Blitting from a 1, 4 or 8-bit pixmap */
1490
1491           if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
1492             WIN32_GDI_FAILED ("GetDIBColorTable");
1493           else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
1494             {
1495               /* Blitting from an 1-bit pixmap */
1496
1497               gint bgix, fgix;
1498               
1499               if (use_fg_bg)
1500                 {
1501                   bgix = gcwin32->background;
1502                   fgix = gcwin32->foreground;
1503                 }
1504               else
1505                 {
1506                   bgix = 0;
1507                   fgix = 1;
1508                 }
1509               
1510               if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
1511                   GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
1512                 {
1513                   /* Destination is also pixmap, get fg and bg from
1514                    * its palette. Either use the foreground and
1515                    * background pixel values in the GC (only in the
1516                    * case of gdk_image_put(), cf. XPutImage()), or 0
1517                    * and 1 to index the palette.
1518                    */
1519                   if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
1520                       !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
1521                     ok = FALSE;
1522                 }
1523               else
1524                 {
1525                   /* Destination is a window, get fg and bg from its
1526                    * colormap
1527                    */
1528
1529                   bg = _gdk_win32_colormap_color (dest->colormap, bgix);
1530                   fg = _gdk_win32_colormap_color (dest->colormap, fgix);
1531                   newtable[0].rgbBlue = GetBValue (bg);
1532                   newtable[0].rgbGreen = GetGValue (bg);
1533                   newtable[0].rgbRed = GetRValue (bg);
1534                   newtable[0].rgbReserved = 0;
1535                   newtable[1].rgbBlue = GetBValue (fg);
1536                   newtable[1].rgbGreen = GetGValue (fg);
1537                   newtable[1].rgbRed = GetRValue (fg);
1538                   newtable[1].rgbReserved = 0;
1539                 }
1540               if (ok)
1541                 GDK_NOTE (MISC, g_print ("bg: %02x %02x %02x "
1542                                          "fg: %02x %02x %02x\n",
1543                                          newtable[0].rgbRed,
1544                                          newtable[0].rgbGreen,
1545                                          newtable[0].rgbBlue,
1546                                          newtable[1].rgbRed,
1547                                          newtable[1].rgbGreen,
1548                                          newtable[1].rgbBlue));
1549               newtable_size = 2;
1550             }
1551           else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
1552             {
1553               /* Destination is pixmap, get its color table */
1554               
1555               if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
1556                 WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
1557             }
1558           
1559           /* If blitting between pixmaps, set source's color table */
1560           if (ok && newtable_size > 0)
1561             {
1562               GDK_NOTE (MISC_OR_COLORMAP,
1563                         g_print ("blit_from_pixmap: set color table"
1564                                  " hdc=%p count=%d\n",
1565                                  srcdc, newtable_size));
1566               if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
1567                 ok = FALSE;
1568             }
1569         }
1570       
1571       if (ok)
1572         GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1573                            srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1574       
1575       /* Restore source's color table if necessary */
1576       if (ok && newtable_size > 0 && oldtable_size > 0)
1577         {
1578           GDK_NOTE (MISC_OR_COLORMAP,
1579                     g_print ("blit_from_pixmap: reset color table"
1580                              " hdc=%p count=%d\n",
1581                              srcdc, oldtable_size));
1582           GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
1583         }
1584       
1585       GDI_CALL (SelectObject, (srcdc, holdbitmap));
1586     }
1587   GDI_CALL (DeleteDC, (srcdc));
1588 }
1589
1590 static void
1591 blit_inside_window (HDC         hdc,
1592                     GdkGCWin32 *gcwin32,
1593                     gint        xsrc,
1594                     gint        ysrc,
1595                     gint        xdest,
1596                     gint        ydest,
1597                     gint        width,
1598                     gint        height)
1599
1600 {
1601   GDK_NOTE (MISC, g_print ("blit_inside_window\n"));
1602
1603   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1604                      hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1605 }
1606
1607 static void
1608 blit_from_window (HDC                   hdc,
1609                   GdkGCWin32           *gcwin32,
1610                   GdkDrawableImplWin32 *src,
1611                   gint                  xsrc,
1612                   gint                  ysrc,
1613                   gint                  xdest,
1614                   gint                  ydest,
1615                   gint                  width,
1616                   gint                  height)
1617 {
1618   HDC srcdc;
1619   HPALETTE holdpal = NULL;
1620   GdkColormap *cmap = gdk_colormap_get_system ();
1621
1622   GDK_NOTE (MISC, g_print ("blit_from_window\n"));
1623
1624   if ((srcdc = GetDC (src->handle)) == NULL)
1625     {
1626       WIN32_GDI_FAILED ("GetDC");
1627       return;
1628     }
1629
1630   if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
1631       cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
1632     {
1633       gint k;
1634       
1635       if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
1636         WIN32_GDI_FAILED ("SelectPalette");
1637       else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
1638         WIN32_GDI_FAILED ("RealizePalette");
1639       else if (k > 0)
1640         GDK_NOTE (MISC_OR_COLORMAP,
1641                   g_print ("blit_from_window: realized %d\n", k));
1642     }
1643   
1644   GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1645                      srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1646   
1647   if (holdpal != NULL)
1648     GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
1649   
1650   GDI_CALL (ReleaseDC, (src->handle, srcdc));
1651 }
1652
1653 void
1654 _gdk_win32_blit (gboolean              use_fg_bg,
1655                  GdkDrawableImplWin32 *drawable,
1656                  GdkGC                *gc,
1657                  GdkDrawable          *src,
1658                  gint                  xsrc,
1659                  gint                  ysrc,
1660                  gint                  xdest,
1661                  gint                  ydest,
1662                  gint                  width,
1663                  gint                  height)
1664 {
1665   HDC hdc;
1666   HRGN src_rgn, draw_rgn, outside_rgn;
1667   RECT r;
1668   GdkDrawableImplWin32 *draw_impl;
1669   GdkDrawableImplWin32 *src_impl = NULL;
1670   gint src_width, src_height;
1671   
1672   GDK_NOTE (MISC, g_print ("_gdk_win32_blit: src:%s %dx%d@+%d+%d\n"
1673                            "                 dst:%s @+%d+%d use_fg_bg=%d\n",
1674                            _gdk_win32_drawable_description (src),
1675                            width, height, xsrc, ysrc,
1676                            _gdk_win32_drawable_description ((GdkDrawable *) drawable),
1677                            xdest, ydest,
1678                            use_fg_bg));
1679
1680   draw_impl = (GdkDrawableImplWin32 *) drawable;
1681
1682   if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
1683     src_impl = (GdkDrawableImplWin32 *) src;
1684   else if (GDK_IS_WINDOW (src))
1685     src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
1686   else if (GDK_IS_PIXMAP (src))
1687     src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
1688   else
1689     g_assert_not_reached ();
1690
1691   hdc = gdk_win32_hdc_get ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
1692
1693   gdk_drawable_get_size (src, &src_width, &src_height);
1694
1695   if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
1696     WIN32_GDI_FAILED ("CreateRectRgn");
1697   else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
1698                                       xsrc + width + 1,
1699                                       ysrc + height + 1)) == NULL)
1700     WIN32_GDI_FAILED ("CreateRectRgn");
1701   else
1702     {
1703       if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
1704         {
1705           int comb;
1706           
1707           /* If we are drawing on a window, calculate the region that is
1708            * outside the source pixmap, and invalidate that, causing it to
1709            * be cleared. Not completely sure whether this is always needed. XXX
1710            */
1711           SetRectEmpty (&r);
1712           outside_rgn = CreateRectRgnIndirect (&r);
1713           
1714           if ((comb = CombineRgn (outside_rgn,
1715                                   draw_rgn, src_rgn,
1716                                   RGN_DIFF)) == ERROR)
1717             WIN32_GDI_FAILED ("CombineRgn");
1718           else if (comb != NULLREGION)
1719             {
1720               OffsetRgn (outside_rgn, xdest, ydest);
1721               GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
1722                                g_print ("...calling InvalidateRgn, "
1723                                         "bbox: %ldx%ld@+%ld+%ld\n",
1724                                         r.right - r.left - 1, r.bottom - r.top - 1,
1725                                         r.left, r.top)));
1726               InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
1727             }
1728           GDI_CALL (DeleteObject, (outside_rgn));
1729         }
1730
1731 #if 1 /* Don't know if this is necessary XXX */
1732       if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
1733         g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
1734       
1735       GetRgnBox (draw_rgn, &r);
1736       if (r.left != xsrc || r.top != ysrc ||
1737           r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
1738         {
1739           xdest += r.left - xsrc;
1740           xsrc = r.left;
1741           ydest += r.top - ysrc;
1742           ysrc = r.top;
1743           width = r.right - xsrc - 1;
1744           height = r.bottom - ysrc - 1;
1745           
1746           GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
1747                                    "dest: @+%d+%d\n",
1748                                    width, height, xsrc, ysrc,
1749                                    xdest, ydest));
1750         }
1751 #endif
1752
1753       GDI_CALL (DeleteObject, (src_rgn));
1754       GDI_CALL (DeleteObject, (draw_rgn));
1755     }
1756
1757   if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
1758     blit_from_pixmap (use_fg_bg, draw_impl, hdc,
1759                       (GdkPixmapImplWin32 *) src_impl, GDK_GC_WIN32 (gc),
1760                       xsrc, ysrc, xdest, ydest, width, height);
1761   else if (draw_impl->handle == src_impl->handle)
1762     blit_inside_window (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
1763   else
1764     blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
1765   gdk_win32_hdc_release ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
1766 }
1767
1768 static void
1769 gdk_win32_draw_image (GdkDrawable     *drawable,
1770                       GdkGC           *gc,
1771                       GdkImage        *image,
1772                       gint             xsrc,
1773                       gint             ysrc,
1774                       gint             xdest,
1775                       gint             ydest,
1776                       gint             width,
1777                       gint             height)
1778 {
1779   g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1780
1781   _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
1782                    gc, (GdkPixmap *) image->windowing_data,
1783                    xsrc, ysrc, xdest, ydest, width, height);
1784 }
1785
1786 static gint
1787 gdk_win32_get_depth (GdkDrawable *drawable)
1788 {
1789   /* This is a bit bogus but I'm not sure the other way is better */
1790
1791   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1792 }
1793
1794 static GdkScreen*
1795 gdk_win32_get_screen (GdkDrawable *drawable)
1796 {
1797   return gdk_screen_get_default ();
1798 }
1799  
1800 static GdkVisual*
1801 gdk_win32_get_visual (GdkDrawable *drawable)
1802 {
1803   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1804 }
1805
1806 HGDIOBJ
1807 gdk_win32_drawable_get_handle (GdkDrawable *drawable)
1808 {
1809   return GDK_DRAWABLE_HANDLE (drawable);
1810 }