]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Store just pixel value of background colour.
[~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 "gdkdrawable.h"
37 #include "gdkprivate.h"
38 #include "gdkwindow.h"
39 #include "gdkwin32.h"
40
41 static void gdk_win32_drawable_destroy   (GdkDrawable     *drawable);
42
43 static void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
44                                       GdkGC          *gc,
45                                       gint            filled,
46                                       gint            x,
47                                       gint            y,
48                                       gint            width,
49                                       gint            height);
50 static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
51                                       GdkGC          *gc,
52                                       gint            filled,
53                                       gint            x,
54                                       gint            y,
55                                       gint            width,
56                                       gint            height,
57                                       gint            angle1,
58                                       gint            angle2);
59 static void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
60                                       GdkGC          *gc,
61                                       gint            filled,
62                                       GdkPoint       *points,
63                                       gint            npoints);
64 static void gdk_win32_draw_text      (GdkDrawable    *drawable,
65                                       GdkFont        *font,
66                                       GdkGC          *gc,
67                                       gint            x,
68                                       gint            y,
69                                       const gchar    *text,
70                                       gint            text_length);
71 static void gdk_win32_draw_text_wc   (GdkDrawable    *drawable,
72                                       GdkFont        *font,
73                                       GdkGC          *gc,
74                                       gint            x,
75                                       gint            y,
76                                       const GdkWChar *text,
77                                       gint            text_length);
78 static void gdk_win32_draw_drawable  (GdkDrawable    *drawable,
79                                       GdkGC          *gc,
80                                       GdkPixmap      *src,
81                                       gint            xsrc,
82                                       gint            ysrc,
83                                       gint            xdest,
84                                       gint            ydest,
85                                       gint            width,
86                                       gint            height);
87 static void gdk_win32_draw_points    (GdkDrawable    *drawable,
88                                       GdkGC          *gc,
89                                       GdkPoint       *points,
90                                       gint            npoints);
91 static void gdk_win32_draw_segments  (GdkDrawable    *drawable,
92                                       GdkGC          *gc,
93                                       GdkSegment     *segs,
94                                       gint            nsegs);
95 static void gdk_win32_draw_lines     (GdkDrawable    *drawable,
96                                       GdkGC          *gc,
97                                       GdkPoint       *points,
98                                       gint            npoints);
99
100 GdkDrawableClass _gdk_win32_drawable_class = {
101   gdk_win32_drawable_destroy,
102   _gdk_win32_gc_new,
103   gdk_win32_draw_rectangle,
104   gdk_win32_draw_arc,
105   gdk_win32_draw_polygon,
106   gdk_win32_draw_text,
107   gdk_win32_draw_text_wc,
108   gdk_win32_draw_drawable,
109   gdk_win32_draw_points,
110   gdk_win32_draw_segments,
111   gdk_win32_draw_lines
112 };
113
114 /*****************************************************
115  * Win32 specific implementations of generic functions *
116  *****************************************************/
117
118 GdkColormap*
119 gdk_drawable_get_colormap (GdkDrawable *drawable)
120 {
121   GdkDrawablePrivate *drawable_private;
122   
123   g_return_val_if_fail (drawable != NULL, NULL);
124   drawable_private = (GdkDrawablePrivate*) drawable;
125
126   if (!GDK_DRAWABLE_DESTROYED (drawable))
127     {
128       if (drawable_private->colormap == NULL)
129         return gdk_colormap_get_system (); /* XXX ??? */
130       else
131         return drawable_private->colormap;
132     }
133   
134   return NULL;
135 }
136
137 void
138 gdk_drawable_set_colormap (GdkDrawable *drawable,
139                            GdkColormap *colormap)
140 {
141   GdkDrawablePrivate *drawable_private;
142   GdkColormapPrivateWin32 *colormap_private;
143   
144   g_return_if_fail (drawable != NULL);
145   g_return_if_fail (colormap != NULL);
146   
147   drawable_private = (GdkDrawablePrivate *) drawable;
148   colormap_private = (GdkColormapPrivateWin32 *) colormap;
149   
150   if (!GDK_DRAWABLE_DESTROYED (drawable))
151     {
152       if (GDK_IS_WINDOW (drawable))
153         {
154           g_return_if_fail (colormap_private->base.visual !=
155                             ((GdkColormapPrivate *) (drawable_private->colormap))->visual);
156           /* XXX ??? */
157           GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n",
158                                    GDK_DRAWABLE_XID (drawable),
159                                    colormap_private->xcolormap));
160         }
161       if (drawable_private->colormap)
162         gdk_colormap_unref (drawable_private->colormap);
163       drawable_private->colormap = colormap;
164       gdk_colormap_ref (drawable_private->colormap);
165       
166       if (GDK_IS_WINDOW (drawable)
167           && drawable_private->window_type != GDK_WINDOW_TOPLEVEL)
168         gdk_window_add_colormap_windows (drawable);
169     }
170 }
171
172 /* Drawing
173  */
174 static void 
175 gdk_win32_drawable_destroy (GdkDrawable *drawable)
176 {
177   
178 }
179
180 static void
181 gdk_win32_draw_rectangle (GdkDrawable *drawable,
182                           GdkGC       *gc,
183                           gint         filled,
184                           gint         x,
185                           gint         y,
186                           gint         width,
187                           gint         height)
188 {
189   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
190   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
191   HDC hdc;
192   HGDIOBJ oldpen, oldbrush;
193   HBRUSH hbr = NULL;
194   POINT pts[4];
195   gboolean ok = TRUE;
196
197   GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
198                            GDK_DRAWABLE_XID (drawable),
199                            gc_private,
200                            (filled ? "fill " : ""),
201                            width, height, x, y));
202     
203   hdc = gdk_gc_predraw (drawable, gc_private,
204                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
205
206 #if 0
207   {
208     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
209     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
210     LOGBRUSH lbr;
211     LOGPEN lpen;
212     GetObject (hbr, sizeof (lbr), &lbr);
213     GetObject (hpen, sizeof (lpen), &lpen);
214     
215     g_print ("current brush: style = %s, color = 0x%.08x\n",
216              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
217              lbr.lbColor);
218     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
219              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
220              lpen.lopnWidth,
221              lpen.lopnColor);
222   }
223 #endif
224
225   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
226     {
227       if (!BeginPath (hdc))
228         WIN32_API_FAILED ("BeginPath"), ok = FALSE;
229
230       /* Win9x doesn't support Rectangle calls in a path,
231        * thus use Polyline.
232        */
233           
234       pts[0].x = x;
235       pts[0].y = y;
236       pts[1].x = x + width + 1;
237       pts[1].y = y;
238       pts[2].x = x + width + 1;
239       pts[2].y = y + height + 1;
240       pts[3].x = x;
241       pts[3].y = y + height + 1;
242       
243       if (ok)
244         MoveToEx (hdc, x, y, NULL);
245       
246       if (ok && !Polyline (hdc, pts, 4))
247         WIN32_API_FAILED ("Polyline"), ok = FALSE;
248           
249       if (ok && !CloseFigure (hdc))
250         WIN32_API_FAILED ("CloseFigure"), ok = FALSE;
251
252       if (ok && !EndPath (hdc))
253         WIN32_API_FAILED ("EndPath"), ok = FALSE;
254           
255       if (ok && !filled)
256         if (!WidenPath (hdc))
257           WIN32_API_FAILED ("WidenPath"), ok = FALSE;
258           
259       if (ok && !FillPath (hdc))
260         WIN32_API_FAILED ("FillPath"), ok = FALSE;
261
262       if (hbr != NULL)
263         if (!DeleteObject (hbr))
264           WIN32_API_FAILED ("DeleteObject");
265     }
266   else
267     {
268       if (filled)
269         oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
270       else
271         oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
272   
273       if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
274         WIN32_API_FAILED ("Rectangle");
275   
276       if (filled)
277         SelectObject (hdc, oldpen);
278       else
279         SelectObject (hdc, oldbrush);
280     }
281
282   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
283 }
284
285 static void
286 gdk_win32_draw_arc (GdkDrawable *drawable,
287                     GdkGC       *gc,
288                     gint         filled,
289                     gint         x,
290                     gint         y,
291                     gint         width,
292                     gint         height,
293                     gint         angle1,
294                     gint         angle2)
295 {
296   GdkGCPrivate *gc_private;
297   HDC hdc;
298   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
299
300   gc_private = (GdkGCPrivate*) gc;
301
302   GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
303                            GDK_DRAWABLE_XID (drawable),
304                            x, y, width, height, angle1, angle2));
305
306   if (width != 0 && height != 0 && angle2 != 0)
307     {
308       hdc = gdk_gc_predraw (drawable, gc_private,
309                             GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
310
311       if (angle2 >= 360*64)
312         {
313           nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
314         }
315       else if (angle2 > 0)
316         {
317           /* The 100. is just an arbitrary value */
318           nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
319           nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
320           nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
321           nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
322         }
323       else
324         {
325           nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
326           nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
327           nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
328           nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
329         }
330
331       /* GDK_OPAQUE_STIPPLED arcs not implemented. */
332
333       if (filled)
334         {
335           GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
336                                    x, y, x+width, y+height,
337                                    nXStartArc, nYStartArc,
338                                    nXEndArc, nYEndArc));
339           Pie (hdc, x, y, x+width, y+height,
340                nXStartArc, nYStartArc, nXEndArc, nYEndArc);
341         }
342       else
343         {
344           GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
345                                    x, y, x+width, y+height,
346                                    nXStartArc, nYStartArc,
347                                    nXEndArc, nYEndArc));
348           Arc (hdc, x, y, x+width, y+height,
349                nXStartArc, nYStartArc, nXEndArc, nYEndArc);
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_API_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_API_FAILED ("Polyline"), ok = FALSE;
400           
401       if (ok && !CloseFigure (hdc))
402         WIN32_API_FAILED ("CloseFigure"), ok = FALSE;
403
404       if (ok && !EndPath (hdc))
405         WIN32_API_FAILED ("EndPath"), ok = FALSE;
406           
407       if (ok && !filled)
408         if (!WidenPath (hdc))
409           WIN32_API_FAILED ("WidenPath"), ok = FALSE;
410           
411       if (ok && !FillPath (hdc))
412         WIN32_API_FAILED ("FillPath"), ok = FALSE;
413
414       if (hbr != NULL)
415         if (!DeleteObject (hbr))
416           WIN32_API_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_API_FAILED ("Polygon");
432         }
433       else
434         {
435           if (!Polyline (hdc, pts, npoints))
436             WIN32_API_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_API_FAILED ("SelectObject");
465       return;
466     }
467   
468   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
469     WIN32_API_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 ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
514     g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed");
515   else
516     gdk_wchar_text_handle (font, wcstr, wlen,
517                            gdk_draw_text_handler, &arg);
518
519   g_free (wcstr);
520
521   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
522 }
523
524 static void
525 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
526                         GdkFont          *font,
527                         GdkGC            *gc,
528                         gint              x,
529                         gint              y,
530                         const GdkWChar *text,
531                         gint              text_length)
532 {
533   GdkGCPrivate *gc_private;
534   gint i, wlen;
535   wchar_t *wcstr;
536   gdk_draw_text_arg arg;
537
538
539   if (GDK_DRAWABLE_DESTROYED (drawable))
540     return;
541
542   if (text_length == 0)
543     return;
544
545   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
546
547   gc_private = (GdkGCPrivate*) gc;
548
549   arg.x = x;
550   arg.y = y;
551   arg.hdc = gdk_gc_predraw (drawable, gc_private,
552                             GDK_GC_FOREGROUND|GDK_GC_FONT);
553
554   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
555                            GDK_DRAWABLE_XID (drawable),
556                            x, y, text_length));
557       
558   if (sizeof (wchar_t) != sizeof (GdkWChar))
559     {
560       wcstr = g_new (wchar_t, text_length);
561       for (i = 0; i < text_length; i++)
562         wcstr[i] = text[i];
563     }
564   else
565     wcstr = (wchar_t *) text;
566
567   gdk_wchar_text_handle (font, wcstr, text_length,
568                          gdk_draw_text_handler, &arg);
569
570   if (sizeof (wchar_t) != sizeof (GdkWChar))
571     g_free (wcstr);
572
573   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
574 }
575
576 static void
577 gdk_win32_draw_drawable (GdkDrawable *drawable,
578                          GdkGC       *gc,
579                          GdkPixmap   *src,
580                          gint         xsrc,
581                          gint         ysrc,
582                          gint         xdest,
583                          gint         ydest,
584                          gint         width,
585                          gint         height)
586 {
587   GdkDrawablePrivate *src_private;
588   GdkGCPrivate *gc_private;
589   HDC hdc;
590   HDC srcdc;
591   HGDIOBJ hgdiobj;
592   HRGN src_rgn, draw_rgn, outside_rgn;
593   RECT r;
594
595   src_private = (GdkDrawablePrivate*) src;
596   gc_private = (GdkGCPrivate*) gc;
597
598   GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
599                            "src: %#x %dx%d@+%d+%d"
600                            " dest: %#x @+%d+%d\n",
601                            GDK_DRAWABLE_XID (drawable),
602                            GDK_DRAWABLE_XID (src),
603                            width, height, xsrc, ysrc,
604                            GDK_DRAWABLE_XID (drawable), xdest, ydest));
605
606   hdc = gdk_gc_predraw (drawable, gc_private, 0);
607
608   src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
609   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
610   SetRectEmpty (&r);
611   outside_rgn = CreateRectRgnIndirect (&r);
612   
613   if (GDK_DRAWABLE_TYPE (drawable) != GDK_DRAWABLE_PIXMAP)
614     {
615       /* If we are drawing on a window, calculate the region that is
616        * outside the source pixmap, and invalidate that, causing it to
617        * be cleared. XXX
618        */
619       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
620         {
621           OffsetRgn (outside_rgn, xdest, ydest);
622           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
623                            g_print ("...calling InvalidateRgn, "
624                                     "bbox: %dx%d@+%d+%d\n",
625                                     r.right - r.left - 1, r.bottom - r.top - 1,
626                                     r.left, r.top)));
627           InvalidateRgn (GDK_DRAWABLE_XID (drawable), outside_rgn, TRUE);
628         }
629     }
630
631 #if 1 /* Don't know if this is necessary  */
632   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
633     g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION");
634
635   GetRgnBox (draw_rgn, &r);
636   if (r.left != xsrc
637       || r.top != ysrc
638       || r.right != xsrc + width + 1
639       || r.bottom != ysrc + height + 1)
640     {
641       xdest += r.left - xsrc;
642       xsrc = r.left;
643       ydest += r.top - ysrc;
644       ysrc = r.top;
645       width = r.right - xsrc - 1;
646       height = r.bottom - ysrc - 1;
647       
648       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
649                                "dest: @+%d+%d\n",
650                                width, height, xsrc, ysrc,
651                                xdest, ydest));
652     }
653 #endif
654
655   DeleteObject (src_rgn);
656   DeleteObject (draw_rgn);
657   DeleteObject (outside_rgn);
658
659   /* Strangely enough, this function is called also to bitblt
660    * from a window.
661    */
662   if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
663     {
664       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
665         WIN32_API_FAILED ("CreateCompatibleDC");
666       
667       if ((hgdiobj = SelectObject (srcdc, GDK_DRAWABLE_XID (src))) == NULL)
668         WIN32_API_FAILED ("SelectObject #1");
669       
670       if (!BitBlt (hdc, xdest, ydest, width, height,
671                    srcdc, xsrc, ysrc, SRCCOPY))
672         WIN32_API_FAILED ("BitBlt");
673       
674       if ((SelectObject (srcdc, hgdiobj) == NULL))
675         WIN32_API_FAILED ("SelectObject #2");
676       
677       if (!DeleteDC (srcdc))
678         WIN32_API_FAILED ("DeleteDC");
679     }
680   else
681     {
682       if (GDK_DRAWABLE_XID(drawable) == GDK_DRAWABLE_XID (src))
683         {
684           /* Blitting inside a window, use ScrollDC */
685           RECT scrollRect, clipRect, emptyRect;
686           HRGN updateRgn;
687
688           scrollRect.left = MIN (xsrc, xdest);
689           scrollRect.top = MIN (ysrc, ydest);
690           scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
691           scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
692
693           clipRect.left = xdest;
694           clipRect.top = ydest;
695           clipRect.right = xdest + width + 1;
696           clipRect.bottom = ydest + height + 1;
697
698           SetRectEmpty (&emptyRect);
699           updateRgn = CreateRectRgnIndirect (&emptyRect);
700           if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
701                          &scrollRect, &clipRect,
702                          updateRgn, NULL))
703             WIN32_API_FAILED ("ScrollDC");
704           if (!InvalidateRgn (GDK_DRAWABLE_XID (drawable), updateRgn, FALSE))
705             WIN32_API_FAILED ("InvalidateRgn");
706           if (!UpdateWindow (GDK_DRAWABLE_XID (drawable)))
707             WIN32_API_FAILED ("UpdateWindow");
708         }
709       else
710         {
711           if ((srcdc = GetDC (GDK_DRAWABLE_XID (src))) == NULL)
712             WIN32_API_FAILED ("GetDC");
713           
714           if (!BitBlt (hdc, xdest, ydest, width, height,
715                        srcdc, xsrc, ysrc, SRCCOPY))
716             WIN32_API_FAILED ("BitBlt");
717           ReleaseDC (GDK_DRAWABLE_XID (src), srcdc);
718         }
719     }
720   gdk_gc_postdraw (drawable, gc_private, 0);
721 }
722
723 static void
724 gdk_win32_draw_points (GdkDrawable *drawable,
725                        GdkGC       *gc,
726                        GdkPoint    *points,
727                        gint         npoints)
728 {
729   HDC hdc;
730   COLORREF fg;
731   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
732   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
733   GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
734   GdkColormapPrivateWin32 *colormap_private =
735     (GdkColormapPrivateWin32 *) drawable_private->colormap;
736   int i;
737
738   hdc = gdk_gc_predraw (drawable, gc_private, 0);
739   
740   fg = gdk_colormap_color (colormap_private, gc_data->foreground);
741
742   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
743                            GDK_DRAWABLE_XID (drawable), npoints, fg));
744
745   for (i = 0; i < npoints; i++)
746     SetPixel (hdc, points[i].x, points[i].y, fg);
747
748   gdk_gc_postdraw (drawable, gc_private, 0);
749 }
750
751 static void
752 gdk_win32_draw_segments (GdkDrawable *drawable,
753                          GdkGC       *gc,
754                          GdkSegment  *segs,
755                          gint         nsegs)
756 {
757   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
758   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
759   HDC hdc;
760   HBRUSH hbr = NULL;
761   gboolean ok = TRUE;
762   int i;
763
764   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x destdc: (%d) %#x "
765                            "nsegs: %d\n",
766                            GDK_DRAWABLE_XID (drawable),
767                            gc_private, hdc,
768                            nsegs));
769
770   hdc = gdk_gc_predraw (drawable, gc_private,
771                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
772
773   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
774     {
775       if (!BeginPath (hdc))
776         WIN32_API_FAILED ("BeginPath"), ok = FALSE;
777       
778       for (i = 0; i < nsegs; i++)
779         {
780           if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
781             WIN32_API_FAILED ("MoveToEx"), ok = FALSE;
782           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
783             WIN32_API_FAILED ("LineTo #1"), ok = FALSE;
784           
785           /* Draw end pixel */
786           if (ok && gc_data->pen_width == 1)
787             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
788               WIN32_API_FAILED ("LineTo #2"), ok = FALSE;
789         }
790
791       if (ok && !EndPath (hdc))
792         WIN32_API_FAILED ("EndPath"), ok = FALSE;
793           
794       if (ok && !WidenPath (hdc))
795         WIN32_API_FAILED ("WidenPath"), ok = FALSE;
796           
797       if (ok && !FillPath (hdc))
798         WIN32_API_FAILED ("FillPath"), ok = FALSE;
799
800       if (hbr != NULL)
801         if (!DeleteObject (hbr))
802           WIN32_API_FAILED ("DeleteObject");
803     }
804   else
805     {
806       for (i = 0; i < nsegs; i++)
807         {
808           if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
809             WIN32_API_FAILED ("MoveToEx");
810           if (!LineTo (hdc, segs[i].x2, segs[i].y2))
811             WIN32_API_FAILED ("LineTo #1");
812           
813           /* Draw end pixel */
814           if (gc_data->pen_width == 1)
815             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
816               WIN32_API_FAILED ("LineTo #2");
817         }
818     }
819   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
820 }
821
822 static void
823 gdk_win32_draw_lines (GdkDrawable *drawable,
824                       GdkGC       *gc,
825                       GdkPoint    *points,
826                       gint         npoints)
827 {
828   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
829   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
830   HDC hdc;
831   POINT *pts;
832   int i;
833
834   if (npoints < 2)
835     return;
836
837   hdc = gdk_gc_predraw (drawable, gc_private,
838                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
839 #if 1
840   pts = g_new (POINT, npoints);
841
842   for (i = 0; i < npoints; i++)
843     {
844       pts[i].x = points[i].x;
845       pts[i].y = points[i].y;
846     }
847   
848   if (!Polyline (hdc, pts, npoints))
849     WIN32_API_FAILED ("Polyline");
850   
851   g_free (pts);
852   
853   /* Draw end pixel */
854   if (gc_data->pen_width == 1)
855     {
856       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
857       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
858         WIN32_API_FAILED ("LineTo");
859     }
860 #else
861   MoveToEx (hdc, points[0].x, points[0].y, NULL);
862   for (i = 1; i < npoints; i++)
863     if (!LineTo (hdc, points[i].x, points[i].y))
864       WIN32_API_FAILED ("LineTo #1");
865   
866   /* Draw end pixel */
867   /* LineTo doesn't draw the last point, so if we have a pen width of 1,
868    * we draw the end pixel separately... With wider pens we don't care.
869    * //HB: But the NT developers don't read their API documentation ...
870    */
871   if (gc_data->pen_width == 1 && windows_version > 0x80000000)
872     if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
873       WIN32_API_FAILED ("LineTo #2");
874 #endif  
875   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
876 }