source: trunk/third/gtk/gdk/gdkimage.c @ 15781

Revision 15781, 12.6 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15780, which included commits to RCS files with non-trunk default branches.
Line 
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 Library 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 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library 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-1999.  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
29#include <errno.h>
30#include <stdlib.h>
31#include <sys/types.h>
32
33#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
34#define USE_SHM
35#endif
36
37#ifdef USE_SHM
38#include <sys/ipc.h>
39#include <sys/shm.h>
40#endif /* USE_SHM */
41
42#include <X11/Xlib.h>
43#include <X11/Xutil.h>
44
45#ifdef USE_SHM
46#include <X11/extensions/XShm.h>
47#endif /* USE_SHM */
48
49#include "gdk.h"
50#include "gdkprivate.h"
51
52
53static void gdk_image_put_normal (GdkDrawable *drawable,
54                                  GdkGC       *gc,
55                                  GdkImage    *image,
56                                  gint         xsrc,
57                                  gint         ysrc,
58                                  gint         xdest,
59                                  gint         ydest,
60                                  gint         width,
61                                  gint         height);
62static void gdk_image_put_shared (GdkDrawable *drawable,
63                                  GdkGC       *gc,
64                                  GdkImage    *image,
65                                  gint         xsrc,
66                                  gint         ysrc,
67                                  gint         xdest,
68                                  gint         ydest,
69                                  gint         width,
70                                  gint         height);
71
72
73static GList *image_list = NULL;
74
75
76void
77gdk_image_exit (void)
78{
79  GdkImage *image;
80
81  while (image_list)
82    {
83      image = image_list->data;
84      gdk_image_destroy (image);
85    }
86}
87
88GdkImage *
89gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h)
90/*
91 * Desc: create a new bitmap image
92 */
93{
94        Visual *xvisual;
95        GdkImage *image;
96        GdkImagePrivate *private;
97        private = g_new(GdkImagePrivate, 1);
98        image = (GdkImage *) private;
99        private->xdisplay = gdk_display;
100        private->image_put = gdk_image_put_normal;
101        image->type = GDK_IMAGE_NORMAL;
102        image->visual = visual;
103        image->width = w;
104        image->height = h;
105        image->depth = 1;
106        xvisual = ((GdkVisualPrivate*) visual)->xvisual;
107        private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap,
108                                       0, 0, w ,h, 8, 0);
109        private->ximage->data = data;
110        private->ximage->bitmap_bit_order = MSBFirst;
111        private->ximage->byte_order = MSBFirst;
112        image->byte_order = MSBFirst;
113        image->mem =  private->ximage->data;
114        image->bpl = private->ximage->bytes_per_line;
115        image->bpp = 1;
116        return(image);
117} /* gdk_image_new_bitmap() */
118
119static int
120gdk_image_check_xshm(Display *display)
121/*
122 * Desc: query the server for support for the MIT_SHM extension
123 * Return:  0 = not available
124 *          1 = shared XImage support available
125 *          2 = shared Pixmap support available also
126 */
127{
128#ifdef USE_SHM
129  int major, minor, ignore;
130  Bool pixmaps;
131 
132  if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore))
133    {
134      if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True)
135        {
136          return (pixmaps==True) ? 2 : 1;
137        }
138    }
139#endif /* USE_SHM */
140  return 0;
141}
142
143void
144gdk_image_init (void)
145{
146  if (gdk_use_xshm)
147    {
148      if (!gdk_image_check_xshm (gdk_display))
149        {
150          gdk_use_xshm = False;
151        }
152    }
153}
154
155GdkImage*
156gdk_image_new (GdkImageType  type,
157               GdkVisual    *visual,
158               gint          width,
159               gint          height)
160{
161  GdkImage *image;
162  GdkImagePrivate *private;
163#ifdef USE_SHM
164  XShmSegmentInfo *x_shm_info;
165#endif /* USE_SHM */
166  Visual *xvisual;
167
168  switch (type)
169    {
170    case GDK_IMAGE_FASTEST:
171      image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height);
172
173      if (!image)
174        image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height);
175      break;
176
177    default:
178      private = g_new (GdkImagePrivate, 1);
179      image = (GdkImage*) private;
180
181      private->xdisplay = gdk_display;
182      private->image_put = NULL;
183
184      image->type = type;
185      image->visual = visual;
186      image->width = width;
187      image->height = height;
188      image->depth = visual->depth;
189
190      xvisual = ((GdkVisualPrivate*) visual)->xvisual;
191
192      switch (type)
193        {
194        case GDK_IMAGE_SHARED:
195#ifdef USE_SHM
196          if (gdk_use_xshm)
197            {
198              private->image_put = gdk_image_put_shared;
199
200              private->x_shm_info = g_new (XShmSegmentInfo, 1);
201              x_shm_info = private->x_shm_info;
202
203              private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth,
204                                                 ZPixmap, NULL, x_shm_info, width, height);
205              if (private->ximage == NULL)
206                {
207                  g_warning ("XShmCreateImage failed");
208                 
209                  g_free (image);
210                  gdk_use_xshm = False;
211                  return NULL;
212                }
213
214              x_shm_info->shmid = shmget (IPC_PRIVATE,
215                                          private->ximage->bytes_per_line * private->ximage->height,
216                                          IPC_CREAT | 0777);
217
218              if (x_shm_info->shmid == -1)
219                {
220                  /* EINVAL indicates, most likely, that the segment we asked for
221                   * is bigger than SHMMAX, so we don't treat it as a permanent
222                   * error. ENOSPC and ENOMEM may also indicate this, but
223                   * more likely are permanent errors.
224                   */
225                  if (errno != EINVAL)
226                    {
227                      g_warning ("shmget failed: error %d (%s)", errno, g_strerror (errno));
228                      gdk_use_xshm = False;
229                    }
230
231                  XDestroyImage (private->ximage);
232                  g_free (private->x_shm_info);
233                  g_free (image);
234
235                  return NULL;
236                }
237
238              x_shm_info->readOnly = False;
239              x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0);
240              private->ximage->data = x_shm_info->shmaddr;
241
242              if (x_shm_info->shmaddr == (char*) -1)
243                {
244                  g_warning ("shmat failed: error %d (%s)", errno, g_strerror (errno));
245
246                  XDestroyImage (private->ximage);
247                  shmctl (x_shm_info->shmid, IPC_RMID, 0);
248
249                  g_free (private->x_shm_info);
250                  g_free (image);
251
252                  /* Failure in shmat is almost certainly permanent. Most likely error is
253                   * EMFILE, which would mean that we've exceeded the per-process
254                   * Shm segment limit.
255                   */
256                  gdk_use_xshm = False;
257                 
258                  return NULL;
259                }
260
261              gdk_error_trap_push ();
262
263              XShmAttach (private->xdisplay, x_shm_info);
264              XSync (private->xdisplay, False);
265
266              if (gdk_error_trap_pop ())
267                {
268                  /* this is the common failure case so omit warning */
269                  XDestroyImage (private->ximage);
270                  shmdt (x_shm_info->shmaddr);
271                  shmctl (x_shm_info->shmid, IPC_RMID, 0);
272                 
273                  g_free (private->x_shm_info);
274                  g_free (image);
275
276                  gdk_use_xshm = False;
277
278                  return NULL;
279                }
280             
281              /* We mark the segment as destroyed so that when
282               * the last process detaches, it will be deleted.
283               * There is a small possibility of leaking if
284               * we die in XShmAttach. In theory, a signal handler
285               * could be set up.
286               */
287              shmctl (x_shm_info->shmid, IPC_RMID, 0);               
288
289              if (image)
290                image_list = g_list_prepend (image_list, image);
291            }
292          else
293            {
294              g_free (image);
295              return NULL;
296            }
297          break;
298#else /* USE_SHM */
299          g_free (image);
300          return NULL;
301#endif /* USE_SHM */
302        case GDK_IMAGE_NORMAL:
303          private->image_put = gdk_image_put_normal;
304
305          private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth,
306                                          ZPixmap, 0, 0, width, height, 32, 0);
307
308          /* Use malloc, not g_malloc here, because X will call free()
309           * on this data
310           */
311          private->ximage->data = malloc (private->ximage->bytes_per_line *
312                                          private->ximage->height);
313          break;
314
315        case GDK_IMAGE_FASTEST:
316          g_assert_not_reached ();
317        }
318
319      if (image)
320        {
321          image->byte_order = private->ximage->byte_order;
322          image->mem = private->ximage->data;
323          image->bpl = private->ximage->bytes_per_line;
324          image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
325        }
326    }
327
328  return image;
329}
330
331GdkImage*
332gdk_image_get (GdkWindow *window,
333               gint       x,
334               gint       y,
335               gint       width,
336               gint       height)
337{
338  GdkImage *image;
339  GdkImagePrivate *private;
340  GdkWindowPrivate *win_private;
341  XImage *ximage;
342
343  g_return_val_if_fail (window != NULL, NULL);
344
345  win_private = (GdkWindowPrivate *) window;
346  if (win_private->destroyed)
347    return NULL;
348
349  ximage = XGetImage (gdk_display,
350                      win_private->xwindow,
351                      x, y, width, height,
352                      AllPlanes, ZPixmap);
353 
354  if (ximage == NULL)
355    return NULL;
356 
357  private = g_new (GdkImagePrivate, 1);
358  image = (GdkImage*) private;
359
360  private->xdisplay = gdk_display;
361  private->image_put = gdk_image_put_normal;
362  private->ximage = ximage;
363  image->type = GDK_IMAGE_NORMAL;
364  image->visual = gdk_window_get_visual (window);
365  image->width = width;
366  image->height = height;
367  image->depth = private->ximage->depth;
368
369  image->mem = private->ximage->data;
370  image->bpl = private->ximage->bytes_per_line;
371  image->bpp = private->ximage->bits_per_pixel;
372  image->byte_order = private->ximage->byte_order;
373
374  return image;
375}
376
377guint32
378gdk_image_get_pixel (GdkImage *image,
379                     gint x,
380                     gint y)
381{
382  guint32 pixel;
383  GdkImagePrivate *private;
384
385  g_return_val_if_fail (image != NULL, 0);
386
387  private = (GdkImagePrivate *) image;
388
389  pixel = XGetPixel (private->ximage, x, y);
390
391  return pixel;
392}
393
394void
395gdk_image_put_pixel (GdkImage *image,
396                     gint x,
397                     gint y,
398                     guint32 pixel)
399{
400  GdkImagePrivate *private;
401
402  g_return_if_fail (image != NULL);
403
404  private = (GdkImagePrivate *) image;
405
406  pixel = XPutPixel (private->ximage, x, y, pixel);
407}
408
409void
410gdk_image_destroy (GdkImage *image)
411{
412  GdkImagePrivate *private;
413#ifdef USE_SHM
414  XShmSegmentInfo *x_shm_info;
415#endif /* USE_SHM */
416
417  g_return_if_fail (image != NULL);
418
419  private = (GdkImagePrivate*) image;
420  switch (image->type)
421    {
422    case GDK_IMAGE_NORMAL:
423      XDestroyImage (private->ximage);
424      break;
425
426    case GDK_IMAGE_SHARED:
427#ifdef USE_SHM
428      gdk_flush();
429
430      XShmDetach (private->xdisplay, private->x_shm_info);
431      XDestroyImage (private->ximage);
432
433      x_shm_info = private->x_shm_info;
434      shmdt (x_shm_info->shmaddr);
435     
436      g_free (private->x_shm_info);
437
438      image_list = g_list_remove (image_list, image);
439#else /* USE_SHM */
440      g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
441#endif /* USE_SHM */
442      break;
443
444    case GDK_IMAGE_FASTEST:
445      g_assert_not_reached ();
446    }
447
448  g_free (image);
449}
450
451static void
452gdk_image_put_normal (GdkDrawable *drawable,
453                      GdkGC       *gc,
454                      GdkImage    *image,
455                      gint         xsrc,
456                      gint         ysrc,
457                      gint         xdest,
458                      gint         ydest,
459                      gint         width,
460                      gint         height)
461{
462  GdkWindowPrivate *drawable_private;
463  GdkImagePrivate *image_private;
464  GdkGCPrivate *gc_private;
465
466  g_return_if_fail (drawable != NULL);
467  g_return_if_fail (image != NULL);
468  g_return_if_fail (gc != NULL);
469
470  drawable_private = (GdkWindowPrivate*) drawable;
471  if (drawable_private->destroyed)
472    return;
473  image_private = (GdkImagePrivate*) image;
474  gc_private = (GdkGCPrivate*) gc;
475
476  g_return_if_fail (image->type == GDK_IMAGE_NORMAL);
477
478  XPutImage (drawable_private->xdisplay, drawable_private->xwindow,
479             gc_private->xgc, image_private->ximage,
480             xsrc, ysrc, xdest, ydest, width, height);
481}
482
483static void
484gdk_image_put_shared (GdkDrawable *drawable,
485                      GdkGC       *gc,
486                      GdkImage    *image,
487                      gint         xsrc,
488                      gint         ysrc,
489                      gint         xdest,
490                      gint         ydest,
491                      gint         width,
492                      gint         height)
493{
494#ifdef USE_SHM
495  GdkWindowPrivate *drawable_private;
496  GdkImagePrivate *image_private;
497  GdkGCPrivate *gc_private;
498
499  g_return_if_fail (drawable != NULL);
500  g_return_if_fail (image != NULL);
501  g_return_if_fail (gc != NULL);
502
503  drawable_private = (GdkWindowPrivate*) drawable;
504  if (drawable_private->destroyed)
505    return;
506  image_private = (GdkImagePrivate*) image;
507  gc_private = (GdkGCPrivate*) gc;
508
509  g_return_if_fail (image->type == GDK_IMAGE_SHARED);
510
511  XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow,
512                gc_private->xgc, image_private->ximage,
513                xsrc, ysrc, xdest, ydest, width, height, False);
514#else /* USE_SHM */
515  g_error ("trying to draw shared memory image when gdk was compiled without shared memory support");
516#endif /* USE_SHM */
517}
Note: See TracBrowser for help on using the repository browser.