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