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