]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Large changes to the Win32 backend, partially made necessary by the
[~andy/gtk] / gdk / win32 / gdkdrawable-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <math.h>
30 #include <glib.h>
31
32 #ifndef G_PI
33 #define G_PI 3.14159265358979323846
34 #endif
35
36 #include "gdkinternals.h"
37 #include "gdkprivate-win32.h"
38
39 static void gdk_win32_drawable_destroy   (GdkDrawable     *drawable);
40
41 static void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
42                                       GdkGC          *gc,
43                                       gint            filled,
44                                       gint            x,
45                                       gint            y,
46                                       gint            width,
47                                       gint            height);
48 static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
49                                       GdkGC          *gc,
50                                       gint            filled,
51                                       gint            x,
52                                       gint            y,
53                                       gint            width,
54                                       gint            height,
55                                       gint            angle1,
56                                       gint            angle2);
57 static void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
58                                       GdkGC          *gc,
59                                       gint            filled,
60                                       GdkPoint       *points,
61                                       gint            npoints);
62 static void gdk_win32_draw_text      (GdkDrawable    *drawable,
63                                       GdkFont        *font,
64                                       GdkGC          *gc,
65                                       gint            x,
66                                       gint            y,
67                                       const gchar    *text,
68                                       gint            text_length);
69 static void gdk_win32_draw_text_wc   (GdkDrawable    *drawable,
70                                       GdkFont        *font,
71                                       GdkGC          *gc,
72                                       gint            x,
73                                       gint            y,
74                                       const GdkWChar *text,
75                                       gint            text_length);
76 static void gdk_win32_draw_drawable  (GdkDrawable    *drawable,
77                                       GdkGC          *gc,
78                                       GdkPixmap      *src,
79                                       gint            xsrc,
80                                       gint            ysrc,
81                                       gint            xdest,
82                                       gint            ydest,
83                                       gint            width,
84                                       gint            height);
85 static void gdk_win32_draw_points    (GdkDrawable    *drawable,
86                                       GdkGC          *gc,
87                                       GdkPoint       *points,
88                                       gint            npoints);
89 static void gdk_win32_draw_segments  (GdkDrawable    *drawable,
90                                       GdkGC          *gc,
91                                       GdkSegment     *segs,
92                                       gint            nsegs);
93 static void gdk_win32_draw_lines     (GdkDrawable    *drawable,
94                                       GdkGC          *gc,
95                                       GdkPoint       *points,
96                                       gint            npoints);
97
98 GdkDrawableClass _gdk_win32_drawable_class = {
99   gdk_win32_drawable_destroy,
100   _gdk_win32_gc_new,
101   gdk_win32_draw_rectangle,
102   gdk_win32_draw_arc,
103   gdk_win32_draw_polygon,
104   gdk_win32_draw_text,
105   gdk_win32_draw_text_wc,
106   gdk_win32_draw_drawable,
107   gdk_win32_draw_points,
108   gdk_win32_draw_segments,
109   gdk_win32_draw_lines
110 };
111
112 /*****************************************************
113  * Win32 specific implementations of generic functions *
114  *****************************************************/
115
116 GdkColormap*
117 gdk_drawable_get_colormap (GdkDrawable *drawable)
118 {
119   GdkDrawablePrivate *drawable_private;
120   
121   g_return_val_if_fail (drawable != NULL, NULL);
122   drawable_private = (GdkDrawablePrivate*) drawable;
123
124   if (!GDK_DRAWABLE_DESTROYED (drawable))
125     {
126       if (drawable_private->colormap == NULL)
127         return gdk_colormap_get_system (); /* XXX ??? */
128       else
129         return drawable_private->colormap;
130     }
131   
132   return NULL;
133 }
134
135 void
136 gdk_drawable_set_colormap (GdkDrawable *drawable,
137                            GdkColormap *colormap)
138 {
139   GdkDrawablePrivate *drawable_private;
140   GdkColormapPrivateWin32 *colormap_private;
141   
142   g_return_if_fail (drawable != NULL);
143   g_return_if_fail (colormap != NULL);
144   
145   drawable_private = (GdkDrawablePrivate *) drawable;
146   colormap_private = (GdkColormapPrivateWin32 *) colormap;
147   
148   if (!GDK_DRAWABLE_DESTROYED (drawable))
149     {
150       if (GDK_IS_WINDOW (drawable))
151         {
152           g_return_if_fail (colormap_private->base.visual !=
153                             ((GdkColormapPrivate *) (drawable_private->colormap))->visual);
154           /* XXX ??? */
155           GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n",
156                                    GDK_DRAWABLE_XID (drawable),
157                                    colormap_private->xcolormap));
158         }
159       if (drawable_private->colormap)
160         gdk_colormap_unref (drawable_private->colormap);
161       drawable_private->colormap = colormap;
162       gdk_colormap_ref (drawable_private->colormap);
163       
164       if (GDK_IS_WINDOW (drawable)
165           && drawable_private->window_type != GDK_WINDOW_TOPLEVEL)
166         gdk_window_add_colormap_windows (drawable);
167     }
168 }
169
170 /* Drawing
171  */
172 static void 
173 gdk_win32_drawable_destroy (GdkDrawable *drawable)
174 {
175   
176 }
177
178 static void
179 gdk_win32_draw_rectangle (GdkDrawable *drawable,
180                           GdkGC       *gc,
181                           gint         filled,
182                           gint         x,
183                           gint         y,
184                           gint         width,
185                           gint         height)
186 {
187   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
188   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
189   HDC hdc;
190   HGDIOBJ oldpen, oldbrush;
191   HBRUSH hbr = NULL;
192   POINT pts[4];
193   gboolean ok = TRUE;
194
195   GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
196                            GDK_DRAWABLE_XID (drawable),
197                            gc_private,
198                            (filled ? "fill " : ""),
199                            width, height, x, y));
200     
201   hdc = gdk_gc_predraw (drawable, gc_private,
202                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
203
204 #if 0
205   {
206     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
207     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
208     LOGBRUSH lbr;
209     LOGPEN lpen;
210     GetObject (hbr, sizeof (lbr), &lbr);
211     GetObject (hpen, sizeof (lpen), &lpen);
212     
213     g_print ("current brush: style = %s, color = 0x%.08x\n",
214              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
215              lbr.lbColor);
216     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
217              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
218              lpen.lopnWidth,
219              lpen.lopnColor);
220   }
221 #endif
222
223   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
224     {
225       if (!BeginPath (hdc))
226         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
227
228       /* Win9x doesn't support Rectangle calls in a path,
229        * thus use Polyline.
230        */
231           
232       pts[0].x = x;
233       pts[0].y = y;
234       pts[1].x = x + width + 1;
235       pts[1].y = y;
236       pts[2].x = x + width + 1;
237       pts[2].y = y + height + 1;
238       pts[3].x = x;
239       pts[3].y = y + height + 1;
240       
241       if (ok)
242         MoveToEx (hdc, x, y, NULL);
243       
244       if (ok && !Polyline (hdc, pts, 4))
245         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
246           
247       if (ok && !CloseFigure (hdc))
248         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
249
250       if (ok && !EndPath (hdc))
251         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
252           
253       if (ok && !filled)
254         if (!WidenPath (hdc))
255           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
256           
257       if (ok && !FillPath (hdc))
258         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
259
260       if (hbr != NULL)
261         if (!DeleteObject (hbr))
262           WIN32_GDI_FAILED ("DeleteObject");
263     }
264   else
265     {
266       if (filled)
267         oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
268       else
269         oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
270   
271       if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
272         WIN32_GDI_FAILED ("Rectangle");
273   
274       if (filled)
275         SelectObject (hdc, oldpen);
276       else
277         SelectObject (hdc, oldbrush);
278     }
279
280   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
281 }
282
283 static void
284 gdk_win32_draw_arc (GdkDrawable *drawable,
285                     GdkGC       *gc,
286                     gint         filled,
287                     gint         x,
288                     gint         y,
289                     gint         width,
290                     gint         height,
291                     gint         angle1,
292                     gint         angle2)
293 {
294   GdkGCPrivate *gc_private;
295   HDC hdc;
296   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
297
298   gc_private = (GdkGCPrivate*) gc;
299
300   GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
301                            GDK_DRAWABLE_XID (drawable),
302                            x, y, width, height, angle1, angle2));
303
304   if (width != 0 && height != 0 && angle2 != 0)
305     {
306       hdc = gdk_gc_predraw (drawable, gc_private,
307                             GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
308
309       if (angle2 >= 360*64)
310         {
311           nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
312         }
313       else if (angle2 > 0)
314         {
315           /* The 100. is just an arbitrary value */
316           nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
317           nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
318           nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
319           nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
320         }
321       else
322         {
323           nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
324           nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
325           nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
326           nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
327         }
328
329       /* GDK_OPAQUE_STIPPLED arcs not implemented. */
330
331       if (filled)
332         {
333           GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
334                                    x, y, x+width, y+height,
335                                    nXStartArc, nYStartArc,
336                                    nXEndArc, nYEndArc));
337           if (!Pie (hdc, x, y, x+width, y+height,
338                     nXStartArc, nYStartArc, nXEndArc, nYEndArc))
339             WIN32_GDI_FAILED ("Pie");
340         }
341       else
342         {
343           GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
344                                    x, y, x+width, y+height,
345                                    nXStartArc, nYStartArc,
346                                    nXEndArc, nYEndArc));
347           if (!Arc (hdc, x, y, x+width, y+height,
348                     nXStartArc, nYStartArc, nXEndArc, nYEndArc))
349             WIN32_GDI_FAILED ("Arc");
350         }
351       gdk_gc_postdraw (drawable, gc_private,
352                        GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
353     }
354 }
355
356 static void
357 gdk_win32_draw_polygon (GdkDrawable *drawable,
358                         GdkGC       *gc,
359                         gint         filled,
360                         GdkPoint    *points,
361                         gint         npoints)
362 {
363   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
364   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
365   HDC hdc;
366   HBRUSH hbr = NULL;
367   POINT *pts;
368   gboolean ok = TRUE;
369   int i;
370
371   GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%d) %d\n",
372                            GDK_DRAWABLE_XID (drawable), gc_private,
373                            npoints));
374
375   if (npoints < 2)
376     return;
377
378   hdc = gdk_gc_predraw (drawable, gc_private,
379                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
380   pts = g_new (POINT, npoints+1);
381
382   for (i = 0; i < npoints; i++)
383     {
384       pts[i].x = points[i].x;
385       pts[i].y = points[i].y;
386     }
387   
388   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
389     {
390       if (!BeginPath (hdc))
391         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
392
393       MoveToEx (hdc, points[0].x, points[0].y, NULL);
394
395       if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
396         npoints--;
397
398       if (ok && !Polyline (hdc, pts, 4))
399         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
400           
401       if (ok && !CloseFigure (hdc))
402         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
403
404       if (ok && !EndPath (hdc))
405         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
406           
407       if (ok && !filled)
408         if (!WidenPath (hdc))
409           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
410           
411       if (ok && !FillPath (hdc))
412         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
413
414       if (hbr != NULL)
415         if (!DeleteObject (hbr))
416           WIN32_GDI_FAILED ("DeleteObject");
417     }
418   else
419     {
420       if (points[0].x != points[npoints-1].x
421           || points[0].y != points[npoints-1].y) 
422         {
423           pts[npoints].x = points[0].x;
424           pts[npoints].y = points[0].y;
425           npoints++;
426         }
427       
428       if (filled)
429         {
430           if (!Polygon (hdc, pts, npoints))
431             WIN32_GDI_FAILED ("Polygon");
432         }
433       else
434         {
435           if (!Polyline (hdc, pts, npoints))
436             WIN32_GDI_FAILED ("Polyline");
437         }
438     }
439   g_free (pts);
440   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
441 }
442
443 typedef struct
444 {
445   gint x, y;
446   HDC hdc;
447 } gdk_draw_text_arg;
448
449 static void
450 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
451                        const wchar_t      *wcstr,
452                        int                 wclen,
453                        void               *arg)
454 {
455   HGDIOBJ oldfont;
456   SIZE size;
457   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
458
459   if (!singlefont)
460     return;
461
462   if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL)
463     {
464       WIN32_GDI_FAILED ("SelectObject");
465       return;
466     }
467   
468   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
469     WIN32_GDI_FAILED ("TextOutW");
470   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
471   argp->x += size.cx;
472
473   SelectObject (argp->hdc, oldfont);
474 }
475
476 static void
477 gdk_win32_draw_text (GdkDrawable *drawable,
478                      GdkFont     *font,
479                      GdkGC       *gc,
480                      gint         x,
481                      gint         y,
482                      const gchar *text,
483                      gint         text_length)
484 {
485   GdkGCPrivate *gc_private;
486   wchar_t *wcstr;
487   gint wlen;
488   gdk_draw_text_arg arg;
489
490
491   if (GDK_DRAWABLE_DESTROYED (drawable))
492     return;
493
494   if (text_length == 0)
495     return;
496
497   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
498
499   gc_private = (GdkGCPrivate*) gc;
500
501   arg.x = x;
502   arg.y = y;
503   arg.hdc = gdk_gc_predraw (drawable, gc_private,
504                             GDK_GC_FOREGROUND|GDK_GC_FONT);
505
506   GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
507                            GDK_DRAWABLE_XID (drawable),
508                            x, y,
509                            (text_length > 10 ? 10 : text_length),
510                            text, text_length));
511   
512   wcstr = g_new (wchar_t, text_length);
513   if (text_length == 1)
514     {
515       /* For single characters, don't try to interpret as UTF-8. */
516       wcstr[0] = (guchar) text[0];
517       gdk_wchar_text_handle (font, wcstr, 1, gdk_draw_text_handler, &arg);
518     }
519   else
520     {
521       if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
522         g_warning ("gdk_win32_draw_text: gdk_nmbstowchar_ts failed");
523       else
524         gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
525     }
526
527   g_free (wcstr);
528
529   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
530 }
531
532 static void
533 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
534                         GdkFont          *font,
535                         GdkGC            *gc,
536                         gint              x,
537                         gint              y,
538                         const GdkWChar *text,
539                         gint              text_length)
540 {
541   GdkGCPrivate *gc_private;
542   gint i, wlen;
543   wchar_t *wcstr;
544   gdk_draw_text_arg arg;
545
546
547   if (GDK_DRAWABLE_DESTROYED (drawable))
548     return;
549
550   if (text_length == 0)
551     return;
552
553   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
554
555   gc_private = (GdkGCPrivate*) gc;
556
557   arg.x = x;
558   arg.y = y;
559   arg.hdc = gdk_gc_predraw (drawable, gc_private,
560                             GDK_GC_FOREGROUND|GDK_GC_FONT);
561
562   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
563                            GDK_DRAWABLE_XID (drawable),
564                            x, y, text_length));
565       
566   if (sizeof (wchar_t) != sizeof (GdkWChar))
567     {
568       wcstr = g_new (wchar_t, text_length);
569       for (i = 0; i < text_length; i++)
570         wcstr[i] = text[i];
571     }
572   else
573     wcstr = (wchar_t *) text;
574
575   gdk_wchar_text_handle (font, wcstr, text_length,
576                          gdk_draw_text_handler, &arg);
577
578   if (sizeof (wchar_t) != sizeof (GdkWChar))
579     g_free (wcstr);
580
581   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
582 }
583
584 static void
585 gdk_win32_draw_drawable (GdkDrawable *drawable,
586                          GdkGC       *gc,
587                          GdkPixmap   *src,
588                          gint         xsrc,
589                          gint         ysrc,
590                          gint         xdest,
591                          gint         ydest,
592                          gint         width,
593                          gint         height)
594 {
595   GdkDrawablePrivate *src_private;
596   GdkGCPrivate *gc_private;
597   HDC hdc;
598   HDC srcdc;
599   HGDIOBJ hgdiobj;
600   HRGN src_rgn, draw_rgn, outside_rgn;
601   RECT r;
602
603   src_private = (GdkDrawablePrivate*) src;
604   gc_private = (GdkGCPrivate*) gc;
605
606   GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
607                            "src: %#x %dx%d@+%d+%d"
608                            " dest: %#x @+%d+%d\n",
609                            GDK_DRAWABLE_XID (drawable),
610                            GDK_DRAWABLE_XID (src),
611                            width, height, xsrc, ysrc,
612                            GDK_DRAWABLE_XID (drawable), xdest, ydest));
613
614   hdc = gdk_gc_predraw (drawable, gc_private, 0);
615
616   src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
617   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
618   SetRectEmpty (&r);
619   outside_rgn = CreateRectRgnIndirect (&r);
620   
621   if (GDK_DRAWABLE_TYPE (drawable) != GDK_DRAWABLE_PIXMAP)
622     {
623       /* If we are drawing on a window, calculate the region that is
624        * outside the source pixmap, and invalidate that, causing it to
625        * be cleared. XXX
626        */
627       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
628         {
629           OffsetRgn (outside_rgn, xdest, ydest);
630           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
631                            g_print ("...calling InvalidateRgn, "
632                                     "bbox: %dx%d@+%d+%d\n",
633                                     r.right - r.left - 1, r.bottom - r.top - 1,
634                                     r.left, r.top)));
635           InvalidateRgn (GDK_DRAWABLE_XID (drawable), outside_rgn, TRUE);
636         }
637     }
638
639 #if 1 /* Don't know if this is necessary  */
640   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
641     g_warning ("gdk_win32_draw_drawable: CombineRgn returned a COMPLEXREGION");
642
643   GetRgnBox (draw_rgn, &r);
644   if (r.left != xsrc
645       || r.top != ysrc
646       || r.right != xsrc + width + 1
647       || r.bottom != ysrc + height + 1)
648     {
649       xdest += r.left - xsrc;
650       xsrc = r.left;
651       ydest += r.top - ysrc;
652       ysrc = r.top;
653       width = r.right - xsrc - 1;
654       height = r.bottom - ysrc - 1;
655       
656       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
657                                "dest: @+%d+%d\n",
658                                width, height, xsrc, ysrc,
659                                xdest, ydest));
660     }
661 #endif
662
663   DeleteObject (src_rgn);
664   DeleteObject (draw_rgn);
665   DeleteObject (outside_rgn);
666
667   /* Strangely enough, this function is called also to bitblt
668    * from a window.
669    */
670   if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
671     {
672       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
673         WIN32_GDI_FAILED ("CreateCompatibleDC");
674       
675       if ((hgdiobj = SelectObject (srcdc, GDK_DRAWABLE_XID (src))) == NULL)
676         WIN32_GDI_FAILED ("SelectObject");
677       
678       if (!BitBlt (hdc, xdest, ydest, width, height,
679                    srcdc, xsrc, ysrc, SRCCOPY))
680         WIN32_GDI_FAILED ("BitBlt");
681       
682       if ((SelectObject (srcdc, hgdiobj) == NULL))
683         WIN32_GDI_FAILED ("SelectObject");
684       
685       if (!DeleteDC (srcdc))
686         WIN32_GDI_FAILED ("DeleteDC");
687     }
688   else
689     {
690       if (GDK_DRAWABLE_XID(drawable) == GDK_DRAWABLE_XID (src))
691         {
692           /* Blitting inside a window, use ScrollDC */
693           RECT scrollRect, clipRect, emptyRect;
694           HRGN updateRgn;
695
696           scrollRect.left = MIN (xsrc, xdest);
697           scrollRect.top = MIN (ysrc, ydest);
698           scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
699           scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
700
701           clipRect.left = xdest;
702           clipRect.top = ydest;
703           clipRect.right = xdest + width + 1;
704           clipRect.bottom = ydest + height + 1;
705
706           SetRectEmpty (&emptyRect);
707           updateRgn = CreateRectRgnIndirect (&emptyRect);
708           if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
709                          &scrollRect, &clipRect,
710                          updateRgn, NULL))
711             WIN32_GDI_FAILED ("ScrollDC");
712           if (!InvalidateRgn (GDK_DRAWABLE_XID (drawable), updateRgn, FALSE))
713             WIN32_GDI_FAILED ("InvalidateRgn");
714           if (!UpdateWindow (GDK_DRAWABLE_XID (drawable)))
715             WIN32_GDI_FAILED ("UpdateWindow");
716         }
717       else
718         {
719           if ((srcdc = GetDC (GDK_DRAWABLE_XID (src))) == NULL)
720             WIN32_GDI_FAILED ("GetDC");
721           
722           if (!BitBlt (hdc, xdest, ydest, width, height,
723                        srcdc, xsrc, ysrc, SRCCOPY))
724             WIN32_GDI_FAILED ("BitBlt");
725           ReleaseDC (GDK_DRAWABLE_XID (src), srcdc);
726         }
727     }
728   gdk_gc_postdraw (drawable, gc_private, 0);
729 }
730
731 static void
732 gdk_win32_draw_points (GdkDrawable *drawable,
733                        GdkGC       *gc,
734                        GdkPoint    *points,
735                        gint         npoints)
736 {
737   HDC hdc;
738   COLORREF fg;
739   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
740   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
741   GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
742   GdkColormapPrivateWin32 *colormap_private =
743     (GdkColormapPrivateWin32 *) drawable_private->colormap;
744   int i;
745
746   hdc = gdk_gc_predraw (drawable, gc_private, 0);
747   
748   fg = gdk_colormap_color (colormap_private, gc_data->foreground);
749
750   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
751                            GDK_DRAWABLE_XID (drawable), npoints, fg));
752
753   for (i = 0; i < npoints; i++)
754     SetPixel (hdc, points[i].x, points[i].y, fg);
755
756   gdk_gc_postdraw (drawable, gc_private, 0);
757 }
758
759 static void
760 gdk_win32_draw_segments (GdkDrawable *drawable,
761                          GdkGC       *gc,
762                          GdkSegment  *segs,
763                          gint         nsegs)
764 {
765   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
766   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
767   HDC hdc;
768   HBRUSH hbr = NULL;
769   gboolean ok = TRUE;
770   int i;
771
772   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
773                            GDK_DRAWABLE_XID (drawable), nsegs));
774
775   hdc = gdk_gc_predraw (drawable, gc_private,
776                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
777
778   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
779     {
780       if (!BeginPath (hdc))
781         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
782       
783       for (i = 0; i < nsegs; i++)
784         {
785           if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
786             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
787           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
788             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
789           
790           /* Draw end pixel */
791           if (ok && gc_data->pen_width == 1)
792             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
793               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
794         }
795
796       if (ok && !EndPath (hdc))
797         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
798           
799       if (ok && !WidenPath (hdc))
800         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
801           
802       if (ok && !FillPath (hdc))
803         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
804
805       if (hbr != NULL)
806         if (!DeleteObject (hbr))
807           WIN32_GDI_FAILED ("DeleteObject");
808     }
809   else
810     {
811       for (i = 0; i < nsegs; i++)
812         {
813           if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
814             WIN32_GDI_FAILED ("MoveToEx");
815           if (!LineTo (hdc, segs[i].x2, segs[i].y2))
816             WIN32_GDI_FAILED ("LineTo");
817           
818           /* Draw end pixel */
819           if (gc_data->pen_width == 1)
820             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
821               WIN32_GDI_FAILED ("LineTo");
822         }
823     }
824   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
825 }
826
827 static void
828 gdk_win32_draw_lines (GdkDrawable *drawable,
829                       GdkGC       *gc,
830                       GdkPoint    *points,
831                       gint         npoints)
832 {
833   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
834   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
835   HDC hdc;
836   POINT *pts;
837   int i;
838
839   if (npoints < 2)
840     return;
841
842   hdc = gdk_gc_predraw (drawable, gc_private,
843                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
844 #if 1
845   pts = g_new (POINT, npoints);
846
847   for (i = 0; i < npoints; i++)
848     {
849       pts[i].x = points[i].x;
850       pts[i].y = points[i].y;
851     }
852   
853   if (!Polyline (hdc, pts, npoints))
854     WIN32_GDI_FAILED ("Polyline");
855   
856   g_free (pts);
857   
858   /* Draw end pixel */
859   if (gc_data->pen_width == 1)
860     {
861       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
862       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
863         WIN32_GDI_FAILED ("LineTo");
864     }
865 #else
866   MoveToEx (hdc, points[0].x, points[0].y, NULL);
867   for (i = 1; i < npoints; i++)
868     if (!LineTo (hdc, points[i].x, points[i].y))
869       WIN32_GDI_FAILED ("LineTo");
870   
871   /* Draw end pixel */
872   /* LineTo doesn't draw the last point, so if we have a pen width of 1,
873    * we draw the end pixel separately... With wider pens we don't care.
874    * //HB: But the NT developers don't read their API documentation ...
875    */
876   if (gc_data->pen_width == 1 && windows_version > 0x80000000)
877     if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
878       WIN32_GDI_FAILED ("LineTo");
879 #endif  
880   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
881 }