]> Pileus Git - ~andy/gtk/blob - gdk/gdkdraw.c
Use a scratch GC in the case where the background is a solid color.
[~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  * Deprecated: Use gdk_draw_layout() instead.
524  **/
525 void
526 gdk_draw_string (GdkDrawable *drawable,
527                  GdkFont     *font,
528                  GdkGC       *gc,
529                  gint         x,
530                  gint         y,
531                  const gchar *string)
532 {
533   gdk_draw_text (drawable, font, gc, x, y, string, _gdk_font_strlen (font, string));
534 }
535
536 /* gdk_draw_text
537  *
538  * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
539  *
540  * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
541  */
542 /**
543  * gdk_draw_text:
544  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
545  * @font: a #GdkFont.
546  * @gc: a #GdkGC.
547  * @x: the x coordinate of the left edge of the text.
548  * @y: the y coordinate of the baseline of the text.
549  * @text:  the characters to draw.
550  * @text_length: the number of characters of @text to draw.
551  * 
552  * Draws a number of characters in the given font or fontset.
553  *
554  * Deprecated: Use gdk_draw_layout() instead.
555  **/
556 void
557 gdk_draw_text (GdkDrawable *drawable,
558                GdkFont     *font,
559                GdkGC       *gc,
560                gint         x,
561                gint         y,
562                const gchar *text,
563                gint         text_length)
564 {
565   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
566   g_return_if_fail (font != NULL);
567   g_return_if_fail (GDK_IS_GC (gc));
568   g_return_if_fail (text != NULL);
569
570   GDK_DRAWABLE_GET_CLASS (drawable)->draw_text (drawable, font, gc, x, y, text, text_length);
571 }
572
573 /**
574  * gdk_draw_text_wc:
575  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
576  * @font: a #GdkFont.
577  * @gc: a #GdkGC.
578  * @x: the x coordinate of the left edge of the text.
579  * @y: the y coordinate of the baseline of the text.
580  * @text: the wide characters to draw.
581  * @text_length: the number of characters to draw.
582  * 
583  * Draws a number of wide characters using the given font of fontset.
584  * If the font is a 1-byte font, the string is converted into 1-byte 
585  * characters (discarding the high bytes) before output.
586  * 
587  * Deprecated: Use gdk_draw_layout() instead.
588  **/
589 void
590 gdk_draw_text_wc (GdkDrawable    *drawable,
591                   GdkFont        *font,
592                   GdkGC          *gc,
593                   gint            x,
594                   gint            y,
595                   const GdkWChar *text,
596                   gint            text_length)
597 {
598   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
599   g_return_if_fail (font != NULL);
600   g_return_if_fail (GDK_IS_GC (gc));
601   g_return_if_fail (text != NULL);
602
603   GDK_DRAWABLE_GET_CLASS (drawable)->draw_text_wc (drawable, font, gc, x, y, text, text_length);
604 }
605
606 /**
607  * gdk_draw_drawable:
608  * @drawable: a #GdkDrawable
609  * @gc: a #GdkGC sharing the drawable's visual and colormap
610  * @src: another #GdkDrawable
611  * @xsrc: X position in @src of rectangle to draw
612  * @ysrc: Y position in @src of rectangle to draw
613  * @xdest: X position in @drawable where the rectangle should be drawn
614  * @ydest: Y position in @drawable where the rectangle should be drawn
615  * @width: width of rectangle to draw, or -1 for entire @src width
616  * @height: height of rectangle to draw, or -1 for entire @src height
617  *
618  * Copies the @width x @height region of @src at coordinates (@xsrc,
619  * @ysrc) to coordinates (@xdest, @ydest) in @drawable.
620  * @width and/or @height may be given as -1, in which case the entire
621  * @src drawable will be copied.
622  *
623  * Most fields in @gc are not used for this operation, but notably the
624  * clip mask or clip region will be honored.
625  *
626  * The source and destination drawables must have the same visual and
627  * colormap, or errors will result. (On X11, failure to match
628  * visual/colormap results in a BadMatch error from the X server.)
629  * A common cause of this problem is an attempt to draw a bitmap to
630  * a color drawable. The way to draw a bitmap is to set the
631  * bitmap as a clip mask on your #GdkGC, then use gdk_draw_rectangle()
632  * to draw a rectangle clipped to the bitmap.
633  **/
634 void
635 gdk_draw_drawable (GdkDrawable *drawable,
636                    GdkGC       *gc,
637                    GdkDrawable *src,
638                    gint         xsrc,
639                    gint         ysrc,
640                    gint         xdest,
641                    gint         ydest,
642                    gint         width,
643                    gint         height)
644 {
645   GdkDrawable *composite;
646   gint composite_x_offset = 0;
647   gint composite_y_offset = 0;
648
649   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
650   g_return_if_fail (src != NULL);
651   g_return_if_fail (GDK_IS_GC (gc));
652
653   if (width < 0 || height < 0)
654     {
655       gint real_width;
656       gint real_height;
657       
658       gdk_drawable_get_size (src, &real_width, &real_height);
659
660       if (width < 0)
661         width = real_width;
662       if (height < 0)
663         height = real_height;
664     }
665
666
667   composite =
668     GDK_DRAWABLE_GET_CLASS (src)->get_composite_drawable (src,
669                                                           xsrc, ysrc,
670                                                           width, height,
671                                                           &composite_x_offset,
672                                                           &composite_y_offset);
673
674   
675   GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc, composite,
676                                                     xsrc - composite_x_offset,
677                                                     ysrc - composite_y_offset,
678                                                     xdest, ydest,
679                                                     width, height);
680   
681   g_object_unref (composite);
682 }
683
684 /**
685  * gdk_draw_image:
686  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
687  * @gc: a #GdkGC.
688  * @image: the #GdkImage to draw.
689  * @xsrc: the left edge of the source rectangle within @image.
690  * @ysrc: the top of the source rectangle within @image.
691  * @xdest: the x coordinate of the destination within @drawable.
692  * @ydest: the y coordinate of the destination within @drawable.
693  * @width: the width of the area to be copied, or -1 to make the area 
694  *     extend to the right edge of @image.
695  * @height: the height of the area to be copied, or -1 to make the area 
696  *     extend to the bottom edge of @image.
697  * 
698  * Draws a #GdkImage onto a drawable.
699  * The depth of the #GdkImage must match the depth of the #GdkDrawable.
700  **/
701 void
702 gdk_draw_image (GdkDrawable *drawable,
703                 GdkGC       *gc,
704                 GdkImage    *image,
705                 gint         xsrc,
706                 gint         ysrc,
707                 gint         xdest,
708                 gint         ydest,
709                 gint         width,
710                 gint         height)
711 {
712   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
713   g_return_if_fail (image != NULL);
714   g_return_if_fail (GDK_IS_GC (gc));
715
716   if (width == -1)
717     width = image->width;
718   if (height == -1)
719     height = image->height;
720
721   GDK_DRAWABLE_GET_CLASS (drawable)->draw_image (drawable, gc, image, xsrc, ysrc,
722                                                  xdest, ydest, width, height);
723 }
724
725 /**
726  * gdk_draw_pixbuf:
727  * @drawable: Destination drawable.
728  * @gc: a #GdkGC, used for clipping, or %NULL
729  * @pixbuf: a #GdkPixbuf
730  * @src_x: Source X coordinate within pixbuf.
731  * @src_y: Source Y coordinates within pixbuf.
732  * @dest_x: Destination X coordinate within drawable.
733  * @dest_y: Destination Y coordinate within drawable.
734  * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
735  * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
736  * @dither: Dithering mode for #GdkRGB.
737  * @x_dither: X offset for dither.
738  * @y_dither: Y offset for dither.
739  * 
740  * Renders a rectangular portion of a pixbuf to a drawable.  The destination
741  * drawable must have a colormap. All windows have a colormap, however, pixmaps
742  * only have colormap by default if they were created with a non-%NULL window 
743  * argument. Otherwise a colormap must be set on them with 
744  * gdk_drawable_set_colormap().
745  *
746  * On older X servers, rendering pixbufs with an alpha channel involves round 
747  * trips to the X server, and may be somewhat slow.
748  *
749  * The clip mask of @gc is ignored, but clip rectangles and clip regions work
750  * fine.
751  * 
752  * Since: 2.2
753  **/
754 void
755 gdk_draw_pixbuf (GdkDrawable     *drawable,
756                   GdkGC           *gc,
757                   GdkPixbuf       *pixbuf,
758                   gint             src_x,
759                   gint             src_y,
760                   gint             dest_x,
761                   gint             dest_y,
762                   gint             width,
763                   gint             height,
764                   GdkRgbDither     dither,
765                   gint             x_dither,
766                   gint             y_dither)
767 {
768   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
769   g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
770   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
771
772   if (width == -1)
773     width = gdk_pixbuf_get_width (pixbuf);
774   if (height == -1)
775     height = gdk_pixbuf_get_height (pixbuf);
776
777   GDK_DRAWABLE_GET_CLASS (drawable)->draw_pixbuf (drawable, gc, pixbuf,
778                                                   src_x, src_y, dest_x, dest_y, width, height,
779                                                   dither, x_dither, y_dither);
780 }
781
782 /**
783  * gdk_draw_points:
784  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
785  * @gc: a #GdkGC.
786  * @points: an array of #GdkPoint structures.
787  * @npoints: the number of points to be drawn.
788  * 
789  * Draws a number of points, using the foreground color and other 
790  * attributes of the #GdkGC.
791  **/
792 void
793 gdk_draw_points (GdkDrawable *drawable,
794                  GdkGC       *gc,
795                  GdkPoint    *points,
796                  gint         npoints)
797 {
798   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
799   g_return_if_fail ((points != NULL) && (npoints > 0));
800   g_return_if_fail (GDK_IS_GC (gc));
801   g_return_if_fail (npoints >= 0);
802
803   if (npoints == 0)
804     return;
805
806   GDK_DRAWABLE_GET_CLASS (drawable)->draw_points (drawable, gc, points, npoints);
807 }
808
809 /**
810  * gdk_draw_segments:
811  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
812  * @gc: a #GdkGC.
813  * @segs: an array of #GdkSegment structures specifying the start and 
814  *   end points of the lines to be drawn.
815  * @nsegs: the number of line segments to draw, i.e. the size of the 
816  *   @segs array.
817  * 
818  * Draws a number of unconnected lines.
819  **/
820 void
821 gdk_draw_segments (GdkDrawable *drawable,
822                    GdkGC       *gc,
823                    GdkSegment  *segs,
824                    gint         nsegs)
825 {
826   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
827
828   if (nsegs == 0)
829     return;
830
831   g_return_if_fail (segs != NULL);
832   g_return_if_fail (GDK_IS_GC (gc));
833   g_return_if_fail (nsegs >= 0);
834
835   GDK_DRAWABLE_GET_CLASS (drawable)->draw_segments (drawable, gc, segs, nsegs);
836 }
837
838 /**
839  * gdk_draw_lines:
840  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
841  * @gc: a #GdkGC.
842  * @points: an array of #GdkPoint structures specifying the endpoints of the
843  * @npoints: the size of the @points array.
844  * 
845  * Draws a series of lines connecting the given points.
846  * The way in which joins between lines are draw is determined by the
847  * #GdkCapStyle value in the #GdkGC. This can be set with
848  * gdk_gc_set_line_attributes().
849  **/
850 void
851 gdk_draw_lines (GdkDrawable *drawable,
852                 GdkGC       *gc,
853                 GdkPoint    *points,
854                 gint         npoints)
855 {
856   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
857   g_return_if_fail (points != NULL);
858   g_return_if_fail (GDK_IS_GC (gc));
859   g_return_if_fail (npoints >= 0);
860
861   if (npoints == 0)
862     return;
863
864   GDK_DRAWABLE_GET_CLASS (drawable)->draw_lines (drawable, gc, points, npoints);
865 }
866
867 /**
868  * gdk_draw_glyphs:
869  * @drawable: a #GdkDrawable
870  * @gc: a #GdkGC
871  * @font: font to be used
872  * @x: X coordinate of baseline origin
873  * @y: Y coordinate of baseline origin
874  * @glyphs: glyphs to render
875  *
876  * This is a low-level function; 99% of text rendering should be done
877  * using gdk_draw_layout() instead.
878  *
879  * A glyph is a character in a font. This function draws a sequence of
880  * glyphs.  To obtain a sequence of glyphs you have to understand a
881  * lot about internationalized text handling, which you don't want to
882  * understand; thus, use gdk_draw_layout() instead of this function,
883  * gdk_draw_layout() handles the details.
884  * 
885  **/
886 void
887 gdk_draw_glyphs (GdkDrawable      *drawable,
888                  GdkGC            *gc,
889                  PangoFont        *font,
890                  gint              x,
891                  gint              y,
892                  PangoGlyphString *glyphs)
893 {
894   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
895   g_return_if_fail (GDK_IS_GC (gc));
896
897
898   GDK_DRAWABLE_GET_CLASS (drawable)->draw_glyphs (drawable, gc, font, x, y, glyphs);
899 }
900
901
902 /**
903  * gdk_drawable_copy_to_image:
904  * @drawable: a #GdkDrawable
905  * @image: a #GdkDrawable, or %NULL if a new @image should be created.
906  * @src_x: x coordinate on @drawable
907  * @src_y: y coordinate on @drawable
908  * @dest_x: x coordinate within @image. Must be 0 if @image is %NULL
909  * @dest_y: y coordinate within @image. Must be 0 if @image is %NULL
910  * @width: width of region to get
911  * @height: height or region to get
912  *
913  * Copies a portion of @drawable into the client side image structure
914  * @image. If @image is %NULL, creates a new image of size @width x @height
915  * and copies into that. See gdk_drawable_get_image() for further details.
916  * 
917  * Return value: @image, or a new a #GdkImage containing the contents
918  *               of @drawable
919  * 
920  * Since: 2.4
921  **/
922 GdkImage*
923 gdk_drawable_copy_to_image (GdkDrawable *drawable,
924                             GdkImage    *image,
925                             gint         src_x,
926                             gint         src_y,
927                             gint         dest_x,
928                             gint         dest_y,
929                             gint         width,
930                             gint         height)
931 {
932   GdkDrawable *composite;
933   gint composite_x_offset = 0;
934   gint composite_y_offset = 0;
935   GdkImage *retval;
936   GdkColormap *cmap;
937   
938   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
939   g_return_val_if_fail (src_x >= 0, NULL);
940   g_return_val_if_fail (src_y >= 0, NULL);
941
942   /* FIXME? Note race condition since we get the size then
943    * get the image, and the size may have changed.
944    */
945   
946   if (width < 0 || height < 0)
947     gdk_drawable_get_size (drawable,
948                            width < 0 ? &width : NULL,
949                            height < 0 ? &height : NULL);
950   
951   composite =
952     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
953                                                                src_x, src_y,
954                                                                width, height,
955                                                                &composite_x_offset,
956                                                                &composite_y_offset); 
957   
958   retval = GDK_DRAWABLE_GET_CLASS (composite)->_copy_to_image (composite,
959                                                                image,
960                                                                src_x - composite_x_offset,
961                                                                src_y - composite_y_offset,
962                                                                dest_x, dest_y,
963                                                                width, height);
964
965   g_object_unref (composite);
966
967   if (!image && retval)
968     {
969       cmap = gdk_drawable_get_colormap (drawable);
970       
971       if (cmap)
972         gdk_image_set_colormap (retval, cmap);
973     }
974   
975   return retval;
976 }
977
978 /**
979  * gdk_drawable_get_image:
980  * @drawable: a #GdkDrawable
981  * @x: x coordinate on @drawable
982  * @y: y coordinate on @drawable
983  * @width: width of region to get
984  * @height: height or region to get
985  * 
986  * A #GdkImage stores client-side image data (pixels). In contrast,
987  * #GdkPixmap and #GdkWindow are server-side
988  * objects. gdk_drawable_get_image() obtains the pixels from a
989  * server-side drawable as a client-side #GdkImage.  The format of a
990  * #GdkImage depends on the #GdkVisual of the current display, which
991  * makes manipulating #GdkImage extremely difficult; therefore, in
992  * most cases you should use gdk_pixbuf_get_from_drawable() instead of
993  * this lower-level function. A #GdkPixbuf contains image data in a
994  * canonicalized RGB format, rather than a display-dependent format.
995  * Of course, there's a convenience vs. speed tradeoff here, so you'll
996  * want to think about what makes sense for your application.
997  *
998  * @x, @y, @width, and @height define the region of @drawable to
999  * obtain as an image.
1000  *
1001  * You would usually copy image data to the client side if you intend
1002  * to examine the values of individual pixels, for example to darken
1003  * an image or add a red tint. It would be prohibitively slow to
1004  * make a round-trip request to the windowing system for each pixel,
1005  * so instead you get all of them at once, modify them, then copy
1006  * them all back at once.
1007  *
1008  * If the X server or other windowing system backend is on the local
1009  * machine, this function may use shared memory to avoid copying
1010  * the image data.
1011  *
1012  * If the source drawable is a #GdkWindow and partially offscreen
1013  * or obscured, then the obscured portions of the returned image
1014  * will contain undefined data.
1015  * 
1016  * Return value: a #GdkImage containing the contents of @drawable
1017  **/
1018 GdkImage*
1019 gdk_drawable_get_image (GdkDrawable *drawable,
1020                         gint         x,
1021                         gint         y,
1022                         gint         width,
1023                         gint         height)
1024 {
1025   GdkDrawable *composite;
1026   gint composite_x_offset = 0;
1027   gint composite_y_offset = 0;
1028   GdkImage *retval;
1029   GdkColormap *cmap;
1030   
1031   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1032   g_return_val_if_fail (x >= 0, NULL);
1033   g_return_val_if_fail (y >= 0, NULL);
1034
1035   /* FIXME? Note race condition since we get the size then
1036    * get the image, and the size may have changed.
1037    */
1038   
1039   if (width < 0 || height < 0)
1040     gdk_drawable_get_size (drawable,
1041                            width < 0 ? &width : NULL,
1042                            height < 0 ? &height : NULL);
1043   
1044   composite =
1045     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
1046                                                                x, y,
1047                                                                width, height,
1048                                                                &composite_x_offset,
1049                                                                &composite_y_offset); 
1050   
1051   retval = GDK_DRAWABLE_GET_CLASS (composite)->get_image (composite,
1052                                                           x - composite_x_offset,
1053                                                           y - composite_y_offset,
1054                                                           width, height);
1055
1056   g_object_unref (composite);
1057
1058   cmap = gdk_drawable_get_colormap (drawable);
1059   
1060   if (retval && cmap)
1061     gdk_image_set_colormap (retval, cmap);
1062   
1063   return retval;
1064 }
1065
1066 static GdkImage*
1067 gdk_drawable_real_get_image (GdkDrawable     *drawable,
1068                              gint             x,
1069                              gint             y,
1070                              gint             width,
1071                              gint             height)
1072 {
1073   return gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
1074 }
1075
1076 static GdkDrawable*
1077 gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
1078                                           gint         x,
1079                                           gint         y,
1080                                           gint         width,
1081                                           gint         height,
1082                                           gint        *composite_x_offset,
1083                                           gint        *composite_y_offset)
1084 {
1085   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1086
1087   *composite_x_offset = 0;
1088   *composite_y_offset = 0;
1089   
1090   return g_object_ref (drawable);
1091 }
1092
1093 /**
1094  * gdk_drawable_get_clip_region:
1095  * @drawable: a #GdkDrawable
1096  * 
1097  * Computes the region of a drawable that potentially can be written
1098  * to by drawing primitives. This region will not take into account
1099  * the clip region for the GC, and may also not take into account
1100  * other factors such as if the window is obscured by other windows,
1101  * but no area outside of this region will be affected by drawing
1102  * primitives.
1103  * 
1104  * Return value: a #GdkRegion. This must be freed with gdk_region_destroy()
1105  *               when you are done.
1106  **/
1107 GdkRegion *
1108 gdk_drawable_get_clip_region (GdkDrawable *drawable)
1109 {
1110   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1111
1112   return GDK_DRAWABLE_GET_CLASS (drawable)->get_clip_region (drawable);
1113 }
1114
1115 /**
1116  * gdk_drawable_get_visible_region:
1117  * @drawable: 
1118  * 
1119  * Computes the region of a drawable that is potentially visible.
1120  * This does not necessarily take into account if the window is
1121  * obscured by other windows, but no area outside of this region
1122  * is visible.
1123  * 
1124  * Return value: a #GdkRegion. This must be freed with gdk_region_destroy()
1125  *               when you are done.
1126  **/
1127 GdkRegion *
1128 gdk_drawable_get_visible_region (GdkDrawable *drawable)
1129 {
1130   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1131
1132   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visible_region (drawable);
1133 }
1134
1135 static GdkRegion *
1136 gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
1137 {
1138   GdkRectangle rect;
1139
1140   rect.x = 0;
1141   rect.y = 0;
1142
1143   gdk_drawable_get_size (drawable, &rect.width, &rect.height);
1144
1145   return gdk_region_rectangle (&rect);
1146 }
1147
1148 static void
1149 composite (guchar *src_buf,
1150            gint    src_rowstride,
1151            guchar *dest_buf,
1152            gint    dest_rowstride,
1153            gint    width,
1154            gint    height)
1155 {
1156   guchar *src = src_buf;
1157   guchar *dest = dest_buf;
1158
1159   while (height--)
1160     {
1161       gint twidth = width;
1162       guchar *p = src;
1163       guchar *q = dest;
1164
1165       while (twidth--)
1166         {
1167           guchar a = p[3];
1168           guint t;
1169
1170           t = a * p[0] + (255 - a) * q[0] + 0x80;
1171           q[0] = (t + (t >> 8)) >> 8;
1172           t = a * p[1] + (255 - a) * q[1] + 0x80;
1173           q[1] = (t + (t >> 8)) >> 8;
1174           t = a * p[2] + (255 - a) * q[2] + 0x80;
1175           q[2] = (t + (t >> 8)) >> 8;
1176
1177           p += 4;
1178           q += 3;
1179         }
1180       
1181       src += src_rowstride;
1182       dest += dest_rowstride;
1183     }
1184 }
1185
1186 static void
1187 composite_0888 (guchar      *src_buf,
1188                 gint         src_rowstride,
1189                 guchar      *dest_buf,
1190                 gint         dest_rowstride,
1191                 GdkByteOrder dest_byte_order,
1192                 gint         width,
1193                 gint         height)
1194 {
1195   guchar *src = src_buf;
1196   guchar *dest = dest_buf;
1197
1198   while (height--)
1199     {
1200       gint twidth = width;
1201       guchar *p = src;
1202       guchar *q = dest;
1203
1204       if (dest_byte_order == GDK_LSB_FIRST)
1205         {
1206           while (twidth--)
1207             {
1208               guint t;
1209               
1210               t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80;
1211               q[0] = (t + (t >> 8)) >> 8;
1212               t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80;
1213               q[1] = (t + (t >> 8)) >> 8;
1214               t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80;
1215               q[2] = (t + (t >> 8)) >> 8;
1216               p += 4;
1217               q += 4;
1218             }
1219         }
1220       else
1221         {
1222           while (twidth--)
1223             {
1224               guint t;
1225               
1226               t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80;
1227               q[1] = (t + (t >> 8)) >> 8;
1228               t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80;
1229               q[2] = (t + (t >> 8)) >> 8;
1230               t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80;
1231               q[3] = (t + (t >> 8)) >> 8;
1232               p += 4;
1233               q += 4;
1234             }
1235         }
1236       
1237       src += src_rowstride;
1238       dest += dest_rowstride;
1239     }
1240 }
1241
1242 static void
1243 composite_565 (guchar      *src_buf,
1244                gint         src_rowstride,
1245                guchar      *dest_buf,
1246                gint         dest_rowstride,
1247                GdkByteOrder dest_byte_order,
1248                gint         width,
1249                gint         height)
1250 {
1251   guchar *src = src_buf;
1252   guchar *dest = dest_buf;
1253
1254   while (height--)
1255     {
1256       gint twidth = width;
1257       guchar *p = src;
1258       gushort *q = (gushort *)dest;
1259
1260       while (twidth--)
1261         {
1262           guchar a = p[3];
1263           guint tr, tg, tb;
1264           guint tr1, tg1, tb1;
1265           guint tmp = *q;
1266
1267 #if 1
1268           /* This is fast, and corresponds to what composite() above does
1269            * if we converted to 8-bit first.
1270            */
1271           tr = (tmp & 0xf800);
1272           tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1273           tg = (tmp & 0x07e0);
1274           tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1275           tb = (tmp & 0x001f);
1276           tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1277
1278           *q = (((tr1 + (tr1 >> 8)) & 0xf800) |
1279                 (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5)  |
1280                 ((tb1 + (tb1 >> 8)) >> 11));
1281 #else
1282           /* This version correspond to the result we get with XRENDER -
1283            * a bit of precision is lost since we convert to 8 bit after premultiplying
1284            * instead of at the end
1285            */
1286           guint tr2, tg2, tb2;
1287           guint tr3, tg3, tb3;
1288           
1289           tr = (tmp & 0xf800);
1290           tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1291           tr2 = a * p[0] + 0x80;
1292           tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8);
1293
1294           tg = (tmp & 0x07e0);
1295           tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1296           tg2 = a * p[0] + 0x80;
1297           tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8);
1298
1299           tb = (tmp & 0x001f);
1300           tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1301           tb2 = a * p[0] + 0x80;
1302           tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8);
1303
1304           *q = (((tr3 & 0xf8) << 8) |
1305                 ((tg3 & 0xfc) << 3) |
1306                 ((tb3 >> 3)));
1307 #endif
1308           
1309           p += 4;
1310           q++;
1311         }
1312       
1313       src += src_rowstride;
1314       dest += dest_rowstride;
1315     }
1316 }
1317
1318 static void
1319 gdk_drawable_real_draw_pixbuf (GdkDrawable  *drawable,
1320                                GdkGC        *gc,
1321                                GdkPixbuf    *pixbuf,
1322                                gint          src_x,
1323                                gint          src_y,
1324                                gint          dest_x,
1325                                gint          dest_y,
1326                                gint          width,
1327                                gint          height,
1328                                GdkRgbDither  dither,
1329                                gint          x_dither,
1330                                gint          y_dither)
1331 {
1332   GdkPixbuf *composited = NULL;
1333   gint dwidth, dheight;
1334   GdkRegion *clip;
1335   GdkRegion *drect;
1336   GdkRectangle tmp_rect;
1337                                        
1338   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1339   g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
1340   g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
1341   g_return_if_fail (pixbuf->bits_per_sample == 8);
1342
1343   g_return_if_fail (drawable != NULL);
1344
1345   if (width == -1) 
1346     width = pixbuf->width;
1347   if (height == -1)
1348     height = pixbuf->height;
1349
1350   g_return_if_fail (width >= 0 && height >= 0);
1351   g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
1352   g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
1353
1354   /* Clip to the drawable; this is required for get_from_drawable() so
1355    * can't be done implicitly
1356    */
1357   
1358   if (dest_x < 0)
1359     {
1360       src_x -= dest_x;
1361       width += dest_x;
1362       dest_x = 0;
1363     }
1364
1365   if (dest_y < 0)
1366     {
1367       src_y -= dest_y;
1368       height += dest_y;
1369       dest_y = 0;
1370     }
1371
1372   gdk_drawable_get_size (drawable, &dwidth, &dheight);
1373
1374   if ((dest_x + width) > dwidth)
1375     width = dwidth - dest_x;
1376
1377   if ((dest_y + height) > dheight)
1378     height = dheight - dest_y;
1379
1380   if (width <= 0 || height <= 0)
1381     return;
1382
1383   /* Clip to the clip region; this avoids getting more
1384    * image data from the server than we need to.
1385    */
1386   
1387   tmp_rect.x = dest_x;
1388   tmp_rect.y = dest_y;
1389   tmp_rect.width = width;
1390   tmp_rect.height = height;
1391
1392   drect = gdk_region_rectangle (&tmp_rect);
1393   clip = gdk_drawable_get_clip_region (drawable);
1394
1395   gdk_region_intersect (drect, clip);
1396
1397   gdk_region_get_clipbox (drect, &tmp_rect);
1398   
1399   gdk_region_destroy (drect);
1400   gdk_region_destroy (clip);
1401
1402   if (tmp_rect.width == 0 ||
1403       tmp_rect.height == 0)
1404     return;
1405   
1406   /* Actually draw */
1407   if (!gc)
1408     gc = _gdk_drawable_get_scratch_gc (drawable, FALSE);
1409   
1410   if (pixbuf->has_alpha)
1411     {
1412       GdkVisual *visual = gdk_drawable_get_visual (drawable);
1413       void (*composite_func) (guchar       *src_buf,
1414                               gint          src_rowstride,
1415                               guchar       *dest_buf,
1416                               gint          dest_rowstride,
1417                               GdkByteOrder  dest_byte_order,
1418                               gint          width,
1419                               gint          height) = NULL;
1420
1421       /* First we see if we have a visual-specific composition function that can composite
1422        * the pixbuf data directly onto the image
1423        */
1424       if (visual)
1425         {
1426           gint bits_per_pixel = _gdk_windowing_get_bits_for_depth (gdk_drawable_get_display (drawable),
1427                                                                    visual->depth);
1428           
1429           if (visual->byte_order == (G_BYTE_ORDER == G_BIG_ENDIAN ? GDK_MSB_FIRST : GDK_LSB_FIRST) &&
1430               visual->depth == 16 &&
1431               visual->red_mask   == 0xf800 &&
1432               visual->green_mask == 0x07e0 &&
1433               visual->blue_mask  == 0x001f)
1434             composite_func = composite_565;
1435           else if (visual->depth == 24 && bits_per_pixel == 32 &&
1436                    visual->red_mask   == 0xff0000 &&
1437                    visual->green_mask == 0x00ff00 &&
1438                    visual->blue_mask  == 0x0000ff)
1439             composite_func = composite_0888;
1440         }
1441
1442       /* We can't use our composite func if we are required to dither
1443        */
1444       if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24))
1445         {
1446           gint x0, y0;
1447           for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1448             {
1449               gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1450               for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1451                 {
1452                   gint xs0, ys0;
1453                   
1454                   gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1455                   
1456                   GdkImage *image = _gdk_image_get_scratch (gdk_drawable_get_screen (drawable),
1457                                                             width1, height1,
1458                                                             gdk_drawable_get_depth (drawable), &xs0, &ys0);
1459                   
1460                   gdk_drawable_copy_to_image (drawable, image,
1461                                               dest_x + x0, dest_y + y0,
1462                                               xs0, ys0,
1463                                               width1, height1);
1464                   (*composite_func) (pixbuf->pixels + (src_y + y0) * pixbuf->rowstride + (src_x + x0) * 4,
1465                                      pixbuf->rowstride,
1466                                      (guchar*)image->mem + ys0 * image->bpl + xs0 * image->bpp,
1467                                      image->bpl,
1468                                      visual->byte_order,
1469                                      width1, height1);
1470                   gdk_draw_image (drawable, gc, image,
1471                                   xs0, ys0,
1472                                   dest_x + x0, dest_y + y0,
1473                                   width1, height1);
1474                 }
1475             }
1476           
1477           goto out;
1478         }
1479       else
1480         {
1481           /* No special composition func, convert dest to 24 bit RGB data, composite against
1482            * that, and convert back.
1483            */
1484           composited = gdk_pixbuf_get_from_drawable (NULL,
1485                                                      drawable,
1486                                                      NULL,
1487                                                      dest_x, dest_y,
1488                                                      0, 0,
1489                                                      width, height);
1490           
1491           if (composited)
1492             composite (pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4,
1493                        pixbuf->rowstride,
1494                        composited->pixels,
1495                        composited->rowstride,
1496                        width, height);
1497         }
1498     }
1499
1500   if (composited)
1501     {
1502       src_x = 0;
1503       src_y = 0;
1504       pixbuf = composited;
1505     }
1506   
1507   if (pixbuf->n_channels == 4)
1508     {
1509       guchar *buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4;
1510
1511       gdk_draw_rgb_32_image_dithalign (drawable, gc,
1512                                        dest_x, dest_y,
1513                                        width, height,
1514                                        dither,
1515                                        buf, pixbuf->rowstride,
1516                                        x_dither, y_dither);
1517     }
1518   else                          /* n_channels == 3 */
1519     {
1520       guchar *buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 3;
1521
1522       gdk_draw_rgb_image_dithalign (drawable, gc,
1523                                     dest_x, dest_y,
1524                                     width, height,
1525                                     dither,
1526                                     buf, pixbuf->rowstride,
1527                                     x_dither, y_dither);
1528     }
1529
1530  out:
1531   if (composited)
1532     g_object_unref (composited);
1533 }
1534
1535 /**
1536  * _gdk_drawable_get_scratch_gc:
1537  * @drawable: A #GdkDrawable
1538  * @graphics_exposures: Whether the reutrned #GdkGC should generate graphics exposures 
1539  * 
1540  * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has
1541  * the standard values for @drawable, except for the graphics_exposures
1542  * field which is determined by the @graphics_exposures parameter.
1543  *
1544  * The foreground color of the returned #GdkGC is undefined. The #GdkGC
1545  * must not be altered in any way, except to change its foreground color.
1546  * 
1547  * Return value: A #GdkGC suitable for drawing on @drawable
1548  * 
1549  * Since: 2.4
1550  **/
1551 GdkGC *
1552 _gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
1553                               gboolean     graphics_exposures)
1554 {
1555   GdkScreen *screen;
1556   gint depth;
1557
1558   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1559
1560   screen = gdk_drawable_get_screen (drawable);
1561
1562   g_return_val_if_fail (!screen->closed, NULL);
1563
1564   depth = gdk_drawable_get_depth (drawable);
1565
1566   if (graphics_exposures)
1567     {
1568       if (!screen->exposure_gcs[depth])
1569         {
1570           GdkGCValues values;
1571           GdkGCValuesMask mask;
1572
1573           values.graphics_exposures = TRUE;
1574           mask = GDK_GC_EXPOSURES;
1575           screen->exposure_gcs[depth] =
1576             gdk_gc_new_with_values (drawable, &values, mask);
1577         }
1578
1579       return screen->exposure_gcs[depth];
1580     }
1581   else
1582     {
1583       if (!screen->normal_gcs[depth])
1584         {
1585           screen->normal_gcs[depth] =
1586             gdk_gc_new (drawable);
1587         }
1588
1589       return screen->normal_gcs[depth];
1590     }
1591 }