]> Pileus Git - ~andy/gtk/blob - gdk/gdkdraw.c
90b44ba1767e2169f729bc729128383006977cde
[~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 <gdk-pixbuf/gdk-pixbuf.h>
31 #include "gdkcairo.h"
32 #include "gdkdrawable.h"
33 #include "gdkinternals.h"
34 #include "gdkwindow.h"
35 #include "gdkscreen.h"
36 #include "gdkpixbuf.h"
37
38
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 cairo_region_t *  gdk_drawable_real_get_visible_region     (GdkDrawable  *drawable);
47 static void         gdk_drawable_real_draw_drawable          (GdkDrawable  *drawable,
48                                                               GdkGC        *gc,
49                                                               GdkDrawable  *src,
50                                                               gint          xsrc,
51                                                               gint          ysrc,
52                                                               gint          xdest,
53                                                               gint          ydest,
54                                                               gint          width,
55                                                               gint          height);
56      
57
58 G_DEFINE_ABSTRACT_TYPE (GdkDrawable, gdk_drawable, G_TYPE_OBJECT)
59
60 static void
61 gdk_drawable_class_init (GdkDrawableClass *klass)
62 {
63   klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
64   /* Default implementation for clip and visible region is the same */
65   klass->get_clip_region = gdk_drawable_real_get_visible_region;
66   klass->get_visible_region = gdk_drawable_real_get_visible_region;
67   klass->draw_drawable = gdk_drawable_real_draw_drawable;
68 }
69
70 static void
71 gdk_drawable_init (GdkDrawable *drawable)
72 {
73 }
74
75 /* Manipulation of drawables
76  */
77
78 /**
79  * gdk_drawable_get_size:
80  * @drawable: a #GdkDrawable
81  * @width: (out) (allow-none): location to store drawable's width, or %NULL
82  * @height: (out) (allow-none): location to store drawable's height, or %NULL
83  *
84  * Fills *@width and *@height with the size of @drawable.
85  * @width or @height can be %NULL if you only want the other one.
86  *
87  * On the X11 platform, if @drawable is a #GdkWindow, the returned
88  * size is the size reported in the most-recently-processed configure
89  * event, rather than the current size on the X server.
90  * 
91  **/
92 void
93 gdk_drawable_get_size (GdkDrawable *drawable,
94                        gint        *width,
95                        gint        *height)
96 {
97   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
98
99   GDK_DRAWABLE_GET_CLASS (drawable)->get_size (drawable, width, height);  
100 }
101
102 /**
103  * gdk_drawable_get_visual:
104  * @drawable: a #GdkDrawable
105  * 
106  * Gets the #GdkVisual describing the pixel format of @drawable.
107  * 
108  * Return value: a #GdkVisual
109  **/
110 GdkVisual*
111 gdk_drawable_get_visual (GdkDrawable *drawable)
112 {
113   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
114   
115   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visual (drawable);
116 }
117
118 /**
119  * gdk_drawable_get_depth:
120  * @drawable: a #GdkDrawable
121  * 
122  * Obtains the bit depth of the drawable, that is, the number of bits
123  * that make up a pixel in the drawable's visual. Examples are 8 bits
124  * per pixel, 24 bits per pixel, etc.
125  * 
126  * Return value: number of bits per pixel
127  **/
128 gint
129 gdk_drawable_get_depth (GdkDrawable *drawable)
130 {
131   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), 0);
132
133   return GDK_DRAWABLE_GET_CLASS (drawable)->get_depth (drawable);
134 }
135 /**
136  * gdk_drawable_get_screen:
137  * @drawable: a #GdkDrawable
138  * 
139  * Gets the #GdkScreen associated with a #GdkDrawable.
140  * 
141  * Return value: the #GdkScreen associated with @drawable
142  *
143  * Since: 2.2
144  **/
145 GdkScreen*
146 gdk_drawable_get_screen(GdkDrawable *drawable)
147 {
148   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
149
150   return GDK_DRAWABLE_GET_CLASS (drawable)->get_screen (drawable);
151 }
152
153 /**
154  * gdk_drawable_get_display:
155  * @drawable: a #GdkDrawable
156  * 
157  * Gets the #GdkDisplay associated with a #GdkDrawable.
158  * 
159  * Return value: the #GdkDisplay associated with @drawable
160  *
161  * Since: 2.2
162  **/
163 GdkDisplay*
164 gdk_drawable_get_display (GdkDrawable *drawable)
165 {
166   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
167   
168   return gdk_screen_get_display (gdk_drawable_get_screen (drawable));
169 }
170         
171 /**
172  * gdk_drawable_set_colormap:
173  * @drawable: a #GdkDrawable
174  * @colormap: a #GdkColormap
175  *
176  * Sets the colormap associated with @drawable. Normally this will
177  * happen automatically when the drawable is created; you only need to
178  * use this function if the drawable-creating function did not have a
179  * way to determine the colormap, and you then use drawable operations
180  * that require a colormap. The colormap for all drawables and
181  * graphics contexts you intend to use together should match. i.e.
182  * when using a #GdkGC to draw to a drawable, or copying one drawable
183  * to another, the colormaps should match.
184  * 
185  **/
186 void
187 gdk_drawable_set_colormap (GdkDrawable *drawable,
188                            GdkColormap *cmap)
189 {
190   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
191   g_return_if_fail (cmap == NULL || gdk_drawable_get_depth (drawable)
192                     == cmap->visual->depth);
193
194   GDK_DRAWABLE_GET_CLASS (drawable)->set_colormap (drawable, cmap);
195 }
196
197 /**
198  * gdk_drawable_get_colormap:
199  * @drawable: a #GdkDrawable
200  * 
201  * Gets the colormap for @drawable, if one is set; returns
202  * %NULL otherwise.
203  * 
204  * Return value: the colormap, or %NULL
205  **/
206 GdkColormap*
207 gdk_drawable_get_colormap (GdkDrawable *drawable)
208 {
209   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
210
211   return GDK_DRAWABLE_GET_CLASS (drawable)->get_colormap (drawable);
212 }
213
214 /* Drawing
215  */
216
217 /**
218  * gdk_draw_drawable:
219  * @drawable: a #GdkDrawable
220  * @gc: a #GdkGC sharing the drawable's visual and colormap
221  * @src: the source #GdkDrawable, which may be the same as @drawable
222  * @xsrc: X position in @src of rectangle to draw
223  * @ysrc: Y position in @src of rectangle to draw
224  * @xdest: X position in @drawable where the rectangle should be drawn
225  * @ydest: Y position in @drawable where the rectangle should be drawn
226  * @width: width of rectangle to draw, or -1 for entire @src width
227  * @height: height of rectangle to draw, or -1 for entire @src height
228  *
229  * Copies the @width x @height region of @src at coordinates (@xsrc,
230  * @ysrc) to coordinates (@xdest, @ydest) in @drawable.
231  * @width and/or @height may be given as -1, in which case the entire
232  * @src drawable will be copied.
233  *
234  * Most fields in @gc are not used for this operation, but notably the
235  * clip mask or clip region will be honored.
236  *
237  * The source and destination drawables must have the same visual and
238  * colormap, or errors will result. (On X11, failure to match
239  * visual/colormap results in a BadMatch error from the X server.)
240  * A common cause of this problem is an attempt to draw a bitmap to
241  * a color drawable. The way to draw a bitmap is to set the bitmap as 
242  * the stipple on the #GdkGC, set the fill mode to %GDK_STIPPLED, and 
243  * then draw the rectangle.
244  **/
245 void
246 gdk_draw_drawable (GdkDrawable *drawable,
247                    GdkGC       *gc,
248                    GdkDrawable *src,
249                    gint         xsrc,
250                    gint         ysrc,
251                    gint         xdest,
252                    gint         ydest,
253                    gint         width,
254                    gint         height)
255 {
256   GdkDrawable *composite;
257   gint composite_x_offset = 0;
258   gint composite_y_offset = 0;
259
260   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
261   g_return_if_fail (GDK_IS_DRAWABLE (src));
262   g_return_if_fail (GDK_IS_GC (gc));
263
264   if (width < 0 || height < 0)
265     {
266       gint real_width;
267       gint real_height;
268       
269       gdk_drawable_get_size (src, &real_width, &real_height);
270
271       if (width < 0)
272         width = real_width;
273       if (height < 0)
274         height = real_height;
275     }
276
277
278   composite =
279     GDK_DRAWABLE_GET_CLASS (src)->get_composite_drawable (src,
280                                                           xsrc, ysrc,
281                                                           width, height,
282                                                           &composite_x_offset,
283                                                           &composite_y_offset);
284
285   /* TODO: For non-native windows this may copy stuff from other overlapping
286      windows. We should clip that and (for windows with bg != None) clear that
287      area in the destination instead. */
288
289   if (GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src)
290     GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src (drawable, gc,
291                                                                composite,
292                                                                xsrc - composite_x_offset,
293                                                                ysrc - composite_y_offset,
294                                                                xdest, ydest,
295                                                                width, height,
296                                                                src);
297   else /* backwards compat for old out-of-tree implementations of GdkDrawable (are there any?) */
298     GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc,
299                                                       composite,
300                                                       xsrc - composite_x_offset,
301                                                       ysrc - composite_y_offset,
302                                                       xdest, ydest,
303                                                       width, height);
304
305   g_object_unref (composite);
306 }
307
308 static GdkDrawable *
309 gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
310                                           gint         x,
311                                           gint         y,
312                                           gint         width,
313                                           gint         height,
314                                           gint        *composite_x_offset,
315                                           gint        *composite_y_offset)
316 {
317   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
318
319   *composite_x_offset = 0;
320   *composite_y_offset = 0;
321   
322   return g_object_ref (drawable);
323 }
324
325 /**
326  * gdk_drawable_get_clip_region:
327  * @drawable: a #GdkDrawable
328  * 
329  * Computes the region of a drawable that potentially can be written
330  * to by drawing primitives. This region will not take into account
331  * the clip region for the GC, and may also not take into account
332  * other factors such as if the window is obscured by other windows,
333  * but no area outside of this region will be affected by drawing
334  * primitives.
335  * 
336  * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
337  *          when you are done.
338  **/
339 cairo_region_t *
340 gdk_drawable_get_clip_region (GdkDrawable *drawable)
341 {
342   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
343
344   return GDK_DRAWABLE_GET_CLASS (drawable)->get_clip_region (drawable);
345 }
346
347 /**
348  * gdk_drawable_get_visible_region:
349  * @drawable: a #GdkDrawable
350  * 
351  * Computes the region of a drawable that is potentially visible.
352  * This does not necessarily take into account if the window is
353  * obscured by other windows, but no area outside of this region
354  * is visible.
355  * 
356  * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
357  *          when you are done.
358  **/
359 cairo_region_t *
360 gdk_drawable_get_visible_region (GdkDrawable *drawable)
361 {
362   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
363
364   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visible_region (drawable);
365 }
366
367 static cairo_region_t *
368 gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
369 {
370   GdkRectangle rect;
371
372   rect.x = 0;
373   rect.y = 0;
374
375   gdk_drawable_get_size (drawable, &rect.width, &rect.height);
376
377   return cairo_region_create_rectangle (&rect);
378 }
379
380 /**
381  * _gdk_drawable_ref_cairo_surface:
382  * @drawable: a #GdkDrawable
383  * 
384  * Obtains a #cairo_surface_t for the given drawable. If a
385  * #cairo_surface_t for the drawable already exists, it will be
386  * referenced, otherwise a new surface will be created.
387  * 
388  * Return value: a newly referenced #cairo_surface_t that points
389  *  to @drawable. Unref with cairo_surface_destroy()
390  **/
391 cairo_surface_t *
392 _gdk_drawable_ref_cairo_surface (GdkDrawable *drawable)
393 {
394   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
395
396   return GDK_DRAWABLE_GET_CLASS (drawable)->ref_cairo_surface (drawable);
397 }
398
399 /* Implementation of the old vfunc in terms of the new one
400    in case someone calls it directly (which they shouldn't!) */
401 static void
402 gdk_drawable_real_draw_drawable (GdkDrawable  *drawable,
403                                  GdkGC         *gc,
404                                  GdkDrawable  *src,
405                                  gint           xsrc,
406                                  gint           ysrc,
407                                  gint           xdest,
408                                  gint           ydest,
409                                  gint           width,
410                                  gint           height)
411 {
412   GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src (drawable,
413                                                              gc,
414                                                              src,
415                                                              xsrc,
416                                                              ysrc,
417                                                              xdest,
418                                                              ydest,
419                                                              width,
420                                                              height,
421                                                              src);
422 }
423
424 /************************************************************************/
425
426 /**
427  * _gdk_drawable_get_scratch_gc:
428  * @drawable: A #GdkDrawable
429  * @graphics_exposures: Whether the returned #GdkGC should generate graphics exposures 
430  * 
431  * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has
432  * the standard values for @drawable, except for the graphics_exposures
433  * field which is determined by the @graphics_exposures parameter.
434  *
435  * The foreground color of the returned #GdkGC is undefined. The #GdkGC
436  * must not be altered in any way, except to change its foreground color.
437  * 
438  * Return value: A #GdkGC suitable for drawing on @drawable
439  * 
440  * Since: 2.4
441  **/
442 GdkGC *
443 _gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
444                               gboolean     graphics_exposures)
445 {
446   GdkScreen *screen;
447   gint depth;
448
449   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
450
451   screen = gdk_drawable_get_screen (drawable);
452
453   g_return_val_if_fail (!screen->closed, NULL);
454
455   depth = gdk_drawable_get_depth (drawable) - 1;
456
457   if (graphics_exposures)
458     {
459       if (!screen->exposure_gcs[depth])
460         {
461           GdkGCValues values;
462           GdkGCValuesMask mask;
463
464           values.graphics_exposures = TRUE;
465           mask = GDK_GC_EXPOSURES;  
466
467           screen->exposure_gcs[depth] =
468             gdk_gc_new_with_values (drawable, &values, mask);
469         }
470
471       return screen->exposure_gcs[depth];
472     }
473   else
474     {
475       if (!screen->normal_gcs[depth])
476         {
477           screen->normal_gcs[depth] =
478             gdk_gc_new (drawable);
479         }
480
481       return screen->normal_gcs[depth];
482     }
483 }
484
485 /**
486  * _gdk_drawable_get_subwindow_scratch_gc:
487  * @drawable: A #GdkDrawable
488  * 
489  * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has
490  * the standard values for @drawable, except for the graphics_exposures
491  * field which is %TRUE and the subwindow mode which is %GDK_INCLUDE_INFERIORS.
492  *
493  * The foreground color of the returned #GdkGC is undefined. The #GdkGC
494  * must not be altered in any way, except to change its foreground color.
495  * 
496  * Return value: A #GdkGC suitable for drawing on @drawable
497  * 
498  * Since: 2.18
499  **/
500 GdkGC *
501 _gdk_drawable_get_subwindow_scratch_gc (GdkDrawable *drawable)
502 {
503   GdkScreen *screen;
504   gint depth;
505
506   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
507
508   screen = gdk_drawable_get_screen (drawable);
509
510   g_return_val_if_fail (!screen->closed, NULL);
511
512   depth = gdk_drawable_get_depth (drawable) - 1;
513
514   if (!screen->subwindow_gcs[depth])
515     {
516       GdkGCValues values;
517       GdkGCValuesMask mask;
518       
519       values.graphics_exposures = TRUE;
520       values.subwindow_mode = GDK_INCLUDE_INFERIORS;
521       mask = GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW;  
522       
523       screen->subwindow_gcs[depth] =
524         gdk_gc_new_with_values (drawable, &values, mask);
525     }
526   
527   return screen->subwindow_gcs[depth];
528 }
529
530
531 /*
532  * _gdk_drawable_get_source_drawable:
533  * @drawable: a #GdkDrawable
534  *
535  * Returns a drawable for the passed @drawable that is guaranteed to be
536  * usable to create a pixmap (e.g.: not an offscreen window).
537  *
538  * Since: 2.16
539  */
540 GdkDrawable *
541 _gdk_drawable_get_source_drawable (GdkDrawable *drawable)
542 {
543   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
544
545   if (GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable)
546     return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable);
547
548   return drawable;
549 }
550
551 cairo_surface_t *
552 _gdk_drawable_create_cairo_surface (GdkDrawable *drawable,
553                                     int width,
554                                     int height)
555 {
556   return GDK_DRAWABLE_GET_CLASS (drawable)->create_cairo_surface (drawable,
557                                                                   width, height);
558 }