]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
gdk/win32/gdkdraw.c gdk/win32/gdkfont.c Various minor cleanups and
[~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
31 #include "gdkdrawable.h"
32 #include "gdkprivate.h"
33 #include "gdkwindow.h"
34 #include "gdkx.h"
35
36 #ifndef G_PI
37 #define G_PI 3.14159265358979323846
38 #endif
39
40 /* Manipulation of drawables
41  */
42 void          
43 gdk_drawable_set_data (GdkDrawable   *drawable,
44                        const gchar   *key,
45                        gpointer       data,
46                        GDestroyNotify destroy_func)
47 {
48   g_dataset_set_data_full (drawable, key, data, destroy_func);
49 }
50
51 void          
52 gdk_drawable_get_data (GdkDrawable   *drawable,
53                        const gchar   *key)
54 {
55   g_dataset_get_data (drawable, key);
56 }
57
58 GdkDrawableType
59 gdk_drawable_get_type (GdkDrawable *drawable)
60 {
61   g_return_val_if_fail (drawable != NULL, (GdkDrawableType) -1);
62   
63   return GDK_DRAWABLE_TYPE (drawable);
64 }
65
66 void
67 gdk_drawable_get_size (GdkDrawable *drawable,
68                        gint        *width,
69                        gint        *height)
70 {
71   GdkDrawablePrivate *drawable_private;
72   
73   g_return_if_fail (drawable != NULL);
74   
75   drawable_private = (GdkDrawablePrivate*) drawable;
76   
77   if (width)
78     *width = drawable_private->width;
79   if (height)
80     *height = drawable_private->height;
81 }
82
83 void
84 gdk_drawable_set_colormap (GdkDrawable *drawable,
85                            GdkColormap *colormap)
86 {
87   GdkDrawablePrivate *drawable_private;
88   GdkColormapPrivate *colormap_private;
89   
90   g_return_if_fail (drawable != NULL);
91   g_return_if_fail (colormap != NULL);
92   
93   drawable_private = (GdkDrawablePrivate*) drawable;
94   colormap_private = (GdkColormapPrivate*) colormap;
95   
96   if (!GDK_DRAWABLE_DESTROYED (drawable))
97     {
98       if (GDK_IS_WINDOW (drawable))
99         {
100           g_return_if_fail (colormap_private->visual !=
101                             ((GdkColormapPrivate*)(drawable_private->colormap))->visual);
102           /* XXX ??? */
103           GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n",
104                                    GDK_DRAWABLE_XID (drawable),
105                                    colormap_private->xcolormap));
106         }
107       if (drawable_private->colormap)
108         gdk_colormap_unref (drawable_private->colormap);
109       drawable_private->colormap = colormap;
110       gdk_colormap_ref (drawable_private->colormap);
111       
112       if (GDK_IS_WINDOW (drawable) &&
113           drawable_private->window_type != GDK_WINDOW_TOPLEVEL)
114         gdk_window_add_colormap_windows (drawable);
115     }
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 GdkVisual*
138 gdk_drawable_get_visual (GdkDrawable *drawable)
139 {
140   GdkColormap *colormap;
141
142   g_return_val_if_fail (drawable != NULL, NULL);
143
144   colormap = gdk_drawable_get_colormap (drawable);
145   return colormap ? gdk_colormap_get_visual (colormap) : NULL;
146 }
147
148 void
149 gdk_draw_point (GdkDrawable *drawable,
150                 GdkGC       *gc,
151                 gint         x,
152                 gint         y)
153 {
154   GdkDrawablePrivate *drawable_private;
155   GdkGCPrivate *gc_private;
156   HDC hdc;
157
158   g_return_if_fail (drawable != NULL);
159   g_return_if_fail (gc != NULL);
160
161   if (GDK_DRAWABLE_DESTROYED (drawable))
162     return;
163   drawable_private = (GdkDrawablePrivate*) drawable;
164   gc_private = (GdkGCPrivate*) gc;
165
166   hdc = gdk_gc_predraw (drawable_private, gc_private);
167
168   /* We use LineTo because SetPixel wants the COLORREF directly,
169    * and doesn't use the current pen, which is what we want.
170    */
171   if (!MoveToEx (hdc, x, y, NULL))
172     g_warning ("gdk_draw_point: MoveToEx failed");
173   if (!LineTo (hdc, x + 1, y))
174     g_warning ("gdk_draw_point: LineTo failed");
175   
176   gdk_gc_postdraw (drawable_private, gc_private);
177 }
178
179 void
180 gdk_draw_line (GdkDrawable *drawable,
181                GdkGC       *gc,
182                gint         x1,
183                gint         y1,
184                gint         x2,
185                gint         y2)
186 {
187   GdkDrawablePrivate *drawable_private;
188   GdkGCPrivate *gc_private;
189   HDC hdc;
190
191   g_return_if_fail (drawable != NULL);
192   g_return_if_fail (gc != NULL);
193
194   if (GDK_DRAWABLE_DESTROYED (drawable))
195     return;
196   drawable_private = (GdkDrawablePrivate*) drawable;
197   gc_private = (GdkGCPrivate*) gc;
198
199   hdc = gdk_gc_predraw (drawable_private, gc_private);
200     
201   GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
202                            drawable_private->xwindow, gc_private,
203                            x1, y1, x2, y2));
204   
205   MoveToEx (hdc, x1, y1, NULL);
206   if (!LineTo (hdc, x2, y2))
207     g_warning ("gdk_draw_line: LineTo #1 failed");
208   /* LineTo doesn't draw the last point, so if we have a pen width of 1,
209    * we draw the end pixel separately... With wider pens we don't care.
210    * //HB: But the NT developers don't read their API documentation ...
211    */
212   if (gc_private->pen_width == 1 && windows_version > 0x80000000)
213     if (!LineTo (hdc, x2 + 1, y2))
214       g_warning ("gdk_draw_line: LineTo #2 failed");
215   gdk_gc_postdraw (drawable_private, gc_private);
216 }
217
218 void
219 gdk_draw_rectangle (GdkDrawable *drawable,
220                     GdkGC       *gc,
221                     gint         filled,
222                     gint         x,
223                     gint         y,
224                     gint         width,
225                     gint         height)
226 {
227   GdkDrawablePrivate *drawable_private;
228   GdkGCPrivate *gc_private;
229   HDC hdc;
230   HGDIOBJ oldpen, oldbrush;
231
232   g_return_if_fail (drawable != NULL);
233   g_return_if_fail (gc != NULL);
234
235   if (GDK_DRAWABLE_DESTROYED (drawable))
236     return;
237   drawable_private = (GdkDrawablePrivate*) drawable;
238   gc_private = (GdkGCPrivate*) gc;
239
240   if (width == -1)
241     width = drawable_private->width;
242   if (height == -1)
243     height = drawable_private->height;
244
245   hdc = gdk_gc_predraw (drawable_private, gc_private);
246
247   GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
248                            drawable_private->xwindow,
249                            gc_private,
250                            (filled ? "fill " : ""),
251                            width, height, x, y));
252     
253 #if 0
254   {
255     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
256     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
257     LOGBRUSH lbr;
258     LOGPEN lpen;
259     GetObject (hbr, sizeof (lbr), &lbr);
260     GetObject (hpen, sizeof (lpen), &lpen);
261     
262     g_print ("current brush: style = %s, color = 0x%.08x\n",
263              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
264              lbr.lbColor);
265     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
266              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
267              lpen.lopnWidth,
268              lpen.lopnColor);
269   }
270 #endif
271
272   if (filled)
273     oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
274   else
275     oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
276   
277   if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
278     g_warning ("gdk_draw_rectangle: Rectangle failed");
279   
280   if (filled)
281     SelectObject (hdc, oldpen);
282   else
283     SelectObject (hdc, oldbrush);
284
285   gdk_gc_postdraw (drawable_private, gc_private);
286 }
287
288 void
289 gdk_draw_arc (GdkDrawable *drawable,
290               GdkGC       *gc,
291               gint         filled,
292               gint         x,
293               gint         y,
294               gint         width,
295               gint         height,
296               gint         angle1,
297               gint         angle2)
298 {
299   GdkDrawablePrivate *drawable_private;
300   GdkGCPrivate *gc_private;
301   HDC hdc;
302   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
303
304   g_return_if_fail (drawable != NULL);
305   g_return_if_fail (gc != NULL);
306
307   if (GDK_DRAWABLE_DESTROYED (drawable))
308     return;
309   drawable_private = (GdkDrawablePrivate*) drawable;
310   gc_private = (GdkGCPrivate*) gc;
311
312   if (width == -1)
313     width = drawable_private->width;
314   if (height == -1)
315     height = drawable_private->height;
316
317   GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
318                            drawable_private->xwindow,
319                            x, y, width, height, angle1, angle2));
320
321   if (width != 0 && height != 0 && angle2 != 0)
322     {
323       hdc = gdk_gc_predraw (drawable_private, gc_private);
324
325       if (angle2 >= 360*64)
326         {
327           nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
328         }
329       else if (angle2 > 0)
330         {
331           /* The 100. is just an arbitrary value */
332           nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
333           nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
334           nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
335           nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
336         }
337       else
338         {
339           nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
340           nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
341           nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
342           nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
343         }
344
345       if (filled)
346         {
347           GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
348                                    x, y, x+width, y+height,
349                                    nXStartArc, nYStartArc,
350                                    nXEndArc, nYEndArc));
351           Pie (hdc, x, y, x+width, y+height,
352                nXStartArc, nYStartArc, nXEndArc, nYEndArc);
353         }
354       else
355         {
356           GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
357                                    x, y, x+width, y+height,
358                                    nXStartArc, nYStartArc,
359                                    nXEndArc, nYEndArc));
360           Arc (hdc, x, y, x+width, y+height,
361                nXStartArc, nYStartArc, nXEndArc, nYEndArc);
362         }
363       gdk_gc_postdraw (drawable_private, gc_private);
364     }
365 }
366
367 void
368 gdk_draw_polygon (GdkDrawable *drawable,
369                   GdkGC       *gc,
370                   gint         filled,
371                   GdkPoint    *points,
372                   gint         npoints)
373 {
374   GdkDrawablePrivate *drawable_private;
375   GdkGCPrivate *gc_private;
376   HDC hdc;
377   POINT *pts;
378   int i;
379
380   g_return_if_fail (drawable != NULL);
381   g_return_if_fail (gc != NULL);
382
383   if (GDK_DRAWABLE_DESTROYED (drawable))
384     return;
385   drawable_private = (GdkDrawablePrivate*) drawable;
386   gc_private = (GdkGCPrivate*) gc;
387
388   GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
389                            drawable_private->xwindow, gc_private,
390                            npoints));
391
392   if (npoints < 2)
393     return;
394
395   hdc = gdk_gc_predraw (drawable_private, gc_private);
396   pts = g_malloc ((npoints+1) * sizeof (POINT));
397
398   for (i = 0; i < npoints; i++)
399     {
400       pts[i].x = points[i].x;
401       pts[i].y = points[i].y;
402     }
403   
404   if ((points[0].x != points[npoints-1].x) ||
405       (points[0].y != points[npoints-1].y)) 
406     {
407       pts[npoints].x = points[0].x;
408       pts[npoints].y = points[0].y;
409       npoints++;
410     }
411   if (filled)
412     {
413       if (!Polygon (hdc, pts, npoints))
414         g_warning ("gdk_draw_polygon: Polygon failed");
415     }
416   else
417     {
418       if (!Polyline (hdc, pts, npoints))
419         g_warning ("gdk_draw_polygon: Polyline failed");
420     }
421   g_free (pts);
422   gdk_gc_postdraw (drawable_private, gc_private);
423 }
424
425 typedef struct
426 {
427   gint x, y;
428   HDC hdc;
429 } gdk_draw_text_arg;
430
431 /* gdk_draw_string
432  */
433 void
434 gdk_draw_string (GdkDrawable *drawable,
435                  GdkFont     *font,
436                  GdkGC       *gc,
437                  gint         x,
438                  gint         y,
439                  const gchar *string)
440 {
441   gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
442 }
443
444 static void
445 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
446                        const wchar_t      *wcstr,
447                        int                 wclen,
448                        void               *arg)
449 {
450   HGDIOBJ oldfont;
451   SIZE size;
452   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
453
454   if (!singlefont)
455     return;
456
457   if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL)
458     {
459       g_warning ("gdk_draw_text_handler: SelectObject failed");
460       return;
461     }
462   
463   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
464     g_warning ("gdk_draw_text_handler: TextOutW failed");
465   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
466   argp->x += size.cx;
467
468   SelectObject (argp->hdc, oldfont);
469 }
470
471 /* gdk_draw_text
472  *
473  */
474 void
475 gdk_draw_text (GdkDrawable *drawable,
476                GdkFont     *font,
477                GdkGC       *gc,
478                gint         x,
479                gint         y,
480                const gchar *text,
481                gint         text_length)
482 {
483   GdkDrawablePrivate *drawable_private;
484   GdkGCPrivate *gc_private;
485   wchar_t *wcstr;
486   gint wlen;
487   gdk_draw_text_arg arg;
488
489   g_return_if_fail (drawable != NULL);
490   g_return_if_fail (font != NULL);
491   g_return_if_fail (gc != NULL);
492   g_return_if_fail (text != NULL);
493
494   if (GDK_DRAWABLE_DESTROYED (drawable))
495     return;
496
497   if (text_length == 0)
498     return;
499
500   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
501
502   drawable_private = (GdkDrawablePrivate*) drawable;
503   gc_private = (GdkGCPrivate*) gc;
504
505   arg.x = x;
506   arg.y = y;
507   arg.hdc = gdk_gc_predraw (drawable_private, gc_private);
508
509   GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
510                            drawable_private->xwindow,
511                            x, y,
512                            (text_length > 10 ? 10 : text_length),
513                            text, text_length));
514   
515   wcstr = g_new (wchar_t, text_length);
516   if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
517     g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed");
518   else
519     gdk_wchar_text_handle (font, wcstr, wlen,
520                            gdk_draw_text_handler, &arg);
521
522   g_free (wcstr);
523
524   gdk_gc_postdraw (drawable_private, gc_private);
525 }
526
527 void
528 gdk_draw_text_wc (GdkDrawable    *drawable,
529                   GdkFont        *font,
530                   GdkGC          *gc,
531                   gint            x,
532                   gint            y,
533                   const GdkWChar *text,
534                   gint            text_length)
535 {
536   GdkDrawablePrivate *drawable_private;
537   GdkGCPrivate *gc_private;
538   gint i, wlen;
539   wchar_t *wcstr;
540   gdk_draw_text_arg arg;
541
542   g_return_if_fail (drawable != NULL);
543   g_return_if_fail (font != NULL);
544   g_return_if_fail (gc != NULL);
545   g_return_if_fail (text != NULL);
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   drawable_private = (GdkDrawablePrivate*) drawable;
556   gc_private = (GdkGCPrivate*) gc;
557
558   arg.x = x;
559   arg.y = y;
560   arg.hdc = gdk_gc_predraw (drawable_private, gc_private);
561
562   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
563                            drawable_private->xwindow,
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_private, gc_private);
582 }
583
584 void
585 gdk_draw_pixmap (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 *drawable_private;
596   GdkDrawablePrivate *src_private;
597   GdkGCPrivate *gc_private;
598   HDC hdc;
599   HDC srcdc;
600   HGDIOBJ hgdiobj;
601   HRGN src_rgn, draw_rgn, outside_rgn;
602   RECT r;
603
604   g_return_if_fail (drawable != NULL);
605   g_return_if_fail (src != NULL);
606   g_return_if_fail (gc != NULL);
607
608   if (GDK_DRAWABLE_DESTROYED (drawable) || GDK_DRAWABLE_DESTROYED (src))
609     return;
610   drawable_private = (GdkDrawablePrivate*) drawable;
611   src_private = (GdkDrawablePrivate*) src;
612   gc_private = (GdkGCPrivate*) gc;
613
614   if (width == -1)
615     width = src_private->width; /* Or should we subtract xsrc? */
616   if (height == -1)
617     height = src_private->height; /* Ditto? */
618
619   GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
620                            "src: %#x %dx%d@+%d+%d"
621                            " dest: %#x @+%d+%d\n",
622                            drawable_private->xwindow,
623                            src_private->xwindow,
624                            width, height, xsrc, ysrc,
625                            drawable_private->xwindow, xdest, ydest));
626
627   hdc = gdk_gc_predraw (drawable_private, gc_private);
628
629   src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
630   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
631   SetRectEmpty (&r);
632   outside_rgn = CreateRectRgnIndirect (&r);
633   
634   if (drawable_private->window_type != GDK_DRAWABLE_PIXMAP)
635     {
636       /* If we are drawing on a window, calculate the region that is
637        * outside the source pixmap, and invalidate that, causing it to
638        * be cleared. XXX
639        */
640       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
641         {
642           OffsetRgn (outside_rgn, xdest, ydest);
643           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
644                            g_print ("...calling InvalidateRgn, "
645                                     "bbox: %dx%d@+%d+%d\n",
646                                     r.right - r.left - 1, r.bottom - r.top - 1,
647                                     r.left, r.top)));
648           InvalidateRgn (drawable_private->xwindow, outside_rgn, TRUE);
649         }
650     }
651
652 #if 1 /* Don't know if this is necessary  */
653   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
654     g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION");
655
656   GetRgnBox (draw_rgn, &r);
657   if (r.left != xsrc
658       || r.top != ysrc
659       || r.right != xsrc + width + 1
660       || r.bottom != ysrc + height + 1)
661     {
662       xdest += r.left - xsrc;
663       xsrc = r.left;
664       ydest += r.top - ysrc;
665       ysrc = r.top;
666       width = r.right - xsrc - 1;
667       height = r.bottom - ysrc - 1;
668       
669       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
670                                "dest: @+%d+%d\n",
671                                width, height, xsrc, ysrc,
672                                xdest, ydest));
673     }
674 #endif
675
676   DeleteObject (src_rgn);
677   DeleteObject (draw_rgn);
678   DeleteObject (outside_rgn);
679
680   /* Strangely enough, this function is called also to bitblt
681    * from a window.
682    */
683   if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
684     {
685       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
686         g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
687       
688       if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
689         g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
690       
691       if (!BitBlt (hdc, xdest, ydest, width, height,
692                    srcdc, xsrc, ysrc, SRCCOPY))
693         g_warning ("gdk_draw_pixmap: BitBlt failed");
694       
695       if ((SelectObject (srcdc, hgdiobj) == NULL))
696         g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
697       
698       if (!DeleteDC (srcdc))
699         g_warning ("gdk_draw_pixmap: DeleteDC failed");
700     }
701   else
702     {
703       if (drawable_private->xwindow == src_private->xwindow)
704         {
705           /* Blitting inside a window, use ScrollDC */
706           RECT scrollRect, clipRect, emptyRect;
707           HRGN updateRgn;
708
709           scrollRect.left = MIN (xsrc, xdest);
710           scrollRect.top = MIN (ysrc, ydest);
711           scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
712           scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
713
714           clipRect.left = xdest;
715           clipRect.top = ydest;
716           clipRect.right = xdest + width + 1;
717           clipRect.bottom = ydest + height + 1;
718
719           SetRectEmpty (&emptyRect);
720           updateRgn = CreateRectRgnIndirect (&emptyRect);
721           if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
722                          &scrollRect, &clipRect,
723                          updateRgn, NULL))
724             g_warning ("gdk_draw_pixmap: ScrollDC failed");
725           if (!InvalidateRgn (drawable_private->xwindow, updateRgn, FALSE))
726             g_warning ("gdk_draw_pixmap: InvalidateRgn failed");
727           if (!UpdateWindow (drawable_private->xwindow))
728             g_warning ("gdk_draw_pixmap: UpdateWindow failed");
729         }
730       else
731         {
732           if ((srcdc = GetDC (src_private->xwindow)) == NULL)
733             g_warning ("gdk_draw_pixmap: GetDC failed");
734           
735           if (!BitBlt (hdc, xdest, ydest, width, height,
736                        srcdc, xsrc, ysrc, SRCCOPY))
737             g_warning ("gdk_draw_pixmap: BitBlt failed");
738           ReleaseDC (src_private->xwindow, srcdc);
739         }
740     }
741   gdk_gc_postdraw (drawable_private, gc_private);
742 }
743
744 void
745 gdk_draw_image (GdkDrawable *drawable,
746                 GdkGC       *gc,
747                 GdkImage    *image,
748                 gint         xsrc,
749                 gint         ysrc,
750                 gint         xdest,
751                 gint         ydest,
752                 gint         width,
753                 gint         height)
754 {
755   GdkImagePrivate *image_private;
756
757   g_return_if_fail (drawable != NULL);
758   g_return_if_fail (image != NULL);
759   g_return_if_fail (gc != NULL);
760
761   image_private = (GdkImagePrivate*) image;
762
763   g_return_if_fail (image_private->image_put != NULL);
764
765   if (width == -1)
766     width = image->width;
767   if (height == -1)
768     height = image->height;
769
770   (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
771                                 xdest, ydest, width, height);
772 }
773
774 void
775 gdk_draw_points (GdkDrawable *drawable,
776                  GdkGC       *gc,
777                  GdkPoint    *points,
778                  gint         npoints)
779 {
780   GdkDrawablePrivate *drawable_private;
781   GdkGCPrivate *gc_private;
782   HDC hdc;
783   int i;
784
785   g_return_if_fail (drawable != NULL);
786   g_return_if_fail ((points != NULL) && (npoints > 0));
787   g_return_if_fail (gc != NULL);
788
789   if (GDK_DRAWABLE_DESTROYED (drawable))
790     return;
791   drawable_private = (GdkDrawablePrivate*) drawable;
792   gc_private = (GdkGCPrivate*) gc;
793
794   hdc = gdk_gc_predraw (drawable_private, gc_private);
795   
796   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x "
797                            "npoints: %d\n",
798                            drawable_private->xwindow, gc_private, hdc,
799                            npoints));
800
801   for (i = 0; i < npoints; i++)
802     {
803       if (!MoveToEx (hdc, points[i].x, points[i].y, NULL))
804         g_warning ("gdk_draw_points: MoveToEx failed");
805       if (!LineTo (hdc, points[i].x + 1, points[i].y))
806         g_warning ("gdk_draw_points: LineTo failed");
807     }
808   gdk_gc_postdraw (drawable_private, gc_private);
809 }
810
811 void
812 gdk_draw_segments (GdkDrawable *drawable,
813                    GdkGC       *gc,
814                    GdkSegment  *segs,
815                    gint         nsegs)
816 {
817   GdkDrawablePrivate *drawable_private;
818   GdkGCPrivate *gc_private;
819   HDC hdc;
820   int i;
821
822   if (nsegs <= 0)
823     return;
824
825   g_return_if_fail (drawable != NULL);
826   g_return_if_fail (segs != NULL);
827   g_return_if_fail (gc != NULL);
828
829   if (GDK_DRAWABLE_DESTROYED (drawable))
830     return;
831   drawable_private = (GdkDrawablePrivate*) drawable;
832   gc_private = (GdkGCPrivate*) gc;
833
834   hdc = gdk_gc_predraw (drawable_private, gc_private);
835
836   for (i = 0; i < nsegs; i++)
837     {
838       if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
839         g_warning ("gdk_draw_segments: MoveToEx failed");
840       if (!LineTo (hdc, segs[i].x2, segs[i].y2))
841         g_warning ("gdk_draw_segments: LineTo #1 failed");
842       
843       /* Draw end pixel */
844       if (gc_private->pen_width == 1)
845         if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
846           g_warning ("gdk_draw_segments: LineTo #2 failed");
847     }
848   gdk_gc_postdraw (drawable_private, gc_private);
849 }
850
851 void
852 gdk_draw_lines (GdkDrawable *drawable,
853                 GdkGC       *gc,
854                 GdkPoint    *points,
855                 gint         npoints)
856 {
857   GdkDrawablePrivate *drawable_private;
858   GdkGCPrivate *gc_private;
859   HDC hdc;
860   POINT *pts;
861   int i;
862
863   if (npoints < 2)
864     return;
865
866   g_return_if_fail (drawable != NULL);
867   g_return_if_fail (points != NULL);
868   g_return_if_fail (gc != NULL);
869
870   if (GDK_DRAWABLE_DESTROYED (drawable))
871     return;
872   drawable_private = (GdkDrawablePrivate*) drawable;
873   gc_private = (GdkGCPrivate*) gc;
874
875   hdc = gdk_gc_predraw (drawable_private, gc_private);
876 #if 1
877   pts = g_malloc (npoints * sizeof (POINT));
878
879   for (i = 0; i < npoints; i++)
880     {
881       pts[i].x = points[i].x;
882       pts[i].y = points[i].y;
883     }
884   
885   if (!Polyline (hdc, pts, npoints))
886     g_warning ("gdk_draw_lines: Polyline(,,%d) failed", npoints);
887   
888   g_free (pts);
889   
890   /* Draw end pixel */
891   if (gc_private->pen_width == 1)
892     {
893       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
894       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
895         g_warning ("gdk_draw_lines: LineTo failed");
896     }
897 #else
898   MoveToEx (hdc, points[0].x, points[0].y, NULL);
899   for (i = 1; i < npoints; i++)
900     if (!LineTo (hdc, points[i].x, points[i].y))
901       g_warning ("gdk_draw_lines: LineTo #1 failed");
902   
903   /* Draw end pixel */
904   if (gc_private->pen_width == 1)
905     if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
906       g_warning ("gdk_draw_lines: LineTo #2 failed");
907 #endif  
908   gdk_gc_postdraw (drawable_private, gc_private);
909 }