1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
29 #include <sys/types.h>
31 #include "gdk.h" /* For gdk_flush() */
33 #include "gdkprivate.h"
34 #include "gdkinternals.h" /* For scratch_image code */
41 * Deprecated function; use g_object_ref() instead.
43 * Return value: the image
45 * Deprecated: 2.0: Use g_object_ref() instead.
48 gdk_image_ref (GdkImage *image)
50 g_return_val_if_fail (GDK_IS_IMAGE (image), NULL);
52 return g_object_ref (image);
59 * Deprecated function; use g_object_unref() instead.
61 * Deprecated: 2.0: Use g_object_unref() instead.
64 gdk_image_unref (GdkImage *image)
66 g_return_if_fail (GDK_IS_IMAGE (image));
68 g_object_unref (image);
73 * @drawable: a #GdkDrawable
74 * @x: x coordinate in @window
75 * @y: y coordinate in @window
76 * @width: width of area in @window
77 * @height: height of area in @window
79 * This is a deprecated wrapper for gdk_drawable_get_image();
80 * gdk_drawable_get_image() should be used instead. Or even better: in
81 * most cases gdk_pixbuf_get_from_drawable() is the most convenient
84 * Return value: a new #GdkImage or %NULL
87 gdk_image_get (GdkWindow *drawable,
93 g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
94 g_return_val_if_fail (x >= 0, NULL);
95 g_return_val_if_fail (y >= 0, NULL);
96 g_return_val_if_fail (width >= 0, NULL);
97 g_return_val_if_fail (height >= 0, NULL);
99 return gdk_drawable_get_image (drawable, x, y, width, height);
103 * gdk_image_set_colormap:
104 * @image: a #GdkImage
105 * @colormap: a #GdkColormap
107 * Sets the colormap for the image to the given colormap. Normally
108 * there's no need to use this function, images are created with the
109 * correct colormap if you get the image from a drawable. If you
110 * create the image from scratch, use the colormap of the drawable you
111 * intend to render the image to.
114 gdk_image_set_colormap (GdkImage *image,
115 GdkColormap *colormap)
117 g_return_if_fail (GDK_IS_IMAGE (image));
118 g_return_if_fail (GDK_IS_COLORMAP (colormap));
120 if (image->colormap != colormap)
123 g_object_unref (image->colormap);
125 image->colormap = colormap;
126 g_object_ref (image->colormap);
131 * gdk_image_get_colormap:
132 * @image: a #GdkImage
134 * Retrieves the colormap for a given image, if it exists. An image
135 * will have a colormap if the drawable from which it was created has
136 * a colormap, or if a colormap was set explicitely with
137 * gdk_image_set_colormap().
139 * Return value: colormap for the image
142 gdk_image_get_colormap (GdkImage *image)
144 g_return_val_if_fail (GDK_IS_IMAGE (image), NULL);
146 return image->colormap;
149 /* We have N_REGION GDK_SCRATCH_IMAGE_WIDTH x GDK_SCRATCH_IMAGE_HEIGHT regions divided
150 * up between n_images different images. possible_n_images gives
151 * various divisors of N_REGIONS. The reason for allowing this
152 * flexibility is that we want to create as few images as possible,
153 * but we want to deal with the abberant systems that have a SHMMAX
156 * GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT * N_REGIONS * 4 (384k)
158 * (Are there any such?)
161 static const int possible_n_images[] = { 1, 2, 3, 6 };
163 /* We allocate one GdkScratchImageInfo structure for each
164 * depth where we are allocating scratch images. (Future: one
165 * per depth, per display)
167 typedef struct _GdkScratchImageInfo GdkScratchImageInfo;
169 struct _GdkScratchImageInfo {
173 GdkImage *static_image[N_REGIONS];
174 gint static_image_idx;
176 /* In order to optimize filling fractions, we simultaneously fill in up
177 * to three regions of size GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT: one
178 * for images that are taller than GDK_SCRATCH_IMAGE_HEIGHT / 2, and must
179 * be tiled horizontally. One for images that are wider than
180 * GDK_SCRATCH_IMAGE_WIDTH / 2 and must be tiled vertically, and a third
181 * for images smaller than GDK_SCRATCH_IMAGE_HEIGHT / 2 x GDK_SCRATCH_IMAGE_WIDTH x 2
182 * that we tile in horizontal rows.
189 /* tile_y1 and tile_y2 define the horizontal band into
190 * which we are tiling images. tile_x is the x extent to
191 * which that is filled
201 static GSList *scratch_image_infos = NULL;
204 allocate_scratch_images (GdkScratchImageInfo *info,
210 for (i = 0; i < n_images; i++)
212 info->static_image[i] = _gdk_image_new_for_depth (info->screen,
213 shared ? GDK_IMAGE_SHARED : GDK_IMAGE_NORMAL,
215 GDK_SCRATCH_IMAGE_WIDTH * (N_REGIONS / n_images),
216 GDK_SCRATCH_IMAGE_HEIGHT,
219 if (!info->static_image[i])
223 for (j = 0; j < i; j++)
224 g_object_unref (info->static_image[j]);
234 scratch_image_info_display_closed (GdkDisplay *display,
236 GdkScratchImageInfo *image_info)
240 g_signal_handlers_disconnect_by_func (display,
241 scratch_image_info_display_closed,
244 scratch_image_infos = g_slist_remove (scratch_image_infos, image_info);
246 for (i = 0; i < image_info->n_images; i++)
247 g_object_unref (image_info->static_image[i]);
252 static GdkScratchImageInfo *
253 scratch_image_info_for_depth (GdkScreen *screen,
257 GdkScratchImageInfo *image_info;
260 tmp_list = scratch_image_infos;
263 image_info = tmp_list->data;
264 if (image_info->depth == depth && image_info->screen == screen)
267 tmp_list = tmp_list->next;
270 image_info = g_new (GdkScratchImageInfo, 1);
272 image_info->depth = depth;
273 image_info->screen = screen;
275 g_signal_connect (gdk_screen_get_display (screen), "closed",
276 G_CALLBACK (scratch_image_info_display_closed),
279 /* Try to allocate as few possible shared images */
280 for (i=0; i < G_N_ELEMENTS (possible_n_images); i++)
282 if (allocate_scratch_images (image_info, possible_n_images[i], TRUE))
284 image_info->n_images = possible_n_images[i];
289 /* If that fails, just allocate N_REGIONS normal images */
290 if (i == G_N_ELEMENTS (possible_n_images))
292 allocate_scratch_images (image_info, N_REGIONS, FALSE);
293 image_info->n_images = N_REGIONS;
296 image_info->static_image_idx = 0;
298 image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT;
299 image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH;
300 image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH;
301 image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT;
303 scratch_image_infos = g_slist_prepend (scratch_image_infos, image_info);
308 /* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
309 for performance evaluation. */
314 static gint sincelast;
318 alloc_scratch_image (GdkScratchImageInfo *image_info)
320 if (image_info->static_image_idx == N_REGIONS)
326 g_print ("flush, %d puts since last flush\n", sincelast);
329 image_info->static_image_idx = 0;
331 /* Mark all regions that we might be filling in as completely
332 * full, to force new tiles to be allocated for subsequent
335 image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT;
336 image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH;
337 image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH;
338 image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT;
340 return image_info->static_image_idx++;
344 * _gdk_image_get_scratch:
345 * @screen: a #GdkScreen
346 * @width: desired width
347 * @height: desired height
348 * @depth: depth of image
349 * @x: X location within returned image of scratch image
350 * @y: Y location within returned image of scratch image
352 * Allocates an image of size width/height, up to a maximum
353 * of GDK_SCRATCH_IMAGE_WIDTHxGDK_SCRATCH_IMAGE_HEIGHT that is
354 * suitable to use on @screen.
356 * Return value: a scratch image. This must be used by a
357 * call to gdk_image_put() before any other calls to
358 * _gdk_image_get_scratch()
361 _gdk_image_get_scratch (GdkScreen *screen,
368 GdkScratchImageInfo *image_info;
372 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
374 image_info = scratch_image_info_for_depth (screen, depth);
376 if (width >= (GDK_SCRATCH_IMAGE_WIDTH >> 1))
378 if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1))
380 idx = alloc_scratch_image (image_info);
386 if (height + image_info->horiz_y > GDK_SCRATCH_IMAGE_HEIGHT)
388 image_info->horiz_idx = alloc_scratch_image (image_info);
389 image_info->horiz_y = 0;
391 idx = image_info->horiz_idx;
393 *y = image_info->horiz_y;
394 image_info->horiz_y += height;
399 if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1))
401 if (width + image_info->vert_x > GDK_SCRATCH_IMAGE_WIDTH)
403 image_info->vert_idx = alloc_scratch_image (image_info);
404 image_info->vert_x = 0;
406 idx = image_info->vert_idx;
407 *x = image_info->vert_x;
409 /* using 3 and -4 would be slightly more efficient on 32-bit machines
410 with > 1bpp displays */
411 image_info->vert_x += (width + 7) & -8;
415 if (width + image_info->tile_x > GDK_SCRATCH_IMAGE_WIDTH)
417 image_info->tile_y1 = image_info->tile_y2;
418 image_info->tile_x = 0;
420 if (height + image_info->tile_y1 > GDK_SCRATCH_IMAGE_HEIGHT)
422 image_info->tile_idx = alloc_scratch_image (image_info);
423 image_info->tile_x = 0;
424 image_info->tile_y1 = 0;
425 image_info->tile_y2 = 0;
427 if (height + image_info->tile_y1 > image_info->tile_y2)
428 image_info->tile_y2 = height + image_info->tile_y1;
429 idx = image_info->tile_idx;
430 *x = image_info->tile_x;
431 *y = image_info->tile_y1;
432 image_info->tile_x += (width + 7) & -8;
435 image = image_info->static_image[idx * image_info->n_images / N_REGIONS];
436 *x += GDK_SCRATCH_IMAGE_WIDTH * (idx % (N_REGIONS / image_info->n_images));
438 g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x, *y, width, height);
445 gdk_image_new (GdkImageType type,
450 return _gdk_image_new_for_depth (gdk_visual_get_screen (visual), type,
451 visual, width, height, -1);
454 #define __GDK_IMAGE_C__
455 #include "gdkaliasdef.c"