]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
updated externals
[~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   if (filled 
237       && (gc_private->tile)
238       && (gc_private->values_mask & GDK_GC_TILE)    
239       && (gc_private->values_mask & GDK_GC_FILL))
240     {
241       gdk_win32_draw_tiles (drawable, gc, gc_private->tile, x, y, width, height);
242       return;
243     }
244
245   hdc = gdk_win32_hdc_get (drawable, gc, mask);
246
247 #if 0
248   {
249     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
250     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
251     LOGBRUSH lbr;
252     LOGPEN lpen;
253     GetObject (hbr, sizeof (lbr), &lbr);
254     GetObject (hpen, sizeof (lpen), &lpen);
255     
256     g_print ("current brush: style = %s, color = 0x%.08x\n",
257              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
258              lbr.lbColor);
259     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
260              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
261              lpen.lopnWidth,
262              lpen.lopnColor);
263   }
264 #endif
265
266   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
267     {
268       if (!BeginPath (hdc))
269         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
270
271       /* Win9x doesn't support Rectangle calls in a path,
272        * thus use Polyline.
273        */
274           
275       pts[0].x = x;
276       pts[0].y = y;
277       pts[1].x = x + width + 1;
278       pts[1].y = y;
279       pts[2].x = x + width + 1;
280       pts[2].y = y + height + 1;
281       pts[3].x = x;
282       pts[3].y = y + height + 1;
283       
284       if (ok)
285         MoveToEx (hdc, x, y, NULL);
286       
287       if (ok && !Polyline (hdc, pts, 4))
288         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
289           
290       if (ok && !CloseFigure (hdc))
291         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
292
293       if (ok && !EndPath (hdc))
294         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
295           
296       if (ok && !filled)
297         if (!WidenPath (hdc))
298           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
299           
300       if (ok && !FillPath (hdc))
301         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
302     }
303   else
304     {
305       if (filled)
306         old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
307       else
308         old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
309   
310       if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
311         WIN32_GDI_FAILED ("Rectangle");
312   
313       SelectObject (hdc, old_pen_or_brush);
314     }
315
316   gdk_win32_hdc_release (drawable, gc, mask);
317 }
318
319 static void
320 gdk_win32_draw_arc (GdkDrawable *drawable,
321                     GdkGC       *gc,
322                     gint         filled,
323                     gint         x,
324                     gint         y,
325                     gint         width,
326                     gint         height,
327                     gint         angle1,
328                     gint         angle2)
329 {
330   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
331   HDC hdc;
332   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
333
334   GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
335                            (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
336                            x, y, width, height, angle1, angle2));
337
338   /* Seems that drawing arcs with width or height <= 2 fails, at least
339    * with my TNT card.
340    */
341   if (width <= 2 || height <= 2 || angle2 == 0)
342     return;
343
344   hdc = gdk_win32_hdc_get (drawable, gc, mask);
345
346   if (angle2 >= 360*64)
347     {
348       nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
349     }
350   else if (angle2 > 0)
351     {
352       /* The 100. is just an arbitrary value */
353       nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
354       nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
355       nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
356       nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
357     }
358   else
359     {
360       nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
361       nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
362       nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
363       nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
364     }
365   
366   /* GDK_OPAQUE_STIPPLED arcs not implemented. */
367   
368   if (filled)
369     {
370       GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
371                                x, y, x+width, y+height,
372                                nXStartArc, nYStartArc,
373                                nXEndArc, nYEndArc));
374       if (!Pie (hdc, x, y, x+width, y+height,
375                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
376         WIN32_GDI_FAILED ("Pie");
377     }
378   else
379     {
380       GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
381                                x, y, x+width, y+height,
382                                nXStartArc, nYStartArc,
383                                nXEndArc, nYEndArc));
384       if (!Arc (hdc, x, y, x+width, y+height,
385                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
386         WIN32_GDI_FAILED ("Arc");
387     }
388   gdk_win32_hdc_release (drawable, gc, mask);
389 }
390
391 static void
392 gdk_win32_draw_polygon (GdkDrawable *drawable,
393                         GdkGC       *gc,
394                         gint         filled,
395                         GdkPoint    *points,
396                         gint         npoints)
397 {
398   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
399   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
400   HDC hdc;
401   POINT *pts;
402   gboolean ok = TRUE;
403   int i;
404
405   GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%p) %d\n",
406                            (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
407                            gc_private,
408                            npoints));
409
410   if (npoints < 2)
411     return;
412
413   hdc = gdk_win32_hdc_get (drawable, gc, mask);
414   pts = g_new (POINT, npoints+1);
415
416   for (i = 0; i < npoints; i++)
417     {
418       pts[i].x = points[i].x;
419       pts[i].y = points[i].y;
420     }
421   
422   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
423     {
424       if (!BeginPath (hdc))
425         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
426
427       if (ok)
428         MoveToEx (hdc, points[0].x, points[0].y, NULL);
429
430       if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
431         npoints--;
432
433       if (ok && !Polyline (hdc, pts, 4))
434         WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
435           
436       if (ok && !CloseFigure (hdc))
437         WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
438
439       if (ok && !EndPath (hdc))
440         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
441           
442       if (ok && !filled)
443         if (!WidenPath (hdc))
444           WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
445           
446       if (ok && !FillPath (hdc))
447         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
448     }
449   else
450     {
451       if (points[0].x != points[npoints-1].x
452           || points[0].y != points[npoints-1].y) 
453         {
454           pts[npoints].x = points[0].x;
455           pts[npoints].y = points[0].y;
456           npoints++;
457         }
458       
459       if (filled)
460         {
461           if (!Polygon (hdc, pts, npoints))
462             WIN32_GDI_FAILED ("Polygon");
463         }
464       else
465         {
466           if (!Polyline (hdc, pts, npoints))
467             WIN32_GDI_FAILED ("Polyline");
468         }
469     }
470   g_free (pts);
471   gdk_win32_hdc_release (drawable, gc, mask);
472 }
473
474 typedef struct
475 {
476   gint x, y;
477   HDC hdc;
478 } gdk_draw_text_arg;
479
480 static void
481 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
482                        const wchar_t      *wcstr,
483                        int                 wclen,
484                        void               *arg)
485 {
486   HGDIOBJ oldfont;
487   SIZE size;
488   gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
489
490   if (!singlefont)
491     return;
492
493   if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
494     {
495       WIN32_GDI_FAILED ("SelectObject");
496       return;
497     }
498   
499   if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
500     WIN32_GDI_FAILED ("TextOutW");
501   GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
502   argp->x += size.cx;
503
504   SelectObject (argp->hdc, oldfont);
505 }
506
507 static void
508 gdk_win32_draw_text (GdkDrawable *drawable,
509                      GdkFont     *font,
510                      GdkGC       *gc,
511                      gint         x,
512                      gint         y,
513                      const gchar *text,
514                      gint         text_length)
515 {
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                            (guint) 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   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
566   gint i;
567   wchar_t *wcstr;
568   gdk_draw_text_arg arg;
569
570   if (text_length == 0)
571     return;
572
573   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
574
575   arg.x = x;
576   arg.y = y;
577   arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
578
579   GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
580                            (guint) GDK_DRAWABLE_HANDLE (drawable),
581                            x, y, text_length));
582       
583   if (sizeof (wchar_t) != sizeof (GdkWChar))
584     {
585       wcstr = g_new (wchar_t, text_length);
586       for (i = 0; i < text_length; i++)
587         wcstr[i] = text[i];
588     }
589   else
590     wcstr = (wchar_t *) text;
591
592   gdk_wchar_text_handle (font, wcstr, text_length,
593                          gdk_draw_text_handler, &arg);
594
595   if (sizeof (wchar_t) != sizeof (GdkWChar))
596     g_free (wcstr);
597
598   gdk_win32_hdc_release (drawable, gc, mask);
599 }
600
601 static void
602 gdk_win32_draw_drawable (GdkDrawable *drawable,
603                          GdkGC       *gc,
604                          GdkPixmap   *src,
605                          gint         xsrc,
606                          gint         ysrc,
607                          gint         xdest,
608                          gint         ydest,
609                          gint         width,
610                          gint         height)
611 {
612   HDC hdc;
613   HDC srcdc;
614   HGDIOBJ hgdiobj;
615   HRGN src_rgn, draw_rgn, outside_rgn;
616   RECT r;
617   gint src_width, src_height;
618   gboolean ok = TRUE;
619   GdkDrawableImplWin32 *impl;
620   HANDLE src_handle;
621
622   impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
623   if (GDK_IS_DRAWABLE_IMPL_WIN32(src))
624     src_handle = GDK_DRAWABLE_IMPL_WIN32 (src)->handle;
625   else
626     src_handle = GDK_DRAWABLE_HANDLE (src);
627
628   GDK_NOTE (MISC, g_print ("gdk_win32_draw_drawable: dest: %#x @+%d+%d"
629                            " src: %#x %dx%d@+%d+%d\n",
630                            (guint) impl->handle,
631                            xdest, ydest,
632                            (guint) src_handle,
633                            width, height, xsrc, ysrc));
634
635   hdc = gdk_win32_hdc_get (drawable, gc, 0);
636
637   gdk_drawable_get_size (src, &src_width, &src_height);
638   src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1);
639   draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
640   
641 #if 0 /* HB: I dont't see reason to do this ... */
642   if (GDK_IS_WINDOW_IMPL_WIN32 (drawable))
643     {
644       /* If we are drawing on a window, calculate the region that is
645        * outside the source pixmap, and invalidate that, causing it to
646        * be cleared. XXX
647        */
648       SetRectEmpty (&r);
649       outside_rgn = CreateRectRgnIndirect (&r);
650       if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
651         {
652           if (ERROR == OffsetRgn (outside_rgn, xdest, ydest))
653             WIN32_GDI_FAILED ("OffsetRgn");
654           GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
655                            g_print ("...calling InvalidateRgn, "
656                                     "bbox: %ldx%ld@+%ld+%ld\n",
657                                     r.right - r.left - 1, r.bottom - r.top - 1,
658                                     r.left, r.top)));
659           if (!InvalidateRgn (impl->handle, outside_rgn, TRUE))
660             WIN32_GDI_FAILED ("InvalidateRgn");
661         }
662       if (!DeleteObject (outside_rgn))
663         WIN32_GDI_FAILED ("DeleteObject");
664     }
665 #endif
666
667 #if 1 /* Don't know if this is necessary  */
668   if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
669     g_warning ("gdk_win32_draw_drawable: CombineRgn returned a COMPLEXREGION");
670
671   if (0 == GetRgnBox (draw_rgn, &r))
672     WIN32_GDI_FAILED("GetRgnBox");
673   if (r.left != xsrc
674       || r.top != ysrc
675       || r.right != xsrc + width + 1
676       || r.bottom != ysrc + height + 1)
677     {
678       xdest += r.left - xsrc;
679       xsrc = r.left;
680       ydest += r.top - ysrc;
681       ysrc = r.top;
682       width = r.right - xsrc - 1;
683       height = r.bottom - ysrc - 1;
684       
685       GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
686                                "dest: @+%d+%d\n",
687                                width, height, xsrc, ysrc,
688                                xdest, ydest));
689     }
690 #endif
691
692   if (!DeleteObject (src_rgn))
693     WIN32_GDI_FAILED ("DeleteObject");
694   if (!DeleteObject (draw_rgn))
695     WIN32_GDI_FAILED ("DeleteObject");
696
697   /* This function is called also to bitblt from a window.
698    */
699   if (GDK_IS_PIXMAP_IMPL_WIN32 (src) || GDK_IS_PIXMAP(src))
700     {
701       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
702         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
703       
704       if (ok && (hgdiobj = SelectObject (srcdc, src_handle)) == NULL)
705         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
706       
707       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
708                          srcdc, xsrc, ysrc, SRCCOPY))
709         WIN32_GDI_FAILED ("BitBlt");
710       
711       if (ok && (SelectObject (srcdc, hgdiobj) == NULL))
712         WIN32_GDI_FAILED ("SelectObject");
713       
714       if (srcdc != NULL && !DeleteDC (srcdc))
715         WIN32_GDI_FAILED ("DeleteDC");
716     }
717   else if (impl->handle == src_handle)
718     {
719       /* Blitting inside a window, use ScrollDC */
720       RECT scrollRect, clipRect, emptyRect;
721       HRGN updateRgn;
722       
723       scrollRect.left = MIN (xsrc, xdest);
724       scrollRect.top = MIN (ysrc, ydest);
725       scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
726       scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
727       
728       clipRect.left = xdest;
729       clipRect.top = ydest;
730       clipRect.right = xdest + width + 1;
731       clipRect.bottom = ydest + height + 1;
732       
733       SetRectEmpty (&emptyRect);
734       updateRgn = CreateRectRgnIndirect (&emptyRect);
735       if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
736                      &scrollRect, &clipRect,
737                      updateRgn, NULL))
738         WIN32_GDI_FAILED ("ScrollDC"), ok = FALSE;
739       if (ok && !InvalidateRgn (impl->handle, updateRgn, FALSE))
740         WIN32_GDI_FAILED ("InvalidateRgn"), ok = FALSE;
741       if (ok && !UpdateWindow (impl->handle))
742         WIN32_GDI_FAILED ("UpdateWindow");
743       if (!DeleteObject (updateRgn))
744         WIN32_GDI_FAILED ("DeleteObject");
745     }
746   else
747     {
748       if ((srcdc = GetDC (src_handle)) == NULL)
749         WIN32_GDI_FAILED ("GetDC"), ok = FALSE;
750       
751       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
752                          srcdc, xsrc, ysrc, SRCCOPY))
753         WIN32_GDI_FAILED ("BitBlt");
754       if (ok && !ReleaseDC (src_handle, srcdc))
755         WIN32_GDI_FAILED ("ReleaseDC");
756     }
757   gdk_win32_hdc_release (drawable, gc, 0);
758 }
759
760 void
761 gdk_win32_draw_tiles (GdkDrawable *drawable,
762                       GdkGC       *gc,
763                       GdkPixmap   *tile,
764                       gint        x_from,
765                       gint        y_from,
766                       gint        max_width,
767                       gint        max_height)
768 {
769   gint x = x_from, y = y_from;
770   gint tile_width, tile_height;
771   gint width, height;
772
773   gdk_drawable_get_size (drawable, &width, &height);
774   gdk_drawable_get_size (tile, &tile_width, &tile_height);
775
776   width  = MIN (width,  max_width);
777   height = MIN (height, max_height);
778
779   tile_width  = MIN (tile_width,  max_width);
780   tile_height = MIN (tile_height, max_height);
781
782   while (y < height)
783     {
784       x = x_from;
785       while (x < width)
786         {
787           gdk_win32_draw_drawable (drawable, gc, tile,
788                                    x % tile_width,  /* xsrc */
789                                    y % tile_height, /* ysrc */
790                                    x, y, /* dest */
791                                    tile_width, tile_height);
792           x += tile_width;
793         }
794       y += tile_height;
795     }
796 }
797
798 static void
799 gdk_win32_draw_points (GdkDrawable *drawable,
800                        GdkGC       *gc,
801                        GdkPoint    *points,
802                        gint         npoints)
803 {
804   HDC hdc;
805   COLORREF fg;
806   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
807   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
808   int i;
809
810   hdc = gdk_win32_hdc_get (drawable, gc, 0);
811   
812   fg = gdk_colormap_color (impl->colormap, gc_private->foreground);
813
814   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
815                            (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
816                            npoints, (guint) fg));
817
818   for (i = 0; i < npoints; i++)
819     SetPixel (hdc, points[i].x, points[i].y, fg);
820
821   gdk_win32_hdc_release (drawable, gc, 0);
822 }
823
824 static void
825 gdk_win32_draw_segments (GdkDrawable *drawable,
826                          GdkGC       *gc,
827                          GdkSegment  *segs,
828                          gint         nsegs)
829 {
830   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
831   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
832   HDC hdc;
833   gboolean ok = TRUE;
834   int i;
835
836   GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
837                            (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle, nsegs));
838
839   hdc = gdk_win32_hdc_get (drawable, gc, mask);
840
841   if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
842     {
843       if (!BeginPath (hdc))
844         WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
845       
846       for (i = 0; ok && i < nsegs; i++)
847         {
848           if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
849             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
850           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
851             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
852           
853           /* Draw end pixel */
854           if (ok && gc_private->pen_width <= 1)
855             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
856               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
857         }
858
859       if (ok && !EndPath (hdc))
860         WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
861           
862       if (ok && !WidenPath (hdc))
863         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
864           
865       if (ok && !FillPath (hdc))
866         WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
867     }
868   else
869     {
870       for (i = 0; ok && i < nsegs; i++)
871         {
872           if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
873             WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
874           if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
875             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
876           
877           /* Draw end pixel */
878           if (ok && gc_private->pen_width <= 1)
879             if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
880               WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
881         }
882     }
883   gdk_win32_hdc_release (drawable, gc, mask);
884 }
885
886 static void
887 gdk_win32_draw_lines (GdkDrawable *drawable,
888                       GdkGC       *gc,
889                       GdkPoint    *points,
890                       gint         npoints)
891 {
892   GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
893   const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
894   HDC hdc;
895   POINT *pts;
896   int i;
897   gboolean ok = TRUE;
898
899   if (npoints < 2)
900     return;
901
902   hdc = gdk_win32_hdc_get (drawable, gc, mask);
903
904   pts = g_new (POINT, npoints);
905
906   for (i = 0; i < npoints; i++)
907     {
908       pts[i].x = points[i].x;
909       pts[i].y = points[i].y;
910     }
911   
912   if (!Polyline (hdc, pts, npoints))
913     WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
914   
915   g_free (pts);
916   
917   /* Draw end pixel */
918   if (ok && gc_private->pen_width <= 1)
919     {
920       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
921       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
922         WIN32_GDI_FAILED ("LineTo");
923     }
924   gdk_win32_hdc_release (drawable, gc, mask);
925 }
926
927 static void
928 gdk_win32_draw_glyphs (GdkDrawable      *drawable,
929                        GdkGC            *gc,
930                        PangoFont        *font,
931                        gint              x,
932                        gint              y,
933                        PangoGlyphString *glyphs)
934 {
935   const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
936   HDC hdc;
937
938   hdc = gdk_win32_hdc_get (drawable, gc, mask);
939
940   /* HB: Maybe there should be a GDK_GC_PANGO flag for hdc_get */
941   /* default write mode is transparent (leave background) */
942   if (SetBkMode (hdc, TRANSPARENT) == 0)
943     WIN32_GDI_FAILED ("SetBkMode");
944
945   if (GDI_ERROR == SetTextAlign (hdc, TA_LEFT|TA_BASELINE|TA_NOUPDATECP))
946     WIN32_GDI_FAILED ("SetTextAlign");
947
948   pango_win32_render (hdc, font, glyphs, x, y);
949
950   gdk_win32_hdc_release (drawable, gc, mask);
951 }
952
953 static void
954 gdk_win32_draw_image (GdkDrawable     *drawable,
955                       GdkGC           *gc,
956                       GdkImage        *image,
957                       gint             xsrc,
958                       gint             ysrc,
959                       gint             xdest,
960                       gint             ydest,
961                       gint             width,
962                       gint             height)
963 {
964   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
965   GdkImagePrivateWin32 *image_private = IMAGE_PRIVATE_DATA (image);
966   GdkColormapPrivateWin32 *colormap_private = (GdkColormapPrivateWin32 *) impl->colormap;
967   HDC hdc, memdc;
968   HGDIOBJ oldbitmap;
969   DIBSECTION ds;
970   static struct {
971     BITMAPINFOHEADER bmiHeader;
972     WORD bmiIndices[256];
973   } bmi;
974   static gboolean bmi_inited = FALSE;
975   gboolean ok = TRUE;
976   int i;
977
978   hdc = gdk_win32_hdc_get (drawable, gc, 0);
979
980   if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR &&
981           colormap_private && colormap_private->xcolormap->rc_palette)
982     {
983       if (!bmi_inited)
984         {
985           for (i = 0; i < 256; i++)
986             bmi.bmiIndices[i] = i;
987           bmi_inited = TRUE;
988         }
989
990       if (GetObject (image_private->hbitmap, sizeof (DIBSECTION),
991                      &ds) != sizeof (DIBSECTION))
992         WIN32_GDI_FAILED ("GetObject"), ok = FALSE;
993 #if 0
994       g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
995               xdest, ydest, xsrc, ysrc, width, height);
996       g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
997               ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
998       g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
999               ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
1000 #endif
1001       bmi.bmiHeader = ds.dsBmih;
1002       /* I have spent hours on getting the parameters to
1003        * SetDIBitsToDevice right. I wonder what drugs the guys in
1004        * Redmond were on when they designed this API.
1005        */
1006       if (ok && SetDIBitsToDevice (hdc,
1007                                    xdest, ydest,
1008                                    width, height,
1009                                    xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
1010                                    0, -ds.dsBmih.biHeight,
1011                                    ds.dsBm.bmBits,
1012                                    (CONST BITMAPINFO *) &bmi,
1013                                    DIB_PAL_COLORS) == 0)
1014         WIN32_GDI_FAILED ("SetDIBitsToDevice");
1015     }
1016   else
1017     {
1018
1019       if ((memdc = CreateCompatibleDC (hdc)) == NULL)
1020         WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
1021
1022       if (ok && (oldbitmap = SelectObject (memdc, image_private->hbitmap)) == NULL)
1023         WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
1024
1025       if (ok && !BitBlt (hdc, xdest, ydest, width, height,
1026                          memdc, xsrc, ysrc, SRCCOPY))
1027         WIN32_GDI_FAILED ("BitBlt");
1028
1029       if (oldbitmap != NULL && SelectObject (memdc, oldbitmap) == NULL)
1030         WIN32_GDI_FAILED ("SelectObject");
1031
1032       if (memdc != NULL && !DeleteDC (memdc))
1033         WIN32_GDI_FAILED ("DeleteDC");
1034     }
1035   gdk_win32_hdc_release (drawable, gc, 0);
1036 }
1037
1038 static gint
1039 gdk_win32_get_depth (GdkDrawable *drawable)
1040 {
1041   /* This is a bit bogus but I'm not sure the other way is better */
1042
1043   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1044 }
1045
1046 static GdkVisual*
1047 gdk_win32_get_visual (GdkDrawable *drawable)
1048 {
1049   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1050 }