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