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