aboutsummaryrefslogtreecommitdiffstats
path: root/x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11.c')
-rw-r--r--x11.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/x11.c b/x11.c
new file mode 100644
index 0000000..5aaa1d0
--- /dev/null
+++ b/x11.c
@@ -0,0 +1,456 @@
+/*
+ * some X11 ximage / pixmaps rotines
+ *
+ * (c) 1996 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * basic usage:
+ * 1) call x11_color_init()
+ * this does all the visual checking/colormap handling stuff and returns
+ * TRUECOLOR or PSEUDOCOLOR
+ * 2) create/load the image
+ * 3) call x11_create_pixmaps()
+ * For TRUECOLOR: It expects the data in one long (4 byte) per pixel.
+ * To create the long, run the rgb-values throuth the
+ * x11_lut_[red|green|blue] tables and or the results
+ * For PSEUDOCOLOR: The data is expected to be one byte per pixel,
+ * containing the results from dither_line (see dither.c)
+ * Not required to call init_dither, this is done by
+ * x11_color_init
+ * returns a pixmap.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/extensions/XShm.h>
+
+#include "x11.h"
+#include "dither.h"
+
+extern Display *dpy;
+
+#define PERROR(str) fprintf(stderr,"%s:%d: %s: %s\n",__FILE__,__LINE__,str,strerror(errno))
+
+/* ------------------------------------------------------------------------ */
+
+int display_type = 0;
+int display_depth = 0;
+XVisualInfo *info;
+
+/* PseudoColor: ditherresult => colormap-entry */
+int x11_colors;
+int x11_grays;
+unsigned long *x11_map;
+unsigned long x11_map_color[256];
+unsigned long x11_map_gray[64];
+
+unsigned long x11_red;
+unsigned long x11_green;
+unsigned long x11_blue;
+
+int have_shmem = 0;
+
+/*
+ * - xv uses 4:8:4 for truecolor images.
+ * - The GIMP 0.99.9 uses 6:6:4, but the 6 intervals for red+green are
+ * choosen somehow wired :-(
+ * - ImageMagick tries to optimize the palette for each image individual
+ */
+static int try_red[] = {4, 6, 6, 5, 4};
+static int try_green[] = {8, 6, 6, 5, 4};
+static int try_blue[] = {4, 6, 4, 5, 4};
+
+/* TrueColor: r,g,b => X11-color */
+unsigned long x11_lut_red[256];
+unsigned long x11_lut_green[256];
+unsigned long x11_lut_blue[256];
+unsigned long x11_lut_gray[256];
+
+static int
+x11_alloc_grays(Display * dpy, Colormap cmap, unsigned long *colors, int gray)
+{
+ XColor akt_color;
+ int i;
+
+ for (i = 0; i < gray; i++) {
+ akt_color.red = i * 65535 / (gray - 1);
+ akt_color.green = i * 65535 / (gray - 1);
+ akt_color.blue = i * 65535 / (gray - 1);
+
+ if (!XAllocColor(dpy, cmap, &akt_color)) {
+ /* failed, free them */
+ XFreeColors(dpy, cmap, colors, i, 0);
+ return 1;
+ }
+ colors[i] = akt_color.pixel;
+#if 0
+ fprintf(stderr, "%2lx: %04x %04x %04x\n",
+ akt_color.pixel,akt_color.red,akt_color.green,akt_color.red);
+#endif
+ }
+ return 0;
+}
+
+static int
+x11_alloc_colorcube(Display * dpy, Colormap cmap, unsigned long *colors,
+ int red, int green, int blue)
+{
+ XColor akt_color;
+ int i;
+
+ for (i = 0; i < red * green * blue; i++) {
+ akt_color.red = ((i / (green * blue)) % red) * 65535 / (red - 1);
+ akt_color.green = ((i / blue) % green) * 65535 / (green - 1);
+ akt_color.blue = (i % blue) * 65535 / (blue - 1);
+#if 0
+ fprintf(stderr, "%04x %04x %04x\n",
+ akt_color.red, akt_color.green, akt_color.red);
+#endif
+
+ if (!XAllocColor(dpy, cmap, &akt_color)) {
+ /* failed, free them */
+ XFreeColors(dpy, cmap, colors, i, 0);
+ return 1;
+ }
+ colors[i] = akt_color.pixel;
+ }
+ return 0;
+}
+
+static unsigned long
+x11_alloc_color(Display * dpy, Colormap cmap, int red, int green, int blue)
+{
+ XColor akt_color;
+
+ akt_color.red = red;
+ akt_color.green = green;
+ akt_color.blue = blue;
+
+ XAllocColor(dpy, cmap, &akt_color);
+ return akt_color.pixel;
+}
+
+static void
+x11_create_lut(unsigned long red_mask,
+ unsigned long green_mask,
+ unsigned long blue_mask)
+{
+ int rgb_red_bits = 0;
+ int rgb_red_shift = 0;
+ int rgb_green_bits = 0;
+ int rgb_green_shift = 0;
+ int rgb_blue_bits = 0;
+ int rgb_blue_shift = 0;
+ int i;
+ unsigned long mask;
+
+ for (i = 0; i < 24; i++) {
+ mask = (1 << i);
+ if (red_mask & mask)
+ rgb_red_bits++;
+ else if (!rgb_red_bits)
+ rgb_red_shift++;
+ if (green_mask & mask)
+ rgb_green_bits++;
+ else if (!rgb_green_bits)
+ rgb_green_shift++;
+ if (blue_mask & mask)
+ rgb_blue_bits++;
+ else if (!rgb_blue_bits)
+ rgb_blue_shift++;
+ }
+#if 0
+ printf("color: bits shift\n");
+ printf("red : %04i %05i\n", rgb_red_bits, rgb_red_shift);
+ printf("green: %04i %05i\n", rgb_green_bits, rgb_green_shift);
+ printf("blue : %04i %05i\n", rgb_blue_bits, rgb_blue_shift);
+#endif
+
+ for (i = 0; i < 256; i++) {
+ x11_lut_red[i] = (i >> (8 - rgb_red_bits)) << rgb_red_shift;
+ x11_lut_green[i] = (i >> (8 - rgb_green_bits)) << rgb_green_shift;
+ x11_lut_blue[i] = (i >> (8 - rgb_blue_bits)) << rgb_blue_shift;
+ x11_lut_gray[i] =
+ x11_lut_red[i] | x11_lut_green[i] | x11_lut_blue[i];
+ }
+}
+
+int
+x11_color_init(Widget shell, int *gray)
+{
+ Screen *scr;
+ Colormap cmap;
+ XVisualInfo template;
+ unsigned int found, i;
+
+ scr = XtScreen(shell);
+ cmap = DefaultColormapOfScreen(scr);
+ if (0 == x11_grays)
+ x11_grays = 8;
+
+ /* Ask for visual type */
+ template.screen = XDefaultScreen(dpy);
+ template.visualid =
+ XVisualIDFromVisual(DefaultVisualOfScreen(scr));
+ info = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &template,
+ &found);
+ if (XShmQueryExtension(dpy)) {
+ have_shmem = 1;
+ }
+
+ /* display_depth = (info->depth+7)/8; */
+ if (info->class == TrueColor) {
+ /* TrueColor */
+ *gray = 0; /* XXX testing... */
+ display_depth = 4;
+ display_type = TRUECOLOR;
+ x11_create_lut(info->red_mask, info->green_mask, info->blue_mask);
+ x11_black = x11_alloc_color(dpy, cmap, 0, 0, 0);
+ x11_gray = x11_alloc_color(dpy, cmap, 0xc400, 0xc400, 0xc400);
+ x11_lightgray = x11_alloc_color(dpy, cmap, 0xe000, 0xe000, 0xe000);
+ x11_white = x11_alloc_color(dpy, cmap, 0xffff, 0xffff, 0xffff);
+ } else if (info->class == PseudoColor && info->depth == 8) {
+ /* 8bit PseudoColor */
+ display_depth = 1;
+ display_type = PSEUDOCOLOR;
+ if (0 != x11_alloc_grays(dpy, cmap, x11_map_gray, x11_grays)) {
+ fprintf(stderr, "sorry, can't allocate %d grays\n", x11_grays);
+ exit(1);
+ }
+ if (!*gray) {
+ for (i = 0; i < sizeof(try_red) / sizeof(int); i++) {
+ if (0 == x11_alloc_colorcube
+ (dpy, cmap, x11_map_color,
+ try_red[i], try_green[i], try_blue[i])) {
+ x11_colors = try_red[i] * try_green[i] * try_blue[i];
+ init_dither(try_red[i], try_green[i], try_blue[i], x11_grays);
+ break;
+ }
+ }
+ if (i == sizeof(try_red) / sizeof(int)) {
+ *gray = 1;
+ fprintf(stderr, "failed to allocate enouth colors, "
+ "using grayscaled\n");
+ }
+ }
+ if (*gray)
+ init_dither(2, 2, 2, x11_grays);
+ } else if (info->class == StaticGray || info->class == GrayScale) {
+ /* Grayscale */
+ display_depth = 1;
+ display_type = PSEUDOCOLOR;
+ x11_grays = 64;
+ *gray = 1;
+ init_dither(2, 2, 2, x11_grays);
+ if (0 != x11_alloc_grays(dpy, cmap, x11_map_gray, x11_grays)) {
+ fprintf(stderr, "sorry, can't allocate %d grays\n", x11_grays);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "sorry, can't handle visual\n");
+ exit(1);
+ }
+
+ /* some common colors */
+ x11_red = x11_alloc_color(dpy, cmap, 65535, 0, 0);
+ x11_green = x11_alloc_color(dpy, cmap, 0, 65535, 0);
+ x11_blue = x11_alloc_color(dpy, cmap, 0, 0, 65535);
+
+ if (*gray) {
+ x11_map = x11_map_gray;
+ dither_line = dither_line_gray;
+ } else {
+ x11_map = x11_map_color;
+ dither_line = dither_line_color;
+ }
+
+ return display_type;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mitshm_bang = 0;
+
+static int
+x11_error_dev_null(Display * dpy, XErrorEvent * event)
+{
+ mitshm_bang = 1;
+ return 0;
+}
+
+XImage*
+x11_create_ximage(Widget shell, int width, int height, void **shm)
+{
+ XImage *ximage = NULL;
+ unsigned char *ximage_data;
+ XShmSegmentInfo *shminfo = NULL;
+ XtPointer old_handler;
+ Screen *scr = XtScreen(shell);
+
+ if (have_shmem) {
+ old_handler = XSetErrorHandler(x11_error_dev_null);
+ (*shm) = shminfo = malloc(sizeof(XShmSegmentInfo));
+ memset(shminfo, 0, sizeof(XShmSegmentInfo));
+ ximage = XShmCreateImage(dpy,
+ DefaultVisualOfScreen(scr),
+ DefaultDepthOfScreen(scr),
+ ZPixmap, NULL,
+ shminfo, width, height);
+ if (ximage) {
+ shminfo->shmid = shmget(IPC_PRIVATE,
+ ximage->bytes_per_line * ximage->height,
+ IPC_CREAT | 0777);
+ if (-1 == shminfo->shmid) {
+ fprintf(stderr,"shmget(%dMB): %s\n",
+ ximage->bytes_per_line * ximage->height / 1024 / 1024,
+ strerror(errno));
+ goto oom;
+ }
+ shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
+ if ((void *) -1 == shminfo->shmaddr) {
+ perror("shmat");
+ goto oom;
+ }
+ ximage->data = shminfo->shmaddr;
+ shminfo->readOnly = False;
+
+ XShmAttach(dpy, shminfo);
+ XSync(dpy, False);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ if (mitshm_bang) {
+ have_shmem = 0;
+ shmdt(shminfo->shmaddr);
+ free(shminfo);
+ shminfo = *shm = NULL;
+ XDestroyImage(ximage);
+ ximage = NULL;
+ }
+ } else {
+ have_shmem = 0;
+ free(shminfo);
+ shminfo = *shm = NULL;
+ }
+ XSetErrorHandler(old_handler);
+ }
+
+ if (ximage == NULL) {
+ (*shm) = NULL;
+ if (NULL == (ximage_data = malloc(width * height * display_depth))) {
+ fprintf(stderr,"Oops: out of memory\n");
+ goto oom;
+ }
+ ximage = XCreateImage(dpy,
+ DefaultVisualOfScreen(scr),
+ DefaultDepthOfScreen(scr),
+ ZPixmap, 0, ximage_data,
+ width, height,
+ 8, 0);
+ }
+ memset(ximage->data, 0, ximage->bytes_per_line * ximage->height);
+
+ return ximage;
+
+ oom:
+ if (shminfo) {
+ if (shminfo->shmid && shminfo->shmid != -1)
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ free(shminfo);
+ }
+ if (ximage)
+ XDestroyImage(ximage);
+ return NULL;
+}
+
+void
+x11_destroy_ximage(Widget shell, XImage * ximage, void *shm)
+{
+ XShmSegmentInfo *shminfo = shm;
+
+ if (shminfo) {
+ XShmDetach(dpy, shminfo);
+ XDestroyImage(ximage);
+ shmdt(shminfo->shmaddr);
+ free(shminfo);
+ } else
+ XDestroyImage(ximage);
+}
+
+Pixmap
+x11_create_pixmap(Widget shell, unsigned char *byte_data,
+ int width, int height, int gray)
+{
+ Pixmap pixmap;
+ XImage *ximage;
+ XGCValues values;
+ GC gc;
+ unsigned long *long_data = (unsigned long *) byte_data;
+ int x, y;
+ void *shm;
+ unsigned long *map = gray ? x11_map_gray : x11_map;
+
+ Screen *scr = XtScreen(shell);
+
+ pixmap = XCreatePixmap(dpy,
+ RootWindowOfScreen(scr),
+ width, height,
+ DefaultDepthOfScreen(scr));
+ gc = XCreateGC(dpy, pixmap, 0, &values);
+
+ if (NULL == (ximage = x11_create_ximage(shell, width, height, &shm))) {
+ XFreePixmap(dpy, pixmap);
+ XFreeGC(dpy, gc);
+ return 0;
+ }
+ for (y = 0; y < height; y++)
+ if (display_type == TRUECOLOR)
+ for (x = 0; x < width; x++)
+ XPutPixel(ximage, x, y, *(long_data++));
+ else
+ for (x = 0; x < width; x++)
+ XPutPixel(ximage, x, y, map[(int) (*(byte_data++))]);
+
+ XPUTIMAGE(dpy, pixmap, gc, ximage, 0, 0, 0, 0, width, height);
+
+ x11_destroy_ximage(shell, ximage, shm);
+ XFreeGC(dpy, gc);
+ return pixmap;
+}
+
+void
+x11_data_to_ximage(unsigned char *data, unsigned char *ximage,
+ int x, int y, int sy, int gray)
+{
+ unsigned long *d;
+ int i, n;
+
+ if (display_type == PSEUDOCOLOR) {
+ if (gray) {
+ for (i = 0; i < y; i++)
+ dither_line_gray(data + x * i, ximage + x * i, i + sy, x);
+ } else {
+ for (i = 0; i < y; i++)
+ dither_line(data + 3 * x * i, ximage + x * i, i + sy, x);
+ }
+ } else {
+ d = (unsigned long *) ximage;
+ if (gray) {
+ n = x * y;
+ for (i = 0; i < n; i++)
+ *(d++) = x11_lut_gray[data[i]];
+ } else {
+ n = 3 * x * y;
+ for (i = 0; i < n; i += 3)
+ *(d++) = x11_lut_red[data[i]] |
+ x11_lut_green[data[i + 1]] |
+ x11_lut_blue[data[i + 2]];
+ }
+ }
+}