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