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

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