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