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