]> Pileus Git - ~andy/gtk/blob - gdk/gdkdraw.c
dfffb042126985781ed6a59d61fad984a91cea5e
[~andy/gtk] / gdk / gdkdraw.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 "gdkdrawable.h"
28 #include "gdkinternals.h"
29 #include "gdkwindow.h"
30 #include "gdkscreen.h"
31 #include "gdk-pixbuf-private.h"
32 #include "gdkpixbuf.h"
33
34 static GdkImage*    gdk_drawable_real_get_image (GdkDrawable     *drawable,
35                                                  gint             x,
36                                                  gint             y,
37                                                  gint             width,
38                                                  gint             height);
39 static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable  *drawable,
40                                                               gint          x,
41                                                               gint          y,
42                                                               gint          width,
43                                                               gint          height,
44                                                               gint         *composite_x_offset,
45                                                               gint         *composite_y_offset);
46 static GdkRegion *  gdk_drawable_real_get_visible_region     (GdkDrawable  *drawable);
47 static void         gdk_drawable_real_draw_pixbuf            (GdkDrawable  *drawable,
48                                                               GdkGC        *gc,
49                                                               GdkPixbuf    *pixbuf,
50                                                               gint          src_x,
51                                                               gint          src_y,
52                                                               gint          dest_x,
53                                                               gint          dest_y,
54                                                               gint          width,
55                                                               gint          height,
56                                                               GdkRgbDither  dither,
57                                                               gint          x_dither,
58                                                               gint          y_dither);
59
60 static void gdk_drawable_class_init (GdkDrawableClass *klass);
61
62 GType
63 gdk_drawable_get_type (void)
64 {
65   static GType object_type = 0;
66
67   if (!object_type)
68     {
69       static const GTypeInfo object_info =
70       {
71         sizeof (GdkDrawableClass),
72         (GBaseInitFunc) NULL,
73         (GBaseFinalizeFunc) NULL,
74         (GClassInitFunc) gdk_drawable_class_init,
75         NULL,           /* class_finalize */
76         NULL,           /* class_data */
77         sizeof (GdkDrawable),
78         0,              /* n_preallocs */
79         (GInstanceInitFunc) NULL,
80       };
81       
82       object_type = g_type_register_static (G_TYPE_OBJECT,
83                                             "GdkDrawable",
84                                             &object_info, 
85                                             G_TYPE_FLAG_ABSTRACT);
86     }  
87
88   return object_type;
89 }
90
91 static void
92 gdk_drawable_class_init (GdkDrawableClass *klass)
93 {
94   klass->get_image = gdk_drawable_real_get_image;
95   klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
96   /* Default implementation for clip and visible region is the same */
97   klass->get_clip_region = gdk_drawable_real_get_visible_region;
98   klass->get_visible_region = gdk_drawable_real_get_visible_region;
99   klass->draw_pixbuf = gdk_drawable_real_draw_pixbuf;
100 }
101
102 /* Manipulation of drawables
103  */
104
105 /**
106  * gdk_drawable_set_data:
107  * @drawable: a #GdkDrawable
108  * @key: name to store the data under
109  * @data: arbitrary data
110  * @destroy_func: function to free @data, or %NULL
111  *
112  * This function is equivalent to g_object_set_data(),
113  * the #GObject variant should be used instead.
114  * 
115  **/
116 void          
117 gdk_drawable_set_data (GdkDrawable   *drawable,
118                        const gchar   *key,
119                        gpointer       data,
120                        GDestroyNotify destroy_func)
121 {
122   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
123   
124   g_object_set_qdata_full (G_OBJECT (drawable),
125                            g_quark_from_string (key),
126                            data,
127                            destroy_func);
128 }
129
130 /**
131  * gdk_drawable_get_data:
132  * @drawable: a #GdkDrawable
133  * @key: name the data was stored under
134  * 
135  * Equivalent to g_object_get_data(); the #GObject variant should be
136  * used instead.
137  * 
138  * Return value: the data stored at @key
139  **/
140 gpointer
141 gdk_drawable_get_data (GdkDrawable   *drawable,
142                        const gchar   *key)
143 {
144   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
145   
146   return g_object_get_qdata (G_OBJECT (drawable),
147                              g_quark_try_string (key));
148 }
149
150 /**
151  * gdk_drawable_get_size:
152  * @drawable: a #GdkDrawable
153  * @width: location to store drawable's width, or %NULL
154  * @height: location to store drawable's height, or %NULL
155  *
156  * Fills *@width and *@height with the size of @drawable.
157  * @width or @height can be %NULL if you only want the other one.
158  * 
159  * On the X11 platform, if @drawable is a #GdkWindow, the returned
160  * size is the size reported in the most-recently-processed configure
161  * event, rather than the current size on the X server.
162  * 
163  **/
164 void
165 gdk_drawable_get_size (GdkDrawable *drawable,
166                        gint        *width,
167                        gint        *height)
168 {
169   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
170
171   GDK_DRAWABLE_GET_CLASS (drawable)->get_size (drawable, width, height);  
172 }
173
174 /**
175  * gdk_drawable_get_visual:
176  * @drawable: a #GdkDrawable
177  * 
178  * Gets the #GdkVisual describing the pixel format of @drawable.
179  * 
180  * Return value: a #GdkVisual
181  **/
182 GdkVisual*
183 gdk_drawable_get_visual (GdkDrawable *drawable)
184 {
185   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
186   
187   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visual (drawable);
188 }
189
190 /**
191  * gdk_drawable_get_depth:
192  * @drawable: a #GdkDrawable
193  * 
194  * Obtains the bit depth of the drawable, that is, the number of bits
195  * that make up a pixel in the drawable's visual. Examples are 8 bits
196  * per pixel, 24 bits per pixel, etc.
197  * 
198  * Return value: number of bits per pixel
199  **/
200 gint
201 gdk_drawable_get_depth (GdkDrawable *drawable)
202 {
203   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), 0);
204
205   return GDK_DRAWABLE_GET_CLASS (drawable)->get_depth (drawable);
206 }
207 /**
208  * gdk_drawable_get_screen:
209  * @drawable: a #GdkDrawable
210  * 
211  * Gets the #GdkScreen associated with a #GdkDrawable.
212  * 
213  * Return value: the #GdkScreen associated with @drawable
214  **/
215 GdkScreen*
216 gdk_drawable_get_screen(GdkDrawable *drawable)
217 {
218   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
219
220   return GDK_DRAWABLE_GET_CLASS (drawable)->get_screen (drawable);
221 }
222
223 /**
224  * gdk_drawable_get_display:
225  * @drawable: a #GdkDrawable
226  * 
227  * Gets the #GdkDisplay associated with a #GdkDrawable.
228  * 
229  * Return value: the #GdkDisplay associated with @drawable
230  **/
231 GdkDisplay*
232 gdk_drawable_get_display (GdkDrawable *drawable)
233 {
234   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
235   
236   return gdk_screen_get_display (gdk_drawable_get_screen (drawable));
237 }
238         
239 /**
240  * gdk_drawable_set_colormap:
241  * @drawable: a #GdkDrawable
242  * @colormap: a #GdkColormap
243  *
244  * Sets the colormap associated with @drawable. Normally this will
245  * happen automatically when the drawable is created; you only need to
246  * use this function if the drawable-creating function did not have a
247  * way to determine the colormap, and you then use drawable operations
248  * that require a colormap. The colormap for all drawables and
249  * graphics contexts you intend to use together should match. i.e.
250  * when using a #GdkGC to draw to a drawable, or copying one drawable
251  * to another, the colormaps should match.
252  * 
253  **/
254 void
255 gdk_drawable_set_colormap (GdkDrawable *drawable,
256                            GdkColormap *cmap)
257 {
258   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
259   g_return_if_fail (cmap == NULL || gdk_drawable_get_depth (drawable)
260                     == cmap->visual->depth);
261
262   GDK_DRAWABLE_GET_CLASS (drawable)->set_colormap (drawable, cmap);
263 }
264
265 /**
266  * gdk_drawable_get_colormap:
267  * @drawable: a #GdkDrawable
268  * 
269  * Gets the colormap for @drawable, if one is set; returns
270  * %NULL otherwise.
271  * 
272  * Return value: the colormap, or %NULL
273  **/
274 GdkColormap*
275 gdk_drawable_get_colormap (GdkDrawable *drawable)
276 {
277   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
278
279   return GDK_DRAWABLE_GET_CLASS (drawable)->get_colormap (drawable);
280 }
281
282 /**
283  * gdk_drawable_ref:
284  * @drawable: a #GdkDrawable
285  * 
286  * Deprecated equivalent of calling g_object_ref() on @drawable.
287  * (Drawables were not objects in previous versions of GDK.)
288  * 
289  * Return value: the same @drawable passed in
290  **/
291 GdkDrawable*
292 gdk_drawable_ref (GdkDrawable *drawable)
293 {
294   return (GdkDrawable *) g_object_ref (drawable);
295 }
296
297 /**
298  * gdk_drawable_unref:
299  * @drawable: a #GdkDrawable
300  * 
301  * Deprecated equivalent of calling g_object_unref() on @drawable.
302  * 
303  **/
304 void
305 gdk_drawable_unref (GdkDrawable *drawable)
306 {
307   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
308
309   g_object_unref (drawable);
310 }
311
312 /* Drawing
313  */
314
315 /**
316  * gdk_draw_point:
317  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
318  * @gc: a #GdkGC.
319  * @x: the x coordinate of the point.
320  * @y: the y coordinate of the point.
321  * 
322  * Draws a point, using the foreground color and other attributes of 
323  * the #GdkGC.
324  **/
325 void
326 gdk_draw_point (GdkDrawable *drawable,
327                 GdkGC       *gc,
328                 gint         x,
329                 gint         y)
330 {
331   GdkPoint point;
332
333   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
334   g_return_if_fail (GDK_IS_GC (gc));
335
336   point.x = x;
337   point.y = y;
338   
339   GDK_DRAWABLE_GET_CLASS (drawable)->draw_points (drawable, gc, &point, 1);
340 }
341
342 /**
343  * gdk_draw_line:
344  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap). 
345  * @gc: a #GdkGC.
346  * @x1_: the x coordinate of the start point.
347  * @y1_: the y coordinate of the start point.
348  * @x2_: the x coordinate of the end point.
349  * @y2_: the y coordinate of the end point.
350  * 
351  * Draws a line, using the foreground color and other attributes of 
352  * the #GdkGC.
353  **/
354 void
355 gdk_draw_line (GdkDrawable *drawable,
356                GdkGC       *gc,
357                gint         x1,
358                gint         y1,
359                gint         x2,
360                gint         y2)
361 {
362   GdkSegment segment;
363
364   g_return_if_fail (drawable != NULL);
365   g_return_if_fail (gc != NULL);
366   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
367   g_return_if_fail (GDK_IS_GC (gc));
368
369   segment.x1 = x1;
370   segment.y1 = y1;
371   segment.x2 = x2;
372   segment.y2 = y2;
373   GDK_DRAWABLE_GET_CLASS (drawable)->draw_segments (drawable, gc, &segment, 1);
374 }
375
376 /**
377  * gdk_draw_rectangle:
378  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
379  * @gc: a #GdkGC.
380  * @filled: %TRUE if the rectangle should be filled.
381  * @x: the x coordinate of the left edge of the rectangle.
382  * @y: the y coordinate of the top edge of the rectangle.
383  * @width: the width of the rectangle.
384  * @height: the height of the rectangle.
385  * 
386  * Draws a rectangular outline or filled rectangle, using the foreground color
387  * and other attributes of the #GdkGC.
388  *
389  * A rectangle drawn filled is 1 pixel smaller in both dimensions than a 
390  * rectangle outlined. Calling 
391  * <literal>gdk_draw_rectangle (window, gc, TRUE, 0, 0, 20, 20)</literal> 
392  * results in a filled rectangle 20 pixels wide and 20 pixels high. Calling
393  * <literal>gdk_draw_rectangle (window, gc, FALSE, 0, 0, 20, 20)</literal> 
394  * results in an outlined rectangle with corners at (0, 0), (0, 20), (20, 20),
395  * and (20, 0), which makes it 21 pixels wide and 21 pixels high.
396  **/
397 void
398 gdk_draw_rectangle (GdkDrawable *drawable,
399                     GdkGC       *gc,
400                     gboolean     filled,
401                     gint         x,
402                     gint         y,
403                     gint         width,
404                     gint         height)
405 {  
406   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
407   g_return_if_fail (GDK_IS_GC (gc));
408
409   if (width < 0 || height < 0)
410     {
411       gint real_width;
412       gint real_height;
413       
414       gdk_drawable_get_size (drawable, &real_width, &real_height);
415
416       if (width < 0)
417         width = real_width;
418       if (height < 0)
419         height = real_height;
420     }
421
422   GDK_DRAWABLE_GET_CLASS (drawable)->draw_rectangle (drawable, gc, filled, x, y,
423                                                      width, height);
424 }
425
426 /**
427  * gdk_draw_arc:
428  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
429  * @gc: a #GdkGC.
430  * @filled: %TRUE if the arc should be filled, producing a 'pie slice'.
431  * @x: the x coordinate of the left edge of the bounding rectangle.
432  * @y: the y coordinate of the top edge of the bounding rectangle.
433  * @width: the width of the bounding rectangle.
434  * @height: the height of the bounding rectangle.
435  * @angle1: the start angle of the arc, relative to the 3 o'clock position,
436  *     counter-clockwise, in 1/64ths of a degree.
437  * @angle2: the end angle of the arc, relative to @angle1, in 1/64ths 
438  *     of a degree.
439  * 
440  * Draws an arc or a filled 'pie slice'. The arc is defined by the bounding
441  * rectangle of the entire ellipse, and the start and end angles of the part 
442  * of the ellipse to be drawn.
443  **/
444 void
445 gdk_draw_arc (GdkDrawable *drawable,
446               GdkGC       *gc,
447               gboolean     filled,
448               gint         x,
449               gint         y,
450               gint         width,
451               gint         height,
452               gint         angle1,
453               gint         angle2)
454 {  
455   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
456   g_return_if_fail (GDK_IS_GC (gc));
457
458   if (width < 0 || height < 0)
459     {
460       gint real_width;
461       gint real_height;
462       
463       gdk_drawable_get_size (drawable, &real_width, &real_height);
464
465       if (width < 0)
466         width = real_width;
467       if (height < 0)
468         height = real_height;
469     }
470
471   GDK_DRAWABLE_GET_CLASS (drawable)->draw_arc (drawable, gc, filled,
472                                                x, y, width, height, angle1, angle2);
473 }
474
475 /**
476  * gdk_draw_polygon:
477  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
478  * @gc: a #GdkGC.
479  * @filled: %TRUE if the polygon should be filled. The polygon is closed
480  *     automatically, connecting the last point to the first point if 
481  *     necessary.
482  * @points: an array of #GdkPoint structures specifying the points making 
483  *     up the polygon.
484  * @npoints: the number of points.
485  * 
486  * Draws an outlined or filled polygon.
487  **/
488 void
489 gdk_draw_polygon (GdkDrawable *drawable,
490                   GdkGC       *gc,
491                   gboolean     filled,
492                   GdkPoint    *points,
493                   gint         npoints)
494 {
495   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
496   g_return_if_fail (GDK_IS_GC (gc));
497
498   GDK_DRAWABLE_GET_CLASS (drawable)->draw_polygon (drawable, gc, filled,
499                                                    points, npoints);
500 }
501
502 /* gdk_draw_string
503  *
504  * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
505  *
506  * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
507  */
508 /**
509  * gdk_draw_string:
510  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
511  * @font: a #GdkFont.
512  * @gc: a #GdkGC.
513  * @x: the x coordinate of the left edge of the text.
514  * @y: the y coordinate of the baseline of the text.
515  * @string:  the string of characters to draw.
516  * 
517  * Draws a string of characters in the given font or fontset.
518  **/
519 void
520 gdk_draw_string (GdkDrawable *drawable,
521                  GdkFont     *font,
522                  GdkGC       *gc,
523                  gint         x,
524                  gint         y,
525                  const gchar *string)
526 {
527   gdk_draw_text (drawable, font, gc, x, y, string, _gdk_font_strlen (font, string));
528 }
529
530 /* gdk_draw_text
531  *
532  * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
533  *
534  * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
535  */
536 /**
537  * gdk_draw_text:
538  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
539  * @font: a #GdkFont.
540  * @gc: a #GdkGC.
541  * @x: the x coordinate of the left edge of the text.
542  * @y: the y coordinate of the baseline of the text.
543  * @text:  the characters to draw.
544  * @text_length: the number of characters of @text to draw.
545  * 
546  * Draws a number of characters in the given font or fontset.
547  **/
548 void
549 gdk_draw_text (GdkDrawable *drawable,
550                GdkFont     *font,
551                GdkGC       *gc,
552                gint         x,
553                gint         y,
554                const gchar *text,
555                gint         text_length)
556 {
557   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
558   g_return_if_fail (font != NULL);
559   g_return_if_fail (GDK_IS_GC (gc));
560   g_return_if_fail (text != NULL);
561
562   GDK_DRAWABLE_GET_CLASS (drawable)->draw_text (drawable, font, gc, x, y, text, text_length);
563 }
564
565 /**
566  * gdk_draw_text_wc:
567  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
568  * @font: a #GdkFont.
569  * @gc: a #GdkGC.
570  * @x: the x coordinate of the left edge of the text.
571  * @y: the y coordinate of the baseline of the text.
572  * @text: the wide characters to draw.
573  * @text_length: the number of characters to draw.
574  * 
575  * Draws a number of wide characters using the given font of fontset.
576  * If the font is a 1-byte font, the string is converted into 1-byte 
577  * characters (discarding the high bytes) before output.
578  **/
579 void
580 gdk_draw_text_wc (GdkDrawable    *drawable,
581                   GdkFont        *font,
582                   GdkGC          *gc,
583                   gint            x,
584                   gint            y,
585                   const GdkWChar *text,
586                   gint            text_length)
587 {
588   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
589   g_return_if_fail (font != NULL);
590   g_return_if_fail (GDK_IS_GC (gc));
591   g_return_if_fail (text != NULL);
592
593   GDK_DRAWABLE_GET_CLASS (drawable)->draw_text_wc (drawable, font, gc, x, y, text, text_length);
594 }
595
596 /**
597  * gdk_draw_drawable:
598  * @drawable: a #GdkDrawable
599  * @gc: a #GdkGC sharing the drawable's visual and colormap
600  * @src: another #GdkDrawable
601  * @xsrc: X position in @src of rectangle to draw
602  * @ysrc: Y position in @src of rectangle to draw
603  * @xdest: X position in @drawable where the rectangle should be drawn
604  * @ydest: Y position in @drawable where the rectangle should be drawn
605  * @width: width of rectangle to draw, or -1 for entire @src width
606  * @height: height of rectangle to draw, or -1 for entire @src height
607  *
608  * Copies the @width x @height region of @src at coordinates (@xsrc,
609  * @ysrc) to coordinates (@xdest, @ydest) in @drawable.
610  * @width and/or @height may be given as -1, in which case the entire
611  * @src drawable will be copied.
612  *
613  * Most fields in @gc are not used for this operation, but notably the
614  * clip mask or clip region will be honored.
615  *
616  * The source and destination drawables must have the same visual and
617  * colormap, or errors will result. (On X11, failure to match
618  * visual/colormap results in a BadMatch error from the X server.)
619  * A common cause of this problem is an attempt to draw a bitmap to
620  * a color drawable. The way to draw a bitmap is to set the
621  * bitmap as a clip mask on your #GdkGC, then use gdk_draw_rectangle()
622  * to draw a rectangle clipped to the bitmap.
623  **/
624 void
625 gdk_draw_drawable (GdkDrawable *drawable,
626                    GdkGC       *gc,
627                    GdkDrawable *src,
628                    gint         xsrc,
629                    gint         ysrc,
630                    gint         xdest,
631                    gint         ydest,
632                    gint         width,
633                    gint         height)
634 {
635   GdkDrawable *composite;
636   gint composite_x_offset = 0;
637   gint composite_y_offset = 0;
638
639   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
640   g_return_if_fail (src != NULL);
641   g_return_if_fail (GDK_IS_GC (gc));
642
643   if (width < 0 || height < 0)
644     {
645       gint real_width;
646       gint real_height;
647       
648       gdk_drawable_get_size (src, &real_width, &real_height);
649
650       if (width < 0)
651         width = real_width;
652       if (height < 0)
653         height = real_height;
654     }
655
656
657   composite =
658     GDK_DRAWABLE_GET_CLASS (src)->get_composite_drawable (src,
659                                                           xsrc, ysrc,
660                                                           width, height,
661                                                           &composite_x_offset,
662                                                           &composite_y_offset);
663
664   
665   GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc, composite,
666                                                     xsrc - composite_x_offset,
667                                                     ysrc - composite_y_offset,
668                                                     xdest, ydest,
669                                                     width, height);
670   
671   g_object_unref (composite);
672 }
673
674 /**
675  * gdk_draw_image:
676  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
677  * @gc: a #GdkGC.
678  * @image: the #GdkImage to draw.
679  * @xsrc: the left edge of the source rectangle within @image.
680  * @ysrc: the top of the source rectangle within @image.
681  * @xdest: the x coordinate of the destination within @drawable.
682  * @ydest: the y coordinate of the destination within @drawable.
683  * @width: the width of the area to be copied, or -1 to make the area 
684  *     extend to the right edge of @image.
685  * @height: the height of the area to be copied, or -1 to make the area 
686  *     extend to the bottom edge of @image.
687  * 
688  * Draws a #GdkImage onto a drawable.
689  * The depth of the #GdkImage must match the depth of the #GdkDrawable.
690  **/
691 void
692 gdk_draw_image (GdkDrawable *drawable,
693                 GdkGC       *gc,
694                 GdkImage    *image,
695                 gint         xsrc,
696                 gint         ysrc,
697                 gint         xdest,
698                 gint         ydest,
699                 gint         width,
700                 gint         height)
701 {
702   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
703   g_return_if_fail (image != NULL);
704   g_return_if_fail (GDK_IS_GC (gc));
705
706   if (width == -1)
707     width = image->width;
708   if (height == -1)
709     height = image->height;
710
711   GDK_DRAWABLE_GET_CLASS (drawable)->draw_image (drawable, gc, image, xsrc, ysrc,
712                                                  xdest, ydest, width, height);
713 }
714
715 /**
716  * gdk_draw_pixbuf:
717  * @drawable: Destination drawable.
718  * @gc: a #GdkGC, used for clipping, or %NULL
719  * @pixbuf: a #GdkPixbuf
720  * @src_x: Source X coordinate within pixbuf.
721  * @src_y: Source Y coordinates within pixbuf.
722  * @dest_x: Destination X coordinate within drawable.
723  * @dest_y: Destination Y coordinate within drawable.
724  * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
725  * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
726  * @dither: Dithering mode for GdkRGB.
727  * @x_dither: X offset for dither.
728  * @y_dither: Y offset for dither.
729  * 
730  * Renders a rectangular portion of a pixbuf to a drawable.  The destination
731  * drawable must have a colormap. All windows have a colormap, however, pixmaps
732  * only have colormap by default if they were created with a non-NULL window argument.
733  * Otherwise a colormap must be set on them with gdk_drawable_set_colormap.
734  *
735  * On older X servers, rendering pixbufs with an alpha channel involves round trips
736  * to the X server, and may be somewhat slow.
737  **/
738 void
739 gdk_draw_pixbuf (GdkDrawable     *drawable,
740                   GdkGC           *gc,
741                   GdkPixbuf       *pixbuf,
742                   gint             src_x,
743                   gint             src_y,
744                   gint             dest_x,
745                   gint             dest_y,
746                   gint             width,
747                   gint             height,
748                   GdkRgbDither     dither,
749                   gint             x_dither,
750                   gint             y_dither)
751 {
752   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
753   g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
754   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
755
756   if (width == -1)
757     width = gdk_pixbuf_get_width (pixbuf);
758   if (height == -1)
759     height = gdk_pixbuf_get_height (pixbuf);
760
761   GDK_DRAWABLE_GET_CLASS (drawable)->draw_pixbuf (drawable, gc, pixbuf,
762                                                   src_x, src_y, dest_x, dest_y, width, height,
763                                                   dither, x_dither, y_dither);
764 }
765
766 /**
767  * gdk_draw_points:
768  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
769  * @gc: a #GdkGC.
770  * @points: an array of #GdkPoint structures.
771  * @npoints: the number of points to be drawn.
772  * 
773  * Draws a number of points, using the foreground color and other 
774  * attributes of the #GdkGC.
775  **/
776 void
777 gdk_draw_points (GdkDrawable *drawable,
778                  GdkGC       *gc,
779                  GdkPoint    *points,
780                  gint         npoints)
781 {
782   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
783   g_return_if_fail ((points != NULL) && (npoints > 0));
784   g_return_if_fail (GDK_IS_GC (gc));
785   g_return_if_fail (npoints >= 0);
786
787   if (npoints == 0)
788     return;
789
790   GDK_DRAWABLE_GET_CLASS (drawable)->draw_points (drawable, gc, points, npoints);
791 }
792
793 /**
794  * gdk_draw_segments:
795  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
796  * @gc: a #GdkGC.
797  * @segs: an array of #GdkSegment structures specifying the start and 
798  *   end points of the lines to be drawn.
799  * @nsegs: the number of line segments to draw, i.e. the size of the 
800  *   @segs array.
801  * 
802  * Draws a number of unconnected lines.
803  **/
804 void
805 gdk_draw_segments (GdkDrawable *drawable,
806                    GdkGC       *gc,
807                    GdkSegment  *segs,
808                    gint         nsegs)
809 {
810   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
811
812   if (nsegs == 0)
813     return;
814
815   g_return_if_fail (segs != NULL);
816   g_return_if_fail (GDK_IS_GC (gc));
817   g_return_if_fail (nsegs >= 0);
818
819   GDK_DRAWABLE_GET_CLASS (drawable)->draw_segments (drawable, gc, segs, nsegs);
820 }
821
822 /**
823  * gdk_draw_lines:
824  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
825  * @gc: a #GdkGC.
826  * @points: an array of #GdkPoint structures specifying the endpoints of the
827  * @npoints: the size of the @points array.
828  * 
829  * Draws a series of lines connecting the given points.
830  * The way in which joins between lines are draw is determined by the
831  * #GdkCapStyle value in the #GdkGC. This can be set with
832  * gdk_gc_set_line_attributes().
833  **/
834 void
835 gdk_draw_lines (GdkDrawable *drawable,
836                 GdkGC       *gc,
837                 GdkPoint    *points,
838                 gint         npoints)
839 {
840   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
841   g_return_if_fail (points != NULL);
842   g_return_if_fail (GDK_IS_GC (gc));
843   g_return_if_fail (npoints >= 0);
844
845   if (npoints == 0)
846     return;
847
848   GDK_DRAWABLE_GET_CLASS (drawable)->draw_lines (drawable, gc, points, npoints);
849 }
850
851 /**
852  * gdk_draw_glyphs:
853  * @drawable: a #GdkDrawable
854  * @gc: a #GdkGC
855  * @font: font to be used
856  * @x: X coordinate of baseline origin
857  * @y: Y coordinate of baseline origin
858  * @glyphs: glyphs to render
859  *
860  * This is a low-level function; 99% of text rendering should be done
861  * using gdk_draw_layout() instead.
862  *
863  * A glyph is a character in a font. This function draws a sequence of
864  * glyphs.  To obtain a sequence of glyphs you have to understand a
865  * lot about internationalized text handling, which you don't want to
866  * understand; thus, use gdk_draw_layout() instead of this function,
867  * gdk_draw_layout() handles the details.
868  * 
869  **/
870 void
871 gdk_draw_glyphs (GdkDrawable      *drawable,
872                  GdkGC            *gc,
873                  PangoFont        *font,
874                  gint              x,
875                  gint              y,
876                  PangoGlyphString *glyphs)
877 {
878   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
879   g_return_if_fail (GDK_IS_GC (gc));
880
881
882   GDK_DRAWABLE_GET_CLASS (drawable)->draw_glyphs (drawable, gc, font, x, y, glyphs);
883 }
884
885
886 /**
887  * _gdk_drawable_copy_to_image:
888  * @drawable: a #GdkDrawable
889  * @image: a #GdkDrawable, or %NULL if a new @image should be created.
890  * @src_x: x coordinate on @drawable
891  * @src_y: y coordinate on @drawable
892  * @dest_x: x coordinate within @image. Must be 0 if @image is %NULL
893  * @dest_y: y coordinate within @image. Must be 0 if @image is %NULL
894  * @width: width of region to get
895  * @height: height or region to get
896  *
897  * Copies a portion of @drawable into the client side image structure
898  * @image. If @image is %NULL, creates a new image of size @width x @height
899  * and copies into that. See gdk_drawable_get_image() for further details.
900  * 
901  * Return value: @image, or a new a #GdkImage containing the contents
902                  of @drawable
903  **/
904 GdkImage*
905 _gdk_drawable_copy_to_image (GdkDrawable *drawable,
906                              GdkImage    *image,
907                              gint         src_x,
908                              gint         src_y,
909                              gint         dest_x,
910                              gint         dest_y,
911                              gint         width,
912                              gint         height)
913 {
914   GdkDrawable *composite;
915   gint composite_x_offset = 0;
916   gint composite_y_offset = 0;
917   GdkImage *retval;
918   GdkColormap *cmap;
919   
920   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
921   g_return_val_if_fail (src_x >= 0, NULL);
922   g_return_val_if_fail (src_y >= 0, NULL);
923
924   /* FIXME? Note race condition since we get the size then
925    * get the image, and the size may have changed.
926    */
927   
928   if (width < 0 || height < 0)
929     gdk_drawable_get_size (drawable,
930                            width < 0 ? &width : NULL,
931                            height < 0 ? &height : NULL);
932   
933   composite =
934     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
935                                                                src_x, src_y,
936                                                                width, height,
937                                                                &composite_x_offset,
938                                                                &composite_y_offset); 
939   
940   retval = GDK_DRAWABLE_GET_CLASS (composite)->_copy_to_image (composite,
941                                                                image,
942                                                                src_x - composite_x_offset,
943                                                                src_y - composite_y_offset,
944                                                                dest_x, dest_y,
945                                                                width, height);
946
947   g_object_unref (composite);
948
949   if (!image && retval)
950     {
951       cmap = gdk_drawable_get_colormap (drawable);
952       
953       if (cmap)
954         gdk_image_set_colormap (retval, cmap);
955     }
956   
957   return retval;
958 }
959
960 /**
961  * gdk_drawable_get_image:
962  * @drawable: a #GdkDrawable
963  * @x: x coordinate on @drawable
964  * @y: y coordinate on @drawable
965  * @width: width of region to get
966  * @height: height or region to get
967  * 
968  * A #GdkImage stores client-side image data (pixels). In contrast,
969  * #GdkPixmap and #GdkWindow are server-side
970  * objects. gdk_drawable_get_image() obtains the pixels from a
971  * server-side drawable as a client-side #GdkImage.  The format of a
972  * #GdkImage depends on the #GdkVisual of the current display, which
973  * makes manipulating #GdkImage extremely difficult; therefore, in
974  * most cases you should use gdk_pixbuf_get_from_drawable() instead of
975  * this lower-level function. A #GdkPixbuf contains image data in a
976  * canonicalized RGB format, rather than a display-dependent format.
977  * Of course, there's a convenience vs. speed tradeoff here, so you'll
978  * want to think about what makes sense for your application.
979  *
980  * @x, @y, @width, and @height define the region of @drawable to
981  * obtain as an image.
982  *
983  * You would usually copy image data to the client side if you intend
984  * to examine the values of individual pixels, for example to darken
985  * an image or add a red tint. It would be prohibitively slow to
986  * make a round-trip request to the windowing system for each pixel,
987  * so instead you get all of them at once, modify them, then copy
988  * them all back at once.
989  *
990  * If the X server or other windowing system backend is on the local
991  * machine, this function may use shared memory to avoid copying
992  * the image data.
993  *
994  * If the source drawable is a #GdkWindow and partially offscreen
995  * or obscured, then the obscured portions of the returned image
996  * will contain undefined data.
997  * 
998  * Return value: a #GdkImage containing the contents of @drawable
999  **/
1000 GdkImage*
1001 gdk_drawable_get_image (GdkDrawable *drawable,
1002                         gint         x,
1003                         gint         y,
1004                         gint         width,
1005                         gint         height)
1006 {
1007   GdkDrawable *composite;
1008   gint composite_x_offset = 0;
1009   gint composite_y_offset = 0;
1010   GdkImage *retval;
1011   GdkColormap *cmap;
1012   
1013   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1014   g_return_val_if_fail (x >= 0, NULL);
1015   g_return_val_if_fail (y >= 0, NULL);
1016
1017   /* FIXME? Note race condition since we get the size then
1018    * get the image, and the size may have changed.
1019    */
1020   
1021   if (width < 0 || height < 0)
1022     gdk_drawable_get_size (drawable,
1023                            width < 0 ? &width : NULL,
1024                            height < 0 ? &height : NULL);
1025   
1026   composite =
1027     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
1028                                                                x, y,
1029                                                                width, height,
1030                                                                &composite_x_offset,
1031                                                                &composite_y_offset); 
1032   
1033   retval = GDK_DRAWABLE_GET_CLASS (composite)->get_image (composite,
1034                                                           x - composite_x_offset,
1035                                                           y - composite_y_offset,
1036                                                           width, height);
1037
1038   g_object_unref (composite);
1039
1040   cmap = gdk_drawable_get_colormap (drawable);
1041   
1042   if (retval && cmap)
1043     gdk_image_set_colormap (retval, cmap);
1044   
1045   return retval;
1046 }
1047
1048 static GdkImage*
1049 gdk_drawable_real_get_image (GdkDrawable     *drawable,
1050                              gint             x,
1051                              gint             y,
1052                              gint             width,
1053                              gint             height)
1054 {
1055   return _gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
1056 }
1057
1058 static GdkDrawable*
1059 gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
1060                                           gint         x,
1061                                           gint         y,
1062                                           gint         width,
1063                                           gint         height,
1064                                           gint        *composite_x_offset,
1065                                           gint        *composite_y_offset)
1066 {
1067   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1068
1069   *composite_x_offset = 0;
1070   *composite_y_offset = 0;
1071   
1072   return g_object_ref (drawable);
1073 }
1074
1075 /**
1076  * gdk_drawable_get_clip_region:
1077  * @drawable: a #GdkDrawable
1078  * 
1079  * Computes the region of a drawable that potentially can be written
1080  * to by drawing primitives. This region will not take into account
1081  * the clip region for the GC, and may also not take into account
1082  * other factors such as if the window is obscured by other windows,
1083  * but no area outside of this region will be affected by drawing
1084  * primitives.
1085  * 
1086  * Return value: a #GdkRegion. This must be freed with gdk_region_destroy()
1087  *               when you are done.
1088  **/
1089 GdkRegion *
1090 gdk_drawable_get_clip_region (GdkDrawable *drawable)
1091 {
1092   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1093
1094   return GDK_DRAWABLE_GET_CLASS (drawable)->get_clip_region (drawable);
1095 }
1096
1097 /**
1098  * gdk_drawable_get_visible_region:
1099  * @drawable: 
1100  * 
1101  * Computes the region of a drawable that is potentially visible.
1102  * This does not necessarily take into account if the window is
1103  * obscured by other windows, but no area outside of this region
1104  * is visible.
1105  * 
1106  * Return value: a #GdkRegion. This must be freed with gdk_region_destroy()
1107  *               when you are done.
1108  **/
1109 GdkRegion *
1110 gdk_drawable_get_visible_region (GdkDrawable *drawable)
1111 {
1112   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1113
1114   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visible_region (drawable);
1115 }
1116
1117 static GdkRegion *
1118 gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
1119 {
1120   GdkRectangle rect;
1121
1122   rect.x = 0;
1123   rect.y = 0;
1124
1125   gdk_drawable_get_size (drawable, &rect.width, &rect.height);
1126
1127   return gdk_region_rectangle (&rect);
1128 }
1129
1130 static void
1131 composite (guchar *src_buf,
1132            gint    src_rowstride,
1133            guchar *dest_buf,
1134            gint    dest_rowstride,
1135            gint    width,
1136            gint    height)
1137 {
1138   guchar *src = src_buf;
1139   guchar *dest = dest_buf;
1140
1141   while (height--)
1142     {
1143       gint twidth = width;
1144       guchar *p = src;
1145       guchar *q = dest;
1146
1147       while (twidth--)
1148         {
1149           guchar a = p[3];
1150           guint t;
1151
1152           t = a * p[0] + (255 - a) * q[0] + 0x80;
1153           q[0] = (t + (t >> 8)) >> 8;
1154           t = a * p[1] + (255 - a) * q[1] + 0x80;
1155           q[1] = (t + (t >> 8)) >> 8;
1156           t = a * p[2] + (255 - a) * q[2] + 0x80;
1157           q[2] = (t + (t >> 8)) >> 8;
1158
1159           p += 4;
1160           q += 3;
1161         }
1162       
1163       src += src_rowstride;
1164       dest += dest_rowstride;
1165     }
1166 }
1167
1168 static void
1169 composite_0888 (guchar      *src_buf,
1170                 gint         src_rowstride,
1171                 guchar      *dest_buf,
1172                 gint         dest_rowstride,
1173                 GdkByteOrder dest_byte_order,
1174                 gint         width,
1175                 gint         height)
1176 {
1177   guchar *src = src_buf;
1178   guchar *dest = dest_buf;
1179
1180   while (height--)
1181     {
1182       gint twidth = width;
1183       guchar *p = src;
1184       guchar *q = dest;
1185
1186       if (dest_byte_order == GDK_LSB_FIRST)
1187         {
1188           while (twidth--)
1189             {
1190               guint t;
1191               
1192               t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80;
1193               q[0] = (t + (t >> 8)) >> 8;
1194               t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80;
1195               q[1] = (t + (t >> 8)) >> 8;
1196               t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80;
1197               q[2] = (t + (t >> 8)) >> 8;
1198               p += 4;
1199               q += 4;
1200             }
1201         }
1202       else
1203         {
1204           while (twidth--)
1205             {
1206               guint t;
1207               
1208               t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80;
1209               q[1] = (t + (t >> 8)) >> 8;
1210               t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80;
1211               q[2] = (t + (t >> 8)) >> 8;
1212               t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80;
1213               q[3] = (t + (t >> 8)) >> 8;
1214               p += 4;
1215               q += 4;
1216             }
1217         }
1218       
1219       src += src_rowstride;
1220       dest += dest_rowstride;
1221     }
1222 }
1223
1224 static void
1225 composite_565 (guchar      *src_buf,
1226                gint         src_rowstride,
1227                guchar      *dest_buf,
1228                gint         dest_rowstride,
1229                GdkByteOrder dest_byte_order,
1230                gint         width,
1231                gint         height)
1232 {
1233   guchar *src = src_buf;
1234   guchar *dest = dest_buf;
1235
1236   while (height--)
1237     {
1238       gint twidth = width;
1239       guchar *p = src;
1240       gushort *q = (gushort *)dest;
1241
1242       while (twidth--)
1243         {
1244           guchar a = p[3];
1245           guint tr, tg, tb;
1246           guint tr1, tg1, tb1;
1247           guint tmp = *q;
1248
1249 #if 1
1250           /* This is fast, and corresponds to what composite() above does
1251            * if we converted to 8-bit first.
1252            */
1253           tr = (tmp & 0xf800);
1254           tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1255           tg = (tmp & 0x07e0);
1256           tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1257           tb = (tmp & 0x001f);
1258           tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1259
1260           *q = (((tr1 + (tr1 >> 8)) & 0xf800) |
1261                 (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5)  |
1262                 ((tb1 + (tb1 >> 8)) >> 11));
1263 #else
1264           /* This version correspond to the result we get with XRENDER -
1265            * a bit of precision is lost since we convert to 8 bit after premultiplying
1266            * instead of at the end
1267            */
1268           guint tr2, tg2, tb2;
1269           guint tr3, tg3, tb3;
1270           
1271           tr = (tmp & 0xf800);
1272           tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1273           tr2 = a * p[0] + 0x80;
1274           tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8);
1275
1276           tg = (tmp & 0x07e0);
1277           tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1278           tg2 = a * p[0] + 0x80;
1279           tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8);
1280
1281           tb = (tmp & 0x001f);
1282           tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1283           tb2 = a * p[0] + 0x80;
1284           tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8);
1285
1286           *q = (((tr3 & 0xf8) << 8) |
1287                 ((tg3 & 0xfc) << 3) |
1288                 ((tb3 >> 3)));
1289 #endif
1290           
1291           p += 4;
1292           q++;
1293         }
1294       
1295       src += src_rowstride;
1296       dest += dest_rowstride;
1297     }
1298 }
1299
1300 static void
1301 gdk_drawable_real_draw_pixbuf (GdkDrawable  *drawable,
1302                                GdkGC        *gc,
1303                                GdkPixbuf    *pixbuf,
1304                                gint          src_x,
1305                                gint          src_y,
1306                                gint          dest_x,
1307                                gint          dest_y,
1308                                gint          width,
1309                                gint          height,
1310                                GdkRgbDither  dither,
1311                                gint          x_dither,
1312                                gint          y_dither)
1313 {
1314   gboolean free_gc = FALSE;
1315   GdkPixbuf *composited = NULL;
1316   gint dwidth, dheight;
1317   GdkRegion *clip;
1318   GdkRegion *drect;
1319   GdkRectangle tmp_rect;
1320                                        
1321   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1322   g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
1323   g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
1324   g_return_if_fail (pixbuf->bits_per_sample == 8);
1325
1326   g_return_if_fail (drawable != NULL);
1327
1328   if (width == -1) 
1329     width = pixbuf->width;
1330   if (height == -1)
1331     height = pixbuf->height;
1332
1333   g_return_if_fail (width >= 0 && height >= 0);
1334   g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
1335   g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
1336
1337   /* Clip to the drawable; this is required for get_from_drawable() so
1338    * can't be done implicitly
1339    */
1340   
1341   if (dest_x < 0)
1342     {
1343       src_x -= dest_x;
1344       width += dest_x;
1345       dest_x = 0;
1346     }
1347
1348   if (dest_y < 0)
1349     {
1350       src_y -= dest_y;
1351       height += dest_y;
1352       dest_y = 0;
1353     }
1354
1355   gdk_drawable_get_size (drawable, &dwidth, &dheight);
1356
1357   if ((dest_x + width) > dwidth)
1358     width = dwidth - dest_x;
1359
1360   if ((dest_y + height) > dheight)
1361     height = dheight - dest_y;
1362
1363   if (width <= 0 || height <= 0)
1364     return;
1365
1366   /* Clip to the clip region; this avoids getting more
1367    * image data from the server than we need to.
1368    */
1369   
1370   tmp_rect.x = dest_x;
1371   tmp_rect.y = dest_y;
1372   tmp_rect.width = width;
1373   tmp_rect.height = height;
1374
1375   drect = gdk_region_rectangle (&tmp_rect);
1376   clip = gdk_drawable_get_clip_region (drawable);
1377
1378   gdk_region_intersect (drect, clip);
1379
1380   gdk_region_get_clipbox (drect, &tmp_rect);
1381   
1382   gdk_region_destroy (drect);
1383   gdk_region_destroy (clip);
1384
1385   if (tmp_rect.width == 0 ||
1386       tmp_rect.height == 0)
1387     return;
1388   
1389   /* Actually draw */
1390
1391   if (!gc)
1392     {
1393       gc = gdk_gc_new (drawable);
1394       free_gc = TRUE;
1395     }
1396   
1397   if (pixbuf->has_alpha)
1398     {
1399       GdkVisual *visual = gdk_drawable_get_visual (drawable);
1400       void (*composite_func) (guchar       *src_buf,
1401                               gint          src_rowstride,
1402                               guchar       *dest_buf,
1403                               gint          dest_rowstride,
1404                               GdkByteOrder  dest_byte_order,
1405                               gint          width,
1406                               gint          height) = NULL;
1407
1408       /* First we see if we have a visual-specific composition function that can composite
1409        * the pixbuf data directly onto the image
1410        */
1411       if (visual)
1412         {
1413           gint bits_per_pixel = _gdk_windowing_get_bits_for_depth (gdk_drawable_get_display (drawable),
1414                                                                    visual->depth);
1415           
1416           if (visual->byte_order == (G_BYTE_ORDER == G_BIG_ENDIAN ? GDK_MSB_FIRST : GDK_LSB_FIRST) &&
1417               visual->depth == 16 &&
1418               visual->red_mask   == 0xf800 &&
1419               visual->green_mask == 0x07e0 &&
1420               visual->blue_mask  == 0x001f)
1421             composite_func = composite_565;
1422           else if (visual->depth == 24 && bits_per_pixel == 32 &&
1423                    visual->red_mask   == 0xff0000 &&
1424                    visual->green_mask == 0x00ff00 &&
1425                    visual->blue_mask  == 0x0000ff)
1426             composite_func = composite_0888;
1427         }
1428
1429       /* We can't use our composite func if we are required to dither
1430        */
1431       if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24))
1432         {
1433           gint x0, y0;
1434           for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1435             {
1436               gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1437               for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1438                 {
1439                   gint xs0, ys0;
1440                   
1441                   gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1442                   
1443                   GdkImage *image = _gdk_image_get_scratch (gdk_drawable_get_screen (drawable),
1444                                                             width1, height1,
1445                                                             gdk_drawable_get_depth (drawable), &xs0, &ys0);
1446                   
1447                   _gdk_drawable_copy_to_image (drawable, image,
1448                                                dest_x + x0, dest_y + y0,
1449                                                xs0, ys0,
1450                                                width1, height1);
1451                   (*composite_func) (pixbuf->pixels + (src_y + y0) * pixbuf->rowstride + (src_x + x0) * 4,
1452                                      pixbuf->rowstride,
1453                                      (guchar*)image->mem + ys0 * image->bpl + xs0 * image->bpp,
1454                                      image->bpl,
1455                                      visual->byte_order,
1456                                      width1, height1);
1457                   gdk_draw_image (drawable, gc, image,
1458                                   xs0, ys0,
1459                                   dest_x + x0, dest_y + y0,
1460                                   width1, height1);
1461                 }
1462             }
1463           
1464           goto out;
1465         }
1466       else
1467         {
1468           /* No special composition func, convert dest to 24 bit RGB data, composite against
1469            * that, and convert back.
1470            */
1471           composited = gdk_pixbuf_get_from_drawable (NULL,
1472                                                      drawable,
1473                                                      NULL,
1474                                                      dest_x, dest_y,
1475                                                      0, 0,
1476                                                      width, height);
1477           
1478           if (composited)
1479             composite (pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4,
1480                        pixbuf->rowstride,
1481                        composited->pixels,
1482                        composited->rowstride,
1483                        width, height);
1484         }
1485     }
1486
1487   if (composited)
1488     {
1489       src_x = 0;
1490       src_y = 0;
1491       pixbuf = composited;
1492     }
1493   
1494   if (pixbuf->n_channels == 4)
1495     {
1496       guchar *buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4;
1497
1498       gdk_draw_rgb_32_image_dithalign (drawable, gc,
1499                                        dest_x, dest_y,
1500                                        width, height,
1501                                        dither,
1502                                        buf, pixbuf->rowstride,
1503                                        x_dither, y_dither);
1504     }
1505   else                          /* n_channels == 3 */
1506     {
1507       guchar *buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 3;
1508
1509       gdk_draw_rgb_image_dithalign (drawable, gc,
1510                                     dest_x, dest_y,
1511                                     width, height,
1512                                     dither,
1513                                     buf, pixbuf->rowstride,
1514                                     x_dither, y_dither);
1515     }
1516
1517  out:
1518   if (composited)
1519     g_object_unref (composited);
1520
1521   if (free_gc)
1522     g_object_unref (gc);
1523 }