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