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