]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Internal GDK error reporting changes: (gdk_win32_gdi_failed) New function
[~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_GDI_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_GDI_FAILED ("Polyline"), ok = FALSE;
248           
249       if (ok && !CloseFigure (hdc))
250         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
251
252       if (ok && !EndPath (hdc))
253         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
254           
255       if (ok && !filled)
256         if (!WidenPath (hdc))
257           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
258           
259       if (ok && !FillPath (hdc))
260         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
261
262       if (hbr != NULL)
263         if (!DeleteObject (hbr))
264           WIN32_GDI_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_GDI_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           if (!Pie (hdc, x, y, x+width, y+height,
340                     nXStartArc, nYStartArc, nXEndArc, nYEndArc))
341             WIN32_GDI_FAILED ("Pie");
342         }
343       else
344         {
345           GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
346                                    x, y, x+width, y+height,
347                                    nXStartArc, nYStartArc,
348                                    nXEndArc, nYEndArc));
349           if (!Arc (hdc, x, y, x+width, y+height,
350                     nXStartArc, nYStartArc, nXEndArc, nYEndArc))
351             WIN32_GDI_FAILED ("Arc");
352         }
353       gdk_gc_postdraw (drawable, gc_private,
354                        GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
355     }
356 }
357
358 static void
359 gdk_win32_draw_polygon (GdkDrawable *drawable,
360                         GdkGC       *gc,
361                         gint         filled,
362                         GdkPoint    *points,
363                         gint         npoints)
364 {
365   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
366   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
367   HDC hdc;
368   HBRUSH hbr = NULL;
369   POINT *pts;
370   gboolean ok = TRUE;
371   int i;
372
373   GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%d) %d\n",
374                            GDK_DRAWABLE_XID (drawable), gc_private,
375                            npoints));
376
377   if (npoints < 2)
378     return;
379
380   hdc = gdk_gc_predraw (drawable, gc_private,
381                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
382   pts = g_new (POINT, npoints+1);
383
384   for (i = 0; i < npoints; i++)
385     {
386       pts[i].x = points[i].x;
387       pts[i].y = points[i].y;
388     }
389   
390   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
391     {
392       if (!BeginPath (hdc))
393         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
394
395       MoveToEx (hdc, points[0].x, points[0].y, NULL);
396
397       if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
398         npoints--;
399
400       if (ok && !Polyline (hdc, pts, 4))
401         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
402           
403       if (ok && !CloseFigure (hdc))
404         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
405
406       if (ok && !EndPath (hdc))
407         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
408           
409       if (ok && !filled)
410         if (!WidenPath (hdc))
411           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
412           
413       if (ok && !FillPath (hdc))
414         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
415
416       if (hbr != NULL)
417         if (!DeleteObject (hbr))
418           WIN32_GDI_FAILED ("DeleteObject");
419     }
420   else
421     {
422       if (points[0].x != points[npoints-1].x
423           || points[0].y != points[npoints-1].y) 
424         {
425           pts[npoints].x = points[0].x;
426           pts[npoints].y = points[0].y;
427           npoints++;
428         }
429       
430       if (filled)
431         {
432           if (!Polygon (hdc, pts, npoints))
433             WIN32_GDI_FAILED ("Polygon");
434         }
435       else
436         {
437           if (!Polyline (hdc, pts, npoints))
438             WIN32_GDI_FAILED ("Polyline");
439         }
440     }
441   g_free (pts);
442   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
443 }
444
445 typedef struct
446 {
447   gint x, y;
448   HDC hdc;
449 } gdk_draw_text_arg;
450
451 static void
452 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
453                        const wchar_t      *wcstr,
454                        int                 wclen,
455                        void               *arg)
456 {
457   HGDIOBJ oldfont;
458   SIZE size;
459   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
460
461   if (!singlefont)
462     return;
463
464   if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL)
465     {
466       WIN32_GDI_FAILED ("SelectObject");
467       return;
468     }
469   
470   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
471     WIN32_GDI_FAILED ("TextOutW");
472   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
473   argp->x += size.cx;
474
475   SelectObject (argp->hdc, oldfont);
476 }
477
478 static void
479 gdk_win32_draw_text (GdkDrawable *drawable,
480                      GdkFont     *font,
481                      GdkGC       *gc,
482                      gint         x,
483                      gint         y,
484                      const gchar *text,
485                      gint         text_length)
486 {
487   GdkGCPrivate *gc_private;
488   wchar_t *wcstr;
489   gint wlen;
490   gdk_draw_text_arg arg;
491
492
493   if (GDK_DRAWABLE_DESTROYED (drawable))
494     return;
495
496   if (text_length == 0)
497     return;
498
499   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
500
501   gc_private = (GdkGCPrivate*) gc;
502
503   arg.x = x;
504   arg.y = y;
505   arg.hdc = gdk_gc_predraw (drawable, gc_private,
506                             GDK_GC_FOREGROUND|GDK_GC_FONT);
507
508   GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
509                            GDK_DRAWABLE_XID (drawable),
510                            x, y,
511                            (text_length > 10 ? 10 : text_length),
512                            text, text_length));
513   
514   wcstr = g_new (wchar_t, text_length);
515   if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
516     g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed");
517   else
518     gdk_wchar_text_handle (font, wcstr, wlen,
519                            gdk_draw_text_handler, &arg);
520
521   g_free (wcstr);
522
523   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
524 }
525
526 static void
527 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
528                         GdkFont          *font,
529                         GdkGC            *gc,
530                         gint              x,
531                         gint              y,
532                         const GdkWChar *text,
533                         gint              text_length)
534 {
535   GdkGCPrivate *gc_private;
536   gint i, wlen;
537   wchar_t *wcstr;
538   gdk_draw_text_arg arg;
539
540
541   if (GDK_DRAWABLE_DESTROYED (drawable))
542     return;
543
544   if (text_length == 0)
545     return;
546
547   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
548
549   gc_private = (GdkGCPrivate*) gc;
550
551   arg.x = x;
552   arg.y = y;
553   arg.hdc = gdk_gc_predraw (drawable, gc_private,
554                             GDK_GC_FOREGROUND|GDK_GC_FONT);
555
556   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
557                            GDK_DRAWABLE_XID (drawable),
558                            x, y, text_length));
559       
560   if (sizeof (wchar_t) != sizeof (GdkWChar))
561     {
562       wcstr = g_new (wchar_t, text_length);
563       for (i = 0; i < text_length; i++)
564         wcstr[i] = text[i];
565     }
566   else
567     wcstr = (wchar_t *) text;
568
569   gdk_wchar_text_handle (font, wcstr, text_length,
570                          gdk_draw_text_handler, &arg);
571
572   if (sizeof (wchar_t) != sizeof (GdkWChar))
573     g_free (wcstr);
574
575   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
576 }
577
578 static void
579 gdk_win32_draw_drawable (GdkDrawable *drawable,
580                          GdkGC       *gc,
581                          GdkPixmap   *src,
582                          gint         xsrc,
583                          gint         ysrc,
584                          gint         xdest,
585                          gint         ydest,
586                          gint         width,
587                          gint         height)
588 {
589   GdkDrawablePrivate *src_private;
590   GdkGCPrivate *gc_private;
591   HDC hdc;
592   HDC srcdc;
593   HGDIOBJ hgdiobj;
594   HRGN src_rgn, draw_rgn, outside_rgn;
595   RECT r;
596
597   src_private = (GdkDrawablePrivate*) src;
598   gc_private = (GdkGCPrivate*) gc;
599
600   GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
601                            "src: %#x %dx%d@+%d+%d"
602                            " dest: %#x @+%d+%d\n",
603                            GDK_DRAWABLE_XID (drawable),
604                            GDK_DRAWABLE_XID (src),
605                            width, height, xsrc, ysrc,
606                            GDK_DRAWABLE_XID (drawable), xdest, ydest));
607
608   hdc = gdk_gc_predraw (drawable, gc_private, 0);
609
610   src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
611   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
612   SetRectEmpty (&r);
613   outside_rgn = CreateRectRgnIndirect (&r);
614   
615   if (GDK_DRAWABLE_TYPE (drawable) != GDK_DRAWABLE_PIXMAP)
616     {
617       /* If we are drawing on a window, calculate the region that is
618        * outside the source pixmap, and invalidate that, causing it to
619        * be cleared. XXX
620        */
621       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
622         {
623           OffsetRgn (outside_rgn, xdest, ydest);
624           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
625                            g_print ("...calling InvalidateRgn, "
626                                     "bbox: %dx%d@+%d+%d\n",
627                                     r.right - r.left - 1, r.bottom - r.top - 1,
628                                     r.left, r.top)));
629           InvalidateRgn (GDK_DRAWABLE_XID (drawable), outside_rgn, TRUE);
630         }
631     }
632
633 #if 1 /* Don't know if this is necessary  */
634   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
635     g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION");
636
637   GetRgnBox (draw_rgn, &r);
638   if (r.left != xsrc
639       || r.top != ysrc
640       || r.right != xsrc + width + 1
641       || r.bottom != ysrc + height + 1)
642     {
643       xdest += r.left - xsrc;
644       xsrc = r.left;
645       ydest += r.top - ysrc;
646       ysrc = r.top;
647       width = r.right - xsrc - 1;
648       height = r.bottom - ysrc - 1;
649       
650       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
651                                "dest: @+%d+%d\n",
652                                width, height, xsrc, ysrc,
653                                xdest, ydest));
654     }
655 #endif
656
657   DeleteObject (src_rgn);
658   DeleteObject (draw_rgn);
659   DeleteObject (outside_rgn);
660
661   /* Strangely enough, this function is called also to bitblt
662    * from a window.
663    */
664   if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
665     {
666       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
667         WIN32_GDI_FAILED ("CreateCompatibleDC");
668       
669       if ((hgdiobj = SelectObject (srcdc, GDK_DRAWABLE_XID (src))) == NULL)
670         WIN32_GDI_FAILED ("SelectObject");
671       
672       if (!BitBlt (hdc, xdest, ydest, width, height,
673                    srcdc, xsrc, ysrc, SRCCOPY))
674         WIN32_GDI_FAILED ("BitBlt");
675       
676       if ((SelectObject (srcdc, hgdiobj) == NULL))
677         WIN32_GDI_FAILED ("SelectObject");
678       
679       if (!DeleteDC (srcdc))
680         WIN32_GDI_FAILED ("DeleteDC");
681     }
682   else
683     {
684       if (GDK_DRAWABLE_XID(drawable) == GDK_DRAWABLE_XID (src))
685         {
686           /* Blitting inside a window, use ScrollDC */
687           RECT scrollRect, clipRect, emptyRect;
688           HRGN updateRgn;
689
690           scrollRect.left = MIN (xsrc, xdest);
691           scrollRect.top = MIN (ysrc, ydest);
692           scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
693           scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
694
695           clipRect.left = xdest;
696           clipRect.top = ydest;
697           clipRect.right = xdest + width + 1;
698           clipRect.bottom = ydest + height + 1;
699
700           SetRectEmpty (&emptyRect);
701           updateRgn = CreateRectRgnIndirect (&emptyRect);
702           if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
703                          &scrollRect, &clipRect,
704                          updateRgn, NULL))
705             WIN32_GDI_FAILED ("ScrollDC");
706           if (!InvalidateRgn (GDK_DRAWABLE_XID (drawable), updateRgn, FALSE))
707             WIN32_GDI_FAILED ("InvalidateRgn");
708           if (!UpdateWindow (GDK_DRAWABLE_XID (drawable)))
709             WIN32_GDI_FAILED ("UpdateWindow");
710         }
711       else
712         {
713           if ((srcdc = GetDC (GDK_DRAWABLE_XID (src))) == NULL)
714             WIN32_GDI_FAILED ("GetDC");
715           
716           if (!BitBlt (hdc, xdest, ydest, width, height,
717                        srcdc, xsrc, ysrc, SRCCOPY))
718             WIN32_GDI_FAILED ("BitBlt");
719           ReleaseDC (GDK_DRAWABLE_XID (src), srcdc);
720         }
721     }
722   gdk_gc_postdraw (drawable, gc_private, 0);
723 }
724
725 static void
726 gdk_win32_draw_points (GdkDrawable *drawable,
727                        GdkGC       *gc,
728                        GdkPoint    *points,
729                        gint         npoints)
730 {
731   HDC hdc;
732   COLORREF fg;
733   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
734   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
735   GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
736   GdkColormapPrivateWin32 *colormap_private =
737     (GdkColormapPrivateWin32 *) drawable_private->colormap;
738   int i;
739
740   hdc = gdk_gc_predraw (drawable, gc_private, 0);
741   
742   fg = gdk_colormap_color (colormap_private, gc_data->foreground);
743
744   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
745                            GDK_DRAWABLE_XID (drawable), npoints, fg));
746
747   for (i = 0; i < npoints; i++)
748     SetPixel (hdc, points[i].x, points[i].y, fg);
749
750   gdk_gc_postdraw (drawable, gc_private, 0);
751 }
752
753 static void
754 gdk_win32_draw_segments (GdkDrawable *drawable,
755                          GdkGC       *gc,
756                          GdkSegment  *segs,
757                          gint         nsegs)
758 {
759   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
760   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
761   HDC hdc;
762   HBRUSH hbr = NULL;
763   gboolean ok = TRUE;
764   int i;
765
766   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
767                            GDK_DRAWABLE_XID (drawable), nsegs));
768
769   hdc = gdk_gc_predraw (drawable, gc_private,
770                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
771
772   if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
773     {
774       if (!BeginPath (hdc))
775         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
776       
777       for (i = 0; i < nsegs; i++)
778         {
779           if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
780             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
781           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
782             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
783           
784           /* Draw end pixel */
785           if (ok && gc_data->pen_width == 1)
786             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
787               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
788         }
789
790       if (ok && !EndPath (hdc))
791         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
792           
793       if (ok && !WidenPath (hdc))
794         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
795           
796       if (ok && !FillPath (hdc))
797         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
798
799       if (hbr != NULL)
800         if (!DeleteObject (hbr))
801           WIN32_GDI_FAILED ("DeleteObject");
802     }
803   else
804     {
805       for (i = 0; i < nsegs; i++)
806         {
807           if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
808             WIN32_GDI_FAILED ("MoveToEx");
809           if (!LineTo (hdc, segs[i].x2, segs[i].y2))
810             WIN32_GDI_FAILED ("LineTo");
811           
812           /* Draw end pixel */
813           if (gc_data->pen_width == 1)
814             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
815               WIN32_GDI_FAILED ("LineTo");
816         }
817     }
818   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
819 }
820
821 static void
822 gdk_win32_draw_lines (GdkDrawable *drawable,
823                       GdkGC       *gc,
824                       GdkPoint    *points,
825                       gint         npoints)
826 {
827   GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
828   GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
829   HDC hdc;
830   POINT *pts;
831   int i;
832
833   if (npoints < 2)
834     return;
835
836   hdc = gdk_gc_predraw (drawable, gc_private,
837                         GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
838 #if 1
839   pts = g_new (POINT, npoints);
840
841   for (i = 0; i < npoints; i++)
842     {
843       pts[i].x = points[i].x;
844       pts[i].y = points[i].y;
845     }
846   
847   if (!Polyline (hdc, pts, npoints))
848     WIN32_GDI_FAILED ("Polyline");
849   
850   g_free (pts);
851   
852   /* Draw end pixel */
853   if (gc_data->pen_width == 1)
854     {
855       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
856       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
857         WIN32_GDI_FAILED ("LineTo");
858     }
859 #else
860   MoveToEx (hdc, points[0].x, points[0].y, NULL);
861   for (i = 1; i < npoints; i++)
862     if (!LineTo (hdc, points[i].x, points[i].y))
863       WIN32_GDI_FAILED ("LineTo");
864   
865   /* Draw end pixel */
866   /* LineTo doesn't draw the last point, so if we have a pen width of 1,
867    * we draw the end pixel separately... With wider pens we don't care.
868    * //HB: But the NT developers don't read their API documentation ...
869    */
870   if (gc_data->pen_width == 1 && windows_version > 0x80000000)
871     if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
872       WIN32_GDI_FAILED ("LineTo");
873 #endif  
874   gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
875 }