]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
gdk/win32/gdkdrawable-win32.c Use correct casts in debugging output.
[~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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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-2000.  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 <math.h>
28 #include <glib.h>
29
30 #include <pango/pangowin32.h>
31
32 #include "gdkinternals.h"
33 #include "gdkprivate-win32.h"
34
35 static void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
36                                       GdkGC          *gc,
37                                       gint            filled,
38                                       gint            x,
39                                       gint            y,
40                                       gint            width,
41                                       gint            height);
42 static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
43                                       GdkGC          *gc,
44                                       gint            filled,
45                                       gint            x,
46                                       gint            y,
47                                       gint            width,
48                                       gint            height,
49                                       gint            angle1,
50                                       gint            angle2);
51 static void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
52                                       GdkGC          *gc,
53                                       gint            filled,
54                                       GdkPoint       *points,
55                                       gint            npoints);
56 static void gdk_win32_draw_text      (GdkDrawable    *drawable,
57                                       GdkFont        *font,
58                                       GdkGC          *gc,
59                                       gint            x,
60                                       gint            y,
61                                       const gchar    *text,
62                                       gint            text_length);
63 static void gdk_win32_draw_text_wc   (GdkDrawable    *drawable,
64                                       GdkFont        *font,
65                                       GdkGC          *gc,
66                                       gint            x,
67                                       gint            y,
68                                       const GdkWChar *text,
69                                       gint            text_length);
70 static void gdk_win32_draw_drawable  (GdkDrawable    *drawable,
71                                       GdkGC          *gc,
72                                       GdkPixmap      *src,
73                                       gint            xsrc,
74                                       gint            ysrc,
75                                       gint            xdest,
76                                       gint            ydest,
77                                       gint            width,
78                                       gint            height);
79 static void gdk_win32_draw_points    (GdkDrawable    *drawable,
80                                       GdkGC          *gc,
81                                       GdkPoint       *points,
82                                       gint            npoints);
83 static void gdk_win32_draw_segments  (GdkDrawable    *drawable,
84                                       GdkGC          *gc,
85                                       GdkSegment     *segs,
86                                       gint            nsegs);
87 static void gdk_win32_draw_lines     (GdkDrawable    *drawable,
88                                       GdkGC          *gc,
89                                       GdkPoint       *points,
90                                       gint            npoints);
91 static void gdk_win32_draw_glyphs    (GdkDrawable      *drawable,
92                                       GdkGC            *gc,
93                                       PangoFont        *font,
94                                       gint              x,
95                                       gint              y,
96                                       PangoGlyphString *glyphs);
97 static void gdk_win32_draw_image     (GdkDrawable     *drawable,
98                                       GdkGC           *gc,
99                                       GdkImage        *image,
100                                       gint             xsrc,
101                                       gint             ysrc,
102                                       gint             xdest,
103                                       gint             ydest,
104                                       gint             width,
105                                       gint             height);
106
107 static void gdk_win32_set_colormap   (GdkDrawable    *drawable,
108                                       GdkColormap    *colormap);
109
110 static GdkColormap* gdk_win32_get_colormap   (GdkDrawable    *drawable);
111
112 static gint         gdk_win32_get_depth      (GdkDrawable    *drawable);
113
114 static GdkVisual*   gdk_win32_get_visual     (GdkDrawable    *drawable);
115
116 static void gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass);
117
118 static gpointer parent_class = NULL;
119
120 GType
121 gdk_drawable_impl_win32_get_type (void)
122 {
123   static GType object_type = 0;
124
125   if (!object_type)
126     {
127       static const GTypeInfo object_info =
128       {
129         sizeof (GdkDrawableImplWin32Class),
130         (GBaseInitFunc) NULL,
131         (GBaseFinalizeFunc) NULL,
132         (GClassInitFunc) gdk_drawable_impl_win32_class_init,
133         NULL,           /* class_finalize */
134         NULL,           /* class_data */
135         sizeof (GdkDrawableImplWin32),
136         0,              /* n_preallocs */
137         (GInstanceInitFunc) NULL,
138       };
139       
140       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
141                                             "GdkDrawableImplWin32",
142                                             &object_info, 0);
143     }
144   
145   return object_type;
146 }
147
148 static void
149 gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
150 {
151   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
152
153   parent_class = g_type_class_peek_parent (klass);
154
155   drawable_class->create_gc = _gdk_win32_gc_new;
156   drawable_class->draw_rectangle = gdk_win32_draw_rectangle;
157   drawable_class->draw_arc = gdk_win32_draw_arc;
158   drawable_class->draw_polygon = gdk_win32_draw_polygon;
159   drawable_class->draw_text = gdk_win32_draw_text;
160   drawable_class->draw_text_wc = gdk_win32_draw_text_wc;
161   drawable_class->draw_drawable = gdk_win32_draw_drawable;
162   drawable_class->draw_points = gdk_win32_draw_points;
163   drawable_class->draw_segments = gdk_win32_draw_segments;
164   drawable_class->draw_lines = gdk_win32_draw_lines;
165   drawable_class->draw_glyphs = gdk_win32_draw_glyphs;
166   drawable_class->draw_image = gdk_win32_draw_image;
167   
168   drawable_class->set_colormap = gdk_win32_set_colormap;
169   drawable_class->get_colormap = gdk_win32_get_colormap;
170
171   drawable_class->get_depth = gdk_win32_get_depth;
172   drawable_class->get_visual = gdk_win32_get_visual;
173
174   drawable_class->get_image = _gdk_win32_get_image;
175 }
176
177 /*****************************************************
178  * Win32 specific implementations of generic functions *
179  *****************************************************/
180
181 static GdkColormap*
182 gdk_win32_get_colormap (GdkDrawable *drawable)
183 {
184   GdkDrawableImplWin32 *impl;
185   
186   impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
187
188   return impl->colormap;
189 }
190
191 static void
192 gdk_win32_set_colormap (GdkDrawable *drawable,
193                         GdkColormap *colormap)
194 {
195   GdkDrawableImplWin32 *impl;
196
197   g_return_if_fail (colormap != NULL);  
198
199   impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
200
201   if (impl->colormap == colormap)
202     return;
203   
204   if (impl->colormap)
205     gdk_colormap_unref (impl->colormap);
206   impl->colormap = colormap;
207   if (impl->colormap)
208     gdk_colormap_ref (impl->colormap);
209 }
210
211 /* Drawing
212  */
213
214 static void
215 gdk_win32_draw_rectangle (GdkDrawable *drawable,
216                           GdkGC       *gc,
217                           gint         filled,
218                           gint         x,
219                           gint         y,
220                           gint         width,
221                           gint         height)
222 {
223   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
224   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
225   HDC hdc;
226   HGDIOBJ old_pen_or_brush;
227   POINT pts[4];
228   gboolean ok = TRUE;
229
230   GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%p) %s%dx%d@+%d+%d\n",
231                            (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
232                            gc_private,
233                            (filled ? "fill " : ""),
234                            width, height, x, y));
235     
236   hdc = gdk_win32_hdc_get (drawable, gc, mask);
237
238 #if 0
239   {
240     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
241     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
242     LOGBRUSH lbr;
243     LOGPEN lpen;
244     GetObject (hbr, sizeof (lbr), &lbr);
245     GetObject (hpen, sizeof (lpen), &lpen);
246     
247     g_print ("current brush: style = %s, color = 0x%.08x\n",
248              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
249              lbr.lbColor);
250     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
251              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
252              lpen.lopnWidth,
253              lpen.lopnColor);
254   }
255 #endif
256
257   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
258     {
259       if (!BeginPath (hdc))
260         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
261
262       /* Win9x doesn't support Rectangle calls in a path,
263        * thus use Polyline.
264        */
265           
266       pts[0].x = x;
267       pts[0].y = y;
268       pts[1].x = x + width + 1;
269       pts[1].y = y;
270       pts[2].x = x + width + 1;
271       pts[2].y = y + height + 1;
272       pts[3].x = x;
273       pts[3].y = y + height + 1;
274       
275       if (ok)
276         MoveToEx (hdc, x, y, NULL);
277       
278       if (ok && !Polyline (hdc, pts, 4))
279         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
280           
281       if (ok && !CloseFigure (hdc))
282         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
283
284       if (ok && !EndPath (hdc))
285         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
286           
287       if (ok && !filled)
288         if (!WidenPath (hdc))
289           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
290           
291       if (ok && !FillPath (hdc))
292         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
293     }
294   else
295     {
296       if (filled)
297         old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
298       else
299         old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
300   
301       if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
302         WIN32_GDI_FAILED ("Rectangle");
303   
304       SelectObject (hdc, old_pen_or_brush);
305     }
306
307   gdk_win32_hdc_release (drawable, gc, mask);
308 }
309
310 static void
311 gdk_win32_draw_arc (GdkDrawable *drawable,
312                     GdkGC       *gc,
313                     gint         filled,
314                     gint         x,
315                     gint         y,
316                     gint         width,
317                     gint         height,
318                     gint         angle1,
319                     gint         angle2)
320 {
321   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
322   HDC hdc;
323   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
324
325   GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
326                            (guint) GDK_DRAWABLE_HANDLE (drawable),
327                            x, y, width, height, angle1, angle2));
328
329   /* Seems that drawing arcs with width or height <= 2 fails, at least
330    * with my TNT card.
331    */
332   if (width <= 2 || height <= 2 || angle2 == 0)
333     return;
334
335   hdc = gdk_win32_hdc_get (drawable, gc, mask);
336
337   if (angle2 >= 360*64)
338     {
339       nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
340     }
341   else if (angle2 > 0)
342     {
343       /* The 100. is just an arbitrary value */
344       nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
345       nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
346       nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
347       nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
348     }
349   else
350     {
351       nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
352       nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
353       nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
354       nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
355     }
356   
357   /* GDK_OPAQUE_STIPPLED arcs not implemented. */
358   
359   if (filled)
360     {
361       GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
362                                x, y, x+width, y+height,
363                                nXStartArc, nYStartArc,
364                                nXEndArc, nYEndArc));
365       if (!Pie (hdc, x, y, x+width, y+height,
366                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
367         WIN32_GDI_FAILED ("Pie");
368     }
369   else
370     {
371       GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
372                                x, y, x+width, y+height,
373                                nXStartArc, nYStartArc,
374                                nXEndArc, nYEndArc));
375       if (!Arc (hdc, x, y, x+width, y+height,
376                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
377         WIN32_GDI_FAILED ("Arc");
378     }
379   gdk_win32_hdc_release (drawable, gc, mask);
380 }
381
382 static void
383 gdk_win32_draw_polygon (GdkDrawable *drawable,
384                         GdkGC       *gc,
385                         gint         filled,
386                         GdkPoint    *points,
387                         gint         npoints)
388 {
389   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
390   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
391   HDC hdc;
392   POINT *pts;
393   gboolean ok = TRUE;
394   int i;
395
396   GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%p) %d\n",
397                            (guint) GDK_DRAWABLE_HANDLE (drawable),
398                            gc_private,
399                            npoints));
400
401   if (npoints < 2)
402     return;
403
404   hdc = gdk_win32_hdc_get (drawable, gc, mask);
405   pts = g_new (POINT, npoints+1);
406
407   for (i = 0; i < npoints; i++)
408     {
409       pts[i].x = points[i].x;
410       pts[i].y = points[i].y;
411     }
412   
413   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
414     {
415       if (!BeginPath (hdc))
416         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
417
418       if (ok)
419         MoveToEx (hdc, points[0].x, points[0].y, NULL);
420
421       if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
422         npoints--;
423
424       if (ok && !Polyline (hdc, pts, 4))
425         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
426           
427       if (ok && !CloseFigure (hdc))
428         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
429
430       if (ok && !EndPath (hdc))
431         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
432           
433       if (ok && !filled)
434         if (!WidenPath (hdc))
435           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
436           
437       if (ok && !FillPath (hdc))
438         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
439     }
440   else
441     {
442       if (points[0].x != points[npoints-1].x
443           || points[0].y != points[npoints-1].y) 
444         {
445           pts[npoints].x = points[0].x;
446           pts[npoints].y = points[0].y;
447           npoints++;
448         }
449       
450       if (filled)
451         {
452           if (!Polygon (hdc, pts, npoints))
453             WIN32_GDI_FAILED ("Polygon");
454         }
455       else
456         {
457           if (!Polyline (hdc, pts, npoints))
458             WIN32_GDI_FAILED ("Polyline");
459         }
460     }
461   g_free (pts);
462   gdk_win32_hdc_release (drawable, gc, mask);
463 }
464
465 typedef struct
466 {
467   gint x, y;
468   HDC hdc;
469 } gdk_draw_text_arg;
470
471 static void
472 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
473                        const wchar_t      *wcstr,
474                        int                 wclen,
475                        void               *arg)
476 {
477   HGDIOBJ oldfont;
478   SIZE size;
479   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
480
481   if (!singlefont)
482     return;
483
484   if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
485     {
486       WIN32_GDI_FAILED ("SelectObject");
487       return;
488     }
489   
490   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
491     WIN32_GDI_FAILED ("TextOutW");
492   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
493   argp->x += size.cx;
494
495   SelectObject (argp->hdc, oldfont);
496 }
497
498 static void
499 gdk_win32_draw_text (GdkDrawable *drawable,
500                      GdkFont     *font,
501                      GdkGC       *gc,
502                      gint         x,
503                      gint         y,
504                      const gchar *text,
505                      gint         text_length)
506 {
507   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
508   wchar_t *wcstr, wc;
509   gint wlen;
510   gdk_draw_text_arg arg;
511
512   if (text_length == 0)
513     return;
514
515   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
516
517   arg.x = x;
518   arg.y = y;
519   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
520
521   GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
522                            (guint) GDK_DRAWABLE_HANDLE (drawable),
523                            x, y,
524                            (text_length > 10 ? 10 : text_length),
525                            text, text_length));
526   
527   if (text_length == 1)
528     {
529       /* For single characters, don't try to interpret as UTF-8. */
530       wc = (guchar) text[0];
531       gdk_wchar_text_handle (font, &wc, 1, gdk_draw_text_handler, &arg);
532     }
533   else
534     {
535       wcstr = g_new (wchar_t, text_length);
536       if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
537         g_warning ("gdk_win32_draw_text: gdk_nmbstowchar_ts failed");
538       else
539         gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
540       g_free (wcstr);
541     }
542
543
544   gdk_win32_hdc_release (drawable, gc, mask);
545 }
546
547 static void
548 gdk_win32_draw_text_wc (GdkDrawable      *drawable,
549                         GdkFont          *font,
550                         GdkGC            *gc,
551                         gint              x,
552                         gint              y,
553                         const GdkWChar *text,
554                         gint              text_length)
555 {
556   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
557   gint i;
558   wchar_t *wcstr;
559   gdk_draw_text_arg arg;
560
561   if (text_length == 0)
562     return;
563
564   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
565
566   arg.x = x;
567   arg.y = y;
568   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
569
570   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
571                            (guint) GDK_DRAWABLE_HANDLE (drawable),
572                            x, y, text_length));
573       
574   if (sizeof (wchar_t) != sizeof (GdkWChar))
575     {
576       wcstr = g_new (wchar_t, text_length);
577       for (i = 0; i < text_length; i++)
578         wcstr[i] = text[i];
579     }
580   else
581     wcstr = (wchar_t *) text;
582
583   gdk_wchar_text_handle (font, wcstr, text_length,
584                          gdk_draw_text_handler, &arg);
585
586   if (sizeof (wchar_t) != sizeof (GdkWChar))
587     g_free (wcstr);
588
589   gdk_win32_hdc_release (drawable, gc, mask);
590 }
591
592 static void
593 gdk_win32_draw_drawable (GdkDrawable *drawable,
594                          GdkGC       *gc,
595                          GdkPixmap   *src,
596                          gint         xsrc,
597                          gint         ysrc,
598                          gint         xdest,
599                          gint         ydest,
600                          gint         width,
601                          gint         height)
602 {
603   HDC hdc;
604   HDC srcdc;
605   HGDIOBJ hgdiobj;
606   HRGN src_rgn, draw_rgn, outside_rgn;
607   RECT r;
608   gint src_width, src_height;
609   gboolean ok = TRUE;
610   GdkDrawableImplWin32 *impl;
611   HANDLE src_handle;
612
613   impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
614   if (GDK_IS_DRAWABLE_IMPL_WIN32(src))
615     src_handle = GDK_DRAWABLE_IMPL_WIN32 (src)->handle;
616   else
617     src_handle = GDK_DRAWABLE_HANDLE (src);
618
619   GDK_NOTE (MISC, g_print ("gdk_win32_draw_drawable: dest: %#x @+%d+%d"
620                            " src: %#x %dx%d@+%d+%d\n",
621                            (guint) impl->handle,
622                            xdest, ydest,
623                            (guint) src_handle,
624                            width, height, xsrc, ysrc));
625
626   hdc = gdk_win32_hdc_get (drawable, gc, 0);
627
628   gdk_drawable_get_size (src, &src_width, &src_height);
629   src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1);
630   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
631   
632   if (GDK_IS_WINDOW_IMPL_WIN32 (drawable))
633     {
634       /* If we are drawing on a window, calculate the region that is
635        * outside the source pixmap, and invalidate that, causing it to
636        * be cleared. XXX
637        */
638       SetRectEmpty (&r);
639       outside_rgn = CreateRectRgnIndirect (&r);
640       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
641         {
642           if (ERROR == OffsetRgn (outside_rgn, xdest, ydest))
643             WIN32_GDI_FAILED ("OffsetRgn");
644           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
645                            g_print ("...calling InvalidateRgn, "
646                                     "bbox: %ldx%ld@+%ld+%ld\n",
647                                     r.right - r.left - 1, r.bottom - r.top - 1,
648                                     r.left, r.top)));
649           if (!InvalidateRgn (impl->handle, outside_rgn, TRUE))
650             WIN32_GDI_FAILED ("InvalidateRgn");
651         }
652       if (!DeleteObject (outside_rgn))
653         WIN32_GDI_FAILED ("DeleteObject");
654     }
655
656 #if 1 /* Don't know if this is necessary  */
657   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
658     g_warning ("gdk_win32_draw_drawable: CombineRgn returned a COMPLEXREGION");
659
660   if (0 == GetRgnBox (draw_rgn, &r))
661     WIN32_GDI_FAILED("GetRgnBox");
662   if (r.left != xsrc
663       || r.top != ysrc
664       || r.right != xsrc + width + 1
665       || r.bottom != ysrc + height + 1)
666     {
667       xdest += r.left - xsrc;
668       xsrc = r.left;
669       ydest += r.top - ysrc;
670       ysrc = r.top;
671       width = r.right - xsrc - 1;
672       height = r.bottom - ysrc - 1;
673       
674       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
675                                "dest: @+%d+%d\n",
676                                width, height, xsrc, ysrc,
677                                xdest, ydest));
678     }
679 #endif
680
681   if (!DeleteObject (src_rgn))
682     WIN32_GDI_FAILED ("DeleteObject");
683   if (!DeleteObject (draw_rgn))
684     WIN32_GDI_FAILED ("DeleteObject");
685
686   /* This function is called also to bitblt from a window.
687    */
688   if (GDK_IS_PIXMAP_IMPL_WIN32 (src) || GDK_IS_PIXMAP(src))
689     {
690       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
691         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
692       
693       if (ok && (hgdiobj = SelectObject (srcdc, src_handle)) == NULL)
694         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
695       
696       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
697                          srcdc, xsrc, ysrc, SRCCOPY))
698         WIN32_GDI_FAILED ("BitBlt");
699       
700       if (ok && (SelectObject (srcdc, hgdiobj) == NULL))
701         WIN32_GDI_FAILED ("SelectObject");
702       
703       if (srcdc != NULL && !DeleteDC (srcdc))
704         WIN32_GDI_FAILED ("DeleteDC");
705     }
706   else if (impl->handle == src_handle)
707     {
708       /* Blitting inside a window, use ScrollDC */
709       RECT scrollRect, clipRect, emptyRect;
710       HRGN updateRgn;
711       
712       scrollRect.left = MIN (xsrc, xdest);
713       scrollRect.top = MIN (ysrc, ydest);
714       scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
715       scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
716       
717       clipRect.left = xdest;
718       clipRect.top = ydest;
719       clipRect.right = xdest + width + 1;
720       clipRect.bottom = ydest + height + 1;
721       
722       SetRectEmpty (&emptyRect);
723       updateRgn = CreateRectRgnIndirect (&emptyRect);
724       if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
725                      &scrollRect, &clipRect,
726                      updateRgn, NULL))
727         WIN32_GDI_FAILED ("ScrollDC"), ok = FALSE;
728       if (ok && !InvalidateRgn (impl->handle, updateRgn, FALSE))
729         WIN32_GDI_FAILED ("InvalidateRgn"), ok = FALSE;
730       if (ok && !UpdateWindow (impl->handle))
731         WIN32_GDI_FAILED ("UpdateWindow");
732       if (!DeleteObject (updateRgn))
733         WIN32_GDI_FAILED ("DeleteObject");
734     }
735   else
736     {
737       if ((srcdc = GetDC (src_handle)) == NULL)
738         WIN32_GDI_FAILED ("GetDC"), ok = FALSE;
739       
740       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
741                          srcdc, xsrc, ysrc, SRCCOPY))
742         WIN32_GDI_FAILED ("BitBlt");
743       if (ok && !ReleaseDC (src_handle, srcdc))
744         WIN32_GDI_FAILED ("ReleaseDC");
745     }
746   gdk_win32_hdc_release (drawable, gc, 0);
747 }
748
749 static void
750 gdk_win32_draw_points (GdkDrawable *drawable,
751                        GdkGC       *gc,
752                        GdkPoint    *points,
753                        gint         npoints)
754 {
755   HDC hdc;
756   COLORREF fg;
757   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
758   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
759   int i;
760
761   hdc = gdk_win32_hdc_get (drawable, gc, 0);
762   
763   fg = gdk_colormap_color (impl->colormap, gc_private->foreground);
764
765   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
766                            (guint) GDK_DRAWABLE_HANDLE (drawable),
767                            npoints, (guint) fg));
768
769   for (i = 0; i < npoints; i++)
770     SetPixel (hdc, points[i].x, points[i].y, fg);
771
772   gdk_win32_hdc_release (drawable, gc, 0);
773 }
774
775 static void
776 gdk_win32_draw_segments (GdkDrawable *drawable,
777                          GdkGC       *gc,
778                          GdkSegment  *segs,
779                          gint         nsegs)
780 {
781   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
782   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
783   HDC hdc;
784   gboolean ok = TRUE;
785   int i;
786
787   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
788                            (guint) GDK_DRAWABLE_HANDLE (drawable), nsegs));
789
790   hdc = gdk_win32_hdc_get (drawable, gc, mask);
791
792   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
793     {
794       if (!BeginPath (hdc))
795         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
796       
797       for (i = 0; ok && i < nsegs; i++)
798         {
799           if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
800             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
801           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
802             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
803           
804           /* Draw end pixel */
805           if (ok && gc_private->pen_width <= 1)
806             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
807               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
808         }
809
810       if (ok && !EndPath (hdc))
811         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
812           
813       if (ok && !WidenPath (hdc))
814         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
815           
816       if (ok && !FillPath (hdc))
817         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
818     }
819   else
820     {
821       for (i = 0; ok && i < nsegs; i++)
822         {
823           if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
824             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
825           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
826             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
827           
828           /* Draw end pixel */
829           if (ok && gc_private->pen_width <= 1)
830             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
831               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
832         }
833     }
834   gdk_win32_hdc_release (drawable, gc, mask);
835 }
836
837 static void
838 gdk_win32_draw_lines (GdkDrawable *drawable,
839                       GdkGC       *gc,
840                       GdkPoint    *points,
841                       gint         npoints)
842 {
843   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
844   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
845   HDC hdc;
846   POINT *pts;
847   int i;
848   gboolean ok = TRUE;
849
850   if (npoints < 2)
851     return;
852
853   hdc = gdk_win32_hdc_get (drawable, gc, mask);
854
855   pts = g_new (POINT, npoints);
856
857   for (i = 0; i < npoints; i++)
858     {
859       pts[i].x = points[i].x;
860       pts[i].y = points[i].y;
861     }
862   
863   if (!Polyline (hdc, pts, npoints))
864     WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
865   
866   g_free (pts);
867   
868   /* Draw end pixel */
869   if (ok && gc_private->pen_width <= 1)
870     {
871       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
872       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
873         WIN32_GDI_FAILED ("LineTo");
874     }
875   gdk_win32_hdc_release (drawable, gc, mask);
876 }
877
878 static void
879 gdk_win32_draw_glyphs (GdkDrawable      *drawable,
880                        GdkGC            *gc,
881                        PangoFont        *font,
882                        gint              x,
883                        gint              y,
884                        PangoGlyphString *glyphs)
885 {
886   const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
887   HDC hdc;
888
889   hdc = gdk_win32_hdc_get (drawable, gc, mask);
890
891   /* HB: Maybe there should be a GDK_GC_PANGO flag for hdc_get */
892   /* default write mode is transparent (leave background) */
893   if (SetBkMode (hdc, TRANSPARENT) == 0)
894     WIN32_GDI_FAILED ("SetBkMode");
895
896   if (GDI_ERROR == SetTextAlign (hdc, TA_LEFT|TA_BOTTOM|TA_NOUPDATECP))
897     WIN32_GDI_FAILED ("SetTextAlign");
898
899   pango_win32_render (hdc, font, glyphs, x, y);
900
901   gdk_win32_hdc_release (drawable, gc, mask);
902 }
903
904 static void
905 gdk_win32_draw_image (GdkDrawable     *drawable,
906                       GdkGC           *gc,
907                       GdkImage        *image,
908                       gint             xsrc,
909                       gint             ysrc,
910                       gint             xdest,
911                       gint             ydest,
912                       gint             width,
913                       gint             height)
914 {
915   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
916   GdkImagePrivateWin32 *image_private = IMAGE_PRIVATE_DATA (image);
917   GdkColormapPrivateWin32 *colormap_private = (GdkColormapPrivateWin32 *) impl->colormap;
918   HDC hdc, memdc;
919   HGDIOBJ oldbitmap;
920   DIBSECTION ds;
921   static struct {
922     BITMAPINFOHEADER bmiHeader;
923     WORD bmiIndices[256];
924   } bmi;
925   static gboolean bmi_inited = FALSE;
926   gboolean ok = TRUE;
927   int i;
928
929   hdc = gdk_win32_hdc_get (drawable, gc, 0);
930
931   if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR &&
932           colormap_private && colormap_private->xcolormap->rc_palette)
933     {
934       if (!bmi_inited)
935         {
936           for (i = 0; i < 256; i++)
937             bmi.bmiIndices[i] = i;
938           bmi_inited = TRUE;
939         }
940
941       if (GetObject (image_private->hbitmap, sizeof (DIBSECTION),
942                      &ds) != sizeof (DIBSECTION))
943         WIN32_GDI_FAILED ("GetObject"), ok = FALSE;
944 #if 0
945       g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
946               xdest, ydest, xsrc, ysrc, width, height);
947       g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
948               ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
949       g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
950               ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
951 #endif
952       bmi.bmiHeader = ds.dsBmih;
953       /* I have spent hours on getting the parameters to
954        * SetDIBitsToDevice right. I wonder what drugs the guys in
955        * Redmond were on when they designed this API.
956        */
957       if (ok && SetDIBitsToDevice (hdc,
958                                    xdest, ydest,
959                                    width, height,
960                                    xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
961                                    0, -ds.dsBmih.biHeight,
962                                    ds.dsBm.bmBits,
963                                    (CONST BITMAPINFO *) &bmi,
964                                    DIB_PAL_COLORS) == 0)
965         WIN32_GDI_FAILED ("SetDIBitsToDevice");
966     }
967   else
968     {
969
970       if ((memdc = CreateCompatibleDC (hdc)) == NULL)
971         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
972
973       if (ok && (oldbitmap = SelectObject (memdc, image_private->hbitmap)) == NULL)
974         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
975
976       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
977                          memdc, xsrc, ysrc, SRCCOPY))
978         WIN32_GDI_FAILED ("BitBlt");
979
980       if (oldbitmap != NULL && SelectObject (memdc, oldbitmap) == NULL)
981         WIN32_GDI_FAILED ("SelectObject");
982
983       if (memdc != NULL && !DeleteDC (memdc))
984         WIN32_GDI_FAILED ("DeleteDC");
985     }
986   gdk_win32_hdc_release (drawable, gc, 0);
987 }
988
989 static gint
990 gdk_win32_get_depth (GdkDrawable *drawable)
991 {
992   /* This is a bit bogus but I'm not sure the other way is better */
993
994   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
995 }
996
997 static GdkVisual*
998 gdk_win32_get_visual (GdkDrawable *drawable)
999 {
1000   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1001 }