/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * * Jan Hubicka (hubicka@paru.cas.cz) * Thomas Marsh (tmarsh@austin.ibm.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * Shamelessly ripped for use in xsynaesthesia */ /*#include "aconfig.h"*/ #define X11_DRIVER /*#define MITSHM*/ #ifdef X11_DRIVER #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/cursorfont.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef __FreeBSD__ #include <malloc.h> #else #include <stdlib.h> #endif #include "xlib.h" #ifdef AMIGA #define XFlush(x) while(0) #endif #undef PIXMAP #define chkalloc(n) if (!n) fprintf(stderr, "out of memory\n"), exit(-1) int xupdate_size(xdisplay * d) { int tmp; Window wtmp; int width = d->width, height = d->height; XGetGeometry(d->display, d->window, &wtmp, &tmp, &tmp, &d->width, &d->height, (unsigned int *) &tmp, (unsigned int *) &tmp); if ((int)d->width != width || (int)d->height != height) return 1; return 0; } void xflip_buffers(xdisplay * d) { d->back = d->vbuffs[d->current]; d->current ^= 1; d->vbuff = d->vbuffs[d->current]; } void draw_screen(xdisplay * d) { switch (d->image[0]->bits_per_pixel) { case 16:{ unsigned short *de; unsigned char *s; unsigned char *e; for (s = (unsigned char *) d->vbuffs[d->current], e = (unsigned char *) d->vbuffs[d->current] + (d->linewidth * d->height), de = (unsigned short *) d->data[d->current]; s < e; s += 8, de += 8) *de = d->pixels[*s], *(de + 1) = d->pixels[*(s + 1)], *(de + 2) = d->pixels[*(s + 2)], *(de + 3) = d->pixels[*(s + 3)], *(de + 4) = d->pixels[*(s + 4)], *(de + 5) = d->pixels[*(s + 5)], *(de + 6) = d->pixels[*(s + 6)], *(de + 7) = d->pixels[*(s + 7)]; s -= 8; de -= 8; for (; s < e; s++, de++) *de = d->pixels[*s]; break; } case 24:{ unsigned char *de; unsigned char *s; unsigned char *e; for (s = (unsigned char *) d->vbuffs[d->current], e = (unsigned char *) d->vbuffs[d->current] + (d->linewidth * d->height), de = (unsigned char *) d->data[d->current]; s < e; s++, de+=3) de[0] = d->pixels[*s], de[1] = d->pixels[*s]>>8, de[2] = d->pixels[*s]>>16; break; } case 32:{ unsigned long *de; unsigned char *s; unsigned char *e; for (s = (unsigned char *) d->vbuffs[d->current], e = (unsigned char *) d->vbuffs[d->current] + (d->linewidth * d->height), de = (unsigned long *) d->data[d->current]; s < e; s += 8, de += 8) *de = d->pixels[*s], *(de + 1) = d->pixels[*(s + 1)], *(de + 2) = d->pixels[*(s + 2)], *(de + 3) = d->pixels[*(s + 3)], *(de + 4) = d->pixels[*(s + 4)], *(de + 5) = d->pixels[*(s + 5)], *(de + 6) = d->pixels[*(s + 6)], *(de + 7) = d->pixels[*(s + 7)]; s -= 8; de -= 8; for (; s < e; s++, de++) *de = d->pixels[*s]; break; } } #ifdef MITSHM if (d->SharedMemFlag) { XShmPutImage(d->display, d->window, d->gc, d->image[d->current], 0, 0, 0, 0, d->width, d->height, True); XFlush(d->display); } else #endif { XPutImage(d->display, d->window, d->gc, d->image[d->current], 0, 0, 0, 0, d->width, d->height); XFlush(d->display); } d->screen_changed = 0; } #ifdef MITSHM int alloc_shm_image(xdisplay * new) { register char *ptr; int temp, size = 0, i; ptr = DisplayString(new->display); if (!ptr || (*ptr == ':') || !strncmp(ptr, "localhost:", 10) || !strncmp(ptr, "unix:", 5) || !strncmp(ptr, "local:", 6)) { new->SharedMemOption = XQueryExtension(new->display, "MIT-SHM", &temp, &temp, &temp); } else { new->SharedMemOption = False; return 0; } new->SharedMemFlag = False; #if 0 new->SharedMemOption = True; new->SharedMemFlag = False; #endif if (new->SharedMemFlag) { XShmDetach(new->display, &new->xshminfo[0]); XShmDetach(new->display, &new->xshminfo[1]); new->image[0]->data = (char *) NULL; new->image[1]->data = (char *) NULL; shmdt(new->xshminfo[0].shmaddr); shmdt(new->xshminfo[1].shmaddr); } for (i = 0; i < 2; i++) { if (new->SharedMemOption) { int mul; if (new->depth == 8) mul = 1; else if (new->depth <= 24) mul = 2; else mul = 4; new->SharedMemFlag = False; new->image[i] = XShmCreateImage(new->display, new->visual, new->depth, ZPixmap, NULL, &new->xshminfo[i], new->width, new->height * mul); if (new->image[i]) { temp = new->image[i]->bytes_per_line * new->image[i]->height; new->linewidth = new->image[i]->bytes_per_line * 8 / new->image[i]->bits_per_pixel; if (temp > size) size = temp; new->xshminfo[i].shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); if (new->xshminfo[i].shmid != -1) { new->xshminfo[i].shmaddr = (char *) shmat(new->xshminfo[i].shmid, 0, 0); if (new->xshminfo[i].shmaddr != (char *) -1) { new->image[i]->data = new->xshminfo[i].shmaddr; new->data[i] = new->vbuffs[i] = (char *) new->image[i]->data; new->xshminfo[i].readOnly = True; new->SharedMemFlag = XShmAttach(new->display, &new->xshminfo[i]); XSync(new->display, False); if (!new->SharedMemFlag) { XDestroyImage(new->image[i]); new->image[i] = (XImage *) NULL; new->SharedMemFlag = 0; return 0; } } /* Always Destroy Shared Memory Ident */ shmctl(new->xshminfo[i].shmid, IPC_RMID, 0); } if (!new->SharedMemFlag) { XDestroyImage(new->image[i]); new->image[i] = (XImage *) NULL; new->SharedMemFlag = 0; return 0; } } else { new->SharedMemFlag = 0; return 0; } } else { new->SharedMemFlag = 0; return 0; } } new->current = 0; xflip_buffers(new); return 1; } void free_shm_image(xdisplay * d) { if (d->SharedMemFlag) { XDestroyImage(d->image[0]); XDestroyImage(d->image[1]); XShmDetach(d->display, &d->xshminfo[0]); XShmDetach(d->display, &d->xshminfo[1]); shmdt(d->xshminfo[0].shmaddr); shmdt(d->xshminfo[1].shmaddr); } } #endif int alloc_image(xdisplay * d) { int i; #ifdef MITSHM if (!d->params->nomitshm && alloc_shm_image(d)) { if (d->depth != 8) { for (i = 0; i < 2; i++) d->vbuffs[i] = malloc(d->linewidth * d->height); } return 1; } #endif for (i = 0; i < 2; i++) { d->image[i] = XCreateImage(d->display, d->visual, d->depth, ZPixmap, 0, NULL, d->width, d->height, 8, 0); if (d->image[i] == NULL) { printf("Out of memory for image..exiting\n"); exit(3); } /*Add a little extra memory to catch overruns when dumping image to buffer in draw_screen*/ d->image[i]->data = malloc(d->image[i]->bytes_per_line * d->height + 32); memset(d->image[i]->data,0,d->image[i]->bytes_per_line * d->height); if (d->image[i]->data == NULL) { printf("Out of memory for image buffers..exiting\n"); exit(3); } d->data[i] = d->vbuffs[i] = (char *) d->image[i]->data; d->linewidth = d->image[i]->bytes_per_line * 8 / d->image[i]->bits_per_pixel; } if (d->depth != 8) { for (i = 0; i < 2; i++) { /* Add a little extra memory to catch overruns */ /* when dumping image to buffer in draw_screen */ d->vbuffs[i] = malloc(d->linewidth * d->height + 32); memset(d->vbuffs[i],0,d->linewidth * d->height); if (d->vbuffs[i] == NULL) { printf("Out of memory for image buffers2..exiting\n"); exit(3); } } } xflip_buffers(d); return 1; } void free_image(xdisplay * d) { if (d->depth != 8) free(d->vbuffs[0]), free(d->vbuffs[1]); #ifdef MITSHM if (d->SharedMemFlag) { free_shm_image(d); return; } #endif XDestroyImage(d->image[0]); XDestroyImage(d->image[1]); } #define MAX(x,y) ((x)>(y)?(x):(y)) xdisplay *xalloc_display(const char *s, int xHint, int yHint, int x, int y, xlibparam * params) { xdisplay *xd; Visual *defaultvisual; XVisualInfo vis; xd = (xdisplay *) calloc(sizeof(xdisplay), 1); chkalloc(xd); xd->display = XOpenDisplay((char *) NULL); if (!xd->display) { free((void *) xd); return NULL; } xd->screen = DefaultScreen(xd->display); xd->attributes = (XSetWindowAttributes *) malloc(sizeof(XSetWindowAttributes)); chkalloc(xd->attributes); xd->attributes->background_pixel = BlackPixel(xd->display, xd->screen); xd->attributes->border_pixel = BlackPixel(xd->display, xd->screen); xd->attributes->event_mask = ButtonPressMask | StructureNotifyMask | ButtonReleaseMask | ButtonMotionMask | KeyPressMask | ExposureMask | KeyReleaseMask; xd->attributes->override_redirect = False; xd->attr_mask = CWBackPixel | CWBorderPixel | CWEventMask; xd->classX = InputOutput; xd->xcolor.n = 0; xd->parent_window = RootWindow(xd->display, xd->screen); defaultvisual = DefaultVisual(xd->display, xd->screen); xd->params = params; if (!params->usedefault) { if (defaultvisual->class != PseudoColor || (!XMatchVisualInfo(xd->display, xd->screen, 8, PseudoColor, &vis) && vis.colormap_size > 128)) { xd->fixedcolormap = 1; if (!XMatchVisualInfo(xd->display, xd->screen, 15, TrueColor, &vis)) { if (!XMatchVisualInfo(xd->display, xd->screen, 16, TrueColor, &vis)) { if (!XMatchVisualInfo(xd->display, xd->screen, 32, TrueColor, &vis) && !XMatchVisualInfo(xd->display, xd->screen, 24, TrueColor, &vis)) { if (!XMatchVisualInfo(xd->display, xd->screen, 8, PseudoColor, &vis) && !XMatchVisualInfo(xd->display, xd->screen, 7, PseudoColor, &vis)) { if (!XMatchVisualInfo(xd->display, xd->screen, 8, TrueColor, &vis) && !XMatchVisualInfo(xd->display, xd->screen, 8, StaticColor, &vis) && !XMatchVisualInfo(xd->display, xd->screen, 8, StaticGray, &vis)) { printf("Display does not support PseudoColor depth 7,8,StaticColor depth 8, StaticGray depth 8, Truecolor depth 8,15,16,24 nor 32!\n"); return NULL; } else xd->truecolor = 1; } else xd->fixedcolormap = 0, xd->truecolor = 0; } else xd->truecolor = 1; } else xd->truecolor = 1; } else xd->truecolor = 1; } else { xd->truecolor = 0; } xd->depth = vis.depth; xd->visual = vis.visual; } else { /*usedefault */ vis.depth = xd->depth = DefaultDepth(xd->display, xd->screen); xd->visual = defaultvisual; switch (defaultvisual->class) { case PseudoColor: if (xd->depth <= 8) { xd->depth = 8; xd->truecolor = 0; xd->fixedcolormap = 0; } else { printf("Pseudocolor visual on unsuported depth\n"); return NULL; } break; case TrueColor: case StaticColor: case StaticGray: xd->truecolor = 1; xd->fixedcolormap = 1; if (xd->depth <= 8) xd->depth = 8; else if (xd->depth <= 16) xd->depth = 16; else if (xd->depth <= 32) xd->depth = 32; else { printf("Truecolor visual on unsuported depth\n"); return NULL; } break; default: printf("Unusuported visual\n"); break; } } /*xd->visual->map_entries = 256; */ xd->colormap = xd->defaultcolormap = DefaultColormap(xd->display, xd->screen); xd->window_name = s; xd->height = y; xd->width = x; xd->border_width = 2; xd->lastx = 0; xd->lasty = 0; xd->font_struct = (XFontStruct *) NULL; xd->window = XCreateWindow(xd->display, xd->parent_window, xHint, yHint, xd->width, xd->height, xd->border_width, vis.depth, xd->classX, xd->visual, xd->attr_mask, xd->attributes); if (!xd->fixedcolormap && params->privatecolormap) { unsigned long pixels[256]; int i; xd->colormap = XCreateColormap(xd->display, xd->window, xd->visual, AllocNone); XAllocColorCells(xd->display, xd->colormap, 1, 0, 0, pixels, MAX(xd->visual->map_entries, 256)); for (i = 0; i < 16; i++) { xd->xcolor.c[i].pixel = pixels[i]; } XQueryColors(xd->display, xd->defaultcolormap, xd->xcolor.c, 16); XStoreColors(xd->display, xd->colormap, xd->xcolor.c, 16); xd->privatecolormap = 1; } if (!xd->fixedcolormap) XSetWindowColormap(xd->display, xd->window, xd->colormap); xd->gc = XCreateGC(xd->display, xd->window, 0L, &(xd->xgcvalues)); XSetBackground(xd->display, xd->gc, BlackPixel(xd->display, xd->screen)); XSetForeground(xd->display, xd->gc, WhitePixel(xd->display, xd->screen)); XStoreName(xd->display, xd->window, xd->window_name); XMapWindow(xd->display, xd->window); #if 1 XSelectInput(xd->display, xd->window, /* ExposureMask | */ KeyPress | /* KeyRelease | */ /* ConfigureRequest | */ /* FocusChangeMask | */ StructureNotifyMask | ButtonPressMask | ButtonReleaseMask); #endif #ifdef PIXAMP xd->pixmap = XCreatePixmap(xd->display, xd->window, xd->width, xd->height, xd->depth); #endif { XColor c; Pixmap p = XCreatePixmap(xd->display, xd->window, 1,1,1); memset(&c,0,sizeof(c)); xd->cursor = XCreatePixmapCursor(xd->display, p,p, &c,&c, 0,0); /* We don't need no fancy cursor XDefineCursor(xd->display,xd->window,xd->cursor); */ XFreePixmap(xd->display, p); } return (xd); } void xsetcolor(xdisplay * d, int col) { switch (col) { case 0: XSetForeground(d->display, d->gc, BlackPixel(d->display, d->screen)); break; case 1: XSetForeground(d->display, d->gc, WhitePixel(d->display, d->screen)); break; default: if ((col - 2) > d->xcolor.n) { fprintf(stderr, "color error\n"); exit(3); } XSetForeground(d->display, d->gc, d->xcolor.c[col - 2].pixel); break; } } void xrotate_palette(xdisplay * d, int direction, unsigned char co[3][256], int ncolors) { int i, p; if (d->privatecolormap) { for (i = 0; i < d->xcolor.n; i++) { p = d->xcolor.c[i].pixel; d->xcolor.c[i].red = (int) co[0][p] * 256; d->xcolor.c[i].green = (int) co[1][p] * 256; d->xcolor.c[i].blue = (int) co[2][p] * 256; } XStoreColors(d->display, d->colormap, d->xcolor.c, d->xcolor.n); } if (d->truecolor) { unsigned long oldpixels[256]; memcpy(oldpixels, d->pixels, sizeof(oldpixels)); p = (ncolors - 1 + direction) % (ncolors - 1) + 1; for (i = 1; i < ncolors; i++) { /*this is ugly..I know */ d->pixels[i] = oldpixels[p]; p++; if (p >= ncolors) p = 1; } draw_screen(d); } } int xalloc_color(xdisplay * d, int r, int g, int b, int readwrite) { d->xcolor.n++; d->xcolor.c[d->xcolor.n - 1].flags = DoRed | DoGreen | DoBlue; d->xcolor.c[d->xcolor.n - 1].red = r; d->xcolor.c[d->xcolor.n - 1].green = g; d->xcolor.c[d->xcolor.n - 1].blue = b; d->xcolor.c[d->xcolor.n - 1].pixel = d->xcolor.n - 1; if ((readwrite && !d->fixedcolormap) || d->privatecolormap) { unsigned long cell; if (d->privatecolormap) { cell = d->xcolor.c[d->xcolor.n - 1].pixel += 16; if (d->xcolor.c[d->xcolor.n - 1].pixel >= d->visual->map_entries) { d->xcolor.n--; return (-1); } } else { if (!XAllocColorCells(d->display, d->colormap, 0, 0, 0, &cell, 1)) { d->xcolor.n--; if (d->xcolor.n <= 32) printf("Colormap is too full! close some colorfull aplications or use -private\n"); return (-1); } d->xcolor.c[d->xcolor.n - 1].pixel = cell; } XStoreColor(d->display, d->colormap, &(d->xcolor.c[d->xcolor.n - 1])); return (cell); } if (!XAllocColor(d->display, d->colormap, &(d->xcolor.c[d->xcolor.n - 1]))) { d->xcolor.n--; if (d->xcolor.n <= 32) printf("Colormap is too full! close some colorfull aplications or use -private\n"); return (-1); } d->pixels[d->xcolor.n - 1] = d->xcolor.c[d->xcolor.n - 1].pixel; return (d->depth != 8 ? d->xcolor.n - 1 : d->xcolor.c[d->xcolor.n - 1].pixel); } void xfree_colors(xdisplay * d) { unsigned long pixels[256]; int i; for (i = 0; i < d->xcolor.n; i++) pixels[i] = d->xcolor.c[i].pixel; if (!d->privatecolormap) XFreeColors(d->display, d->colormap, pixels, d->xcolor.n, 0); d->xcolor.n = 0; } void xfree_display(xdisplay * d) { XSync(d->display, 0); if (d->font_struct != (XFontStruct *) NULL) { XFreeFont(d->display, d->font_struct); } XUnmapWindow(d->display, d->window); #ifdef PIXMAP XFreePixmap(d->display, d->pixmap); #endif XDestroyWindow(d->display, d->window); XFreeCursor(d->display, d->cursor); XCloseDisplay(d->display); free((void *) d->attributes); free((void *) d); } #ifdef PIXMAP void xline(xdisplay * d, int x1, int y1, int x2, int y2) { XDrawLine(d->display, d->pixmap, d->gc, x1, y1, x2, y2); d->lastx = x2, d->lasty = y2; d->screen_changed = 1; } void xlineto(xdisplay * d, int x, int y) { XDrawLine(d->display, d->pixmap, d->gc, d->lastx, d->lasty, x, y); d->lastx = x, d->lasty = y; d->screen_changed = 1; } void xrect(xdisplay * d, int x1, int y1, int x2, int y2) { XDrawRectangle(d->display, d->pixmap, d->gc, x1, y1, (x2 - x1), (y2 - y1)); d->lastx = x2, d->lasty = y2; d->screen_changed = 1; } void xfillrect(xdisplay * d, int x1, int y1, int x2, int y2) { XFillRectangle(d->display, d->pixmap, d->gc, x1, y1, (x2 - x1), (y2 - y1)); d->lastx = x2, d->lasty = y2; d->screen_changed = 1; } void xpoint(xdisplay * d, int x, int y) { XDrawPoint(d->display, d->pixmap, d->gc, x, y); d->lastx = x, d->lasty = y; d->screen_changed = 1; } void xflush(xdisplay * d) { draw_screen(d); XFlush(d->display); } void xclear_screen(xdisplay * d) { xfillrect(d, 0, 0, d->width, d->height); d->screen_changed = 1; } #endif void xmoveto(xdisplay * d, int x, int y) { d->lastx = x, d->lasty = y; } int xsetfont(xdisplay * d, char *font_name) { if (d->font_struct != (XFontStruct *) NULL) { XFreeFont(d->display, d->font_struct); } d->font_struct = XLoadQueryFont(d->display, font_name); if (!d->font_struct) { fprintf(stderr, "could not load font: %s\n", font_name); exit(3); } return (d->font_struct->max_bounds.ascent + d->font_struct->max_bounds.descent); } void xouttext(xdisplay * d, char *string) { int sz; sz = strlen(string); XDrawImageString(d->display, d->window, d->gc, d->lastx, d->lasty, string, sz); #if 0 d->lastx += XTextWidth(d->font_struct, string, sz); d->screen_changed = 1; #endif } void xresize(xdisplay * d, XEvent * ev) { #ifdef PIXMAP XFreePixmap(d->display, d->pixmap); #endif d->width = ev->xconfigure.width; d->height = ev->xconfigure.height; #ifdef PIXMAP d->pixmap = XCreatePixmap(d->display, d->window, d->width, d->height, d->depth); #endif } #ifdef PIXMAP void xarc(xdisplay * d, int x, int y, unsigned int w, unsigned int h, int a1, int a2) { XDrawArc(d->display, d->pixmap, d->gc, x, y, w, h, a1, a2); } void xfillarc(xdisplay * d, int x, int y, unsigned int w, unsigned int h, int a1, int a2) { XFillArc(d->display, d->pixmap, d->gc, x, y, w, h, a1, a2); } #endif void xsize_set(xdisplay *d, int width, int height) { XResizeWindow(d->display, d->window, width, height); } int xmouse_x(xdisplay * d) { return d->mouse_x; } int xmouse_y(xdisplay * d) { return d->mouse_y; } void xmouse_update(xdisplay * d) { Window rootreturn, childreturn; int rootx = 0, rooty = 0, buttons = 0; XEvent event; if (XCheckMaskEvent(d->display,ButtonPressMask | ButtonReleaseMask, &event)) { if (event.type == ButtonPress) d->mouse_buttons |= 1 << ((XButtonEvent*)(&event))->button; else d->mouse_buttons &= ~( 1 << ((XButtonEvent*)(&event))->button ); } XQueryPointer(d->display, d->window, &rootreturn, &childreturn, &rootx, &rooty, &(d->mouse_x), &(d->mouse_y), &buttons); } char xkeyboard_query(xdisplay * d) { XEvent event; if (XCheckMaskEvent(d->display,KeyPressMask | KeyReleaseMask, &event)) { char *str = XKeysymToString(XLookupKeysym((XKeyPressedEvent*)(&event),0)); if ( ((XKeyPressedEvent*)(&event))->state & (ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask) ) return 0; if (str) { char key; if (strlen(str) == 1) key = str[0]; else if (strcmp(str,"equal") == 0) key = '='; else if (strcmp(str,"minus") == 0) key = '-'; else if (strcmp(str,"bracketleft") == 0) key = '['; else if (strcmp(str,"bracketright") == 0) key = ']'; else if (strcmp(str,"comma") == 0) key = ','; else if (strcmp(str,"period") == 0) key = '.'; else if (strcmp(str,"slash") == 0) key = '/'; else return 0; if ( ((XKeyPressedEvent*)(&event))->state & ShiftMask ) switch(key) { case '=' : key = '+'; break; case '[' : key = '{'; break; case ']' : key = '}'; break; case ',' : key = '<'; break; case '/' : key = '?'; break; default : if (key >= 'a' && key <= 'z') key = key+'A'-'a'; break; } return key; } } return 0; } int xsize_update(xdisplay *d,int *width,int *height) { XEvent event; if (XCheckMaskEvent(d->display,StructureNotifyMask, &event)) { if (event.type == ConfigureNotify) { xupdate_size(d); free_image(d); alloc_image(d); *width = d->linewidth; *height = d->height; return 1; } } return 0; } unsigned int xmouse_buttons(xdisplay * d) { return d->mouse_buttons; } #endif