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