/* * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "aconfig.h" #ifdef X11_DRIVER #include #include #include #include #include #include #include #ifndef NO_MALLOC_H #include #endif #include "xlib.h" #ifdef AMIGA #define XFlush(x) while(0) #endif #define chkalloc(n) if (!n) fprintf(stderr, "out of memory\n"), exit(-1) extern int prog_argc; extern char **prog_argv; Atom wmDeleteWindow; int xupdate_size(xdisplay * d) { int tmp; Window wtmp; unsigned int width = d->width, height = d->height; XSync(d->display, False); XGetGeometry(d->display, d->window, &wtmp, &tmp, &tmp, &d->width, &d->height, (unsigned int *) &tmp, (unsigned int *) &tmp); if (d->width != width || 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) { #ifdef MITSHM if (d->SharedMemFlag) { XShmPutImage(d->display, d->window, d->gc, d->image[d->current], 0, 0, 0, 0, d->bwidth, d->bheight, True); } else #endif XPutImage(d->display, d->window, d->gc, d->image[d->current], 0, 0, 0, 0, d->bwidth, d->bheight); /*XFlush(d->display); *//*gives small rest to X but degrades perofrmance too much */ 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 (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) { new->SharedMemFlag = False; new->image[i] = XShmCreateImage(new->display, new->visual, new->depth, new->depth == 1 ? XYBitmap : ZPixmap, NULL, &new->xshminfo[i], new->width, new->height); if (new->image[i]) { temp = new->image[i]->bytes_per_line * (new->image[i]->height + 150); new->linewidth = new->image[i]->bytes_per_line; if (temp > size) size = temp; new->xshminfo[i].shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); if (new->xshminfo[i].shmid != -1) { errno = 0; new->xshminfo[i].shmaddr = (char *) shmat(new->xshminfo[i].shmid, 0, 0); if (!errno) { 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; d->bwidth = d->width; d->bheight = d->height; #ifdef MITSHM if (!d->params->nomitshm && d->depth != 1 && alloc_shm_image(d)) { return 1; } #endif for (i = 0; i < 2; i++) { d->image[i] = XCreateImage(d->display, d->visual, d->depth, d->depth == 1 ? XYBitmap : ZPixmap, 0, NULL, d->width, d->height, 32, 0); if (d->image[i] == NULL) { printf("Out of memory for image..exiting\n"); exit(-1); } d->image[i]->data = malloc(d->image[i]->bytes_per_line * d->height); if (d->image[i]->data == NULL) { printf("Out of memory for image buffers..exiting\n"); exit(-1); } { unsigned char c[4]; int byteexact = 0; *(unsigned short *) c = 0xff; if ((!(d->image[i]->red_mask & ~0xffU) || !(d->image[i]->red_mask & ~0xff00U) || !(d->image[i]->red_mask & ~0xff0000U) || !(d->image[i]->red_mask & ~0xff000000U)) && (!(d->image[i]->green_mask & ~0xffU) || !(d->image[i]->green_mask & ~0xff00U) || !(d->image[i]->green_mask & ~0xff0000U) || !(d->image[i]->green_mask & ~0xff000000U)) && (!(d->image[i]->blue_mask & ~0xffU) || !(d->image[i]->blue_mask & ~0xff00U) || !(d->image[i]->blue_mask & ~0xff0000U) || !(d->image[i]->blue_mask & ~0xff000000U))) byteexact = 1; if (!byteexact) { /*Make endianity correct */ if (c[0] == (unsigned char) 0xff) { if (d->image[i]->byte_order != LSBFirst) { d->image[i]->byte_order = LSBFirst; /*XInitImage(d->image[i]); */ } } else { if (d->image[i]->byte_order != MSBFirst) { d->image[i]->byte_order = MSBFirst; /*XInitImage(d->image[i]); */ } } } } d->data[i] = d->vbuffs[i] = (char *) d->image[i]->data; d->linewidth = d->image[i]->bytes_per_line; } xflip_buffers(d); return 1; } void free_image(xdisplay * d) { #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 x, int y, xlibparam * params) { xdisplay *new; Visual *defaultvisual; XVisualInfo vis; int found; int i; XClassHint classHint; XWMHints *hints; char **faked_argv; new = (xdisplay *) calloc(sizeof(xdisplay), 1); chkalloc(new); new->display = XOpenDisplay(params->display); if (!new->display) { free((void *) new); return NULL; } new->screen = DefaultScreen(new->display); new->attributes = (XSetWindowAttributes *) malloc(sizeof(XSetWindowAttributes)); chkalloc(new->attributes); new->attributes->background_pixel = BlackPixel(new->display, new->screen); new->attributes->border_pixel = BlackPixel(new->display, new->screen); new->attributes->event_mask = ButtonPressMask | StructureNotifyMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | ExposureMask | KeyReleaseMask; new->attr_mask = CWBackPixel | CWEventMask; if (params->fullscreen || params->rootwindow) { new->attributes->override_redirect = True; new->attr_mask |= CWOverrideRedirect; } else new->attr_mask |= CWBorderPixel; new->class = InputOutput; new->xcolor.n = 0; new->parent_window = RootWindow(new->display, new->screen); defaultvisual = DefaultVisual(new->display, new->screen); new->params = params; found = 0; for (i = 31; i > 13 && !found; i--) if (XMatchVisualInfo (new->display, new->screen, i, TrueColor, &vis)) { found = 1; } if (defaultvisual->class != StaticGray && defaultvisual->class != GrayScale) { for (i = 8; i && !found; i--) if (XMatchVisualInfo (new->display, new->screen, i, PseudoColor, &vis)) { found = 1; } for (i = 8; i && !found; i--) if (XMatchVisualInfo (new->display, new->screen, i, StaticColor, &vis)) { found = 1; } for (i = 8; i && !found; i--) if (XMatchVisualInfo (new->display, new->screen, i, TrueColor, &vis)) { found = 1; } } if (!found && XMatchVisualInfo(new->display, new->screen, 8, StaticGray, &vis)) { found = 1; } for (i = 8; i && !found; i--) if (XMatchVisualInfo (new->display, new->screen, i, GrayScale, &vis)) { found = 1; } if (!found && XMatchVisualInfo(new->display, new->screen, 1, StaticGray, &vis)) { found = 8; } if (!found || params->fullscreen || params->rootwindow) { new->visual = defaultvisual; new->depth = DefaultDepth(new->display, new->screen); } else { new->visual = vis.visual; new->depth = vis.depth; } switch (new->visual->class) { case StaticColor: case StaticGray: smallcolor: new->truecolor = 0; new->fixedcolormap = 1; break; case PseudoColor: case GrayScale: if (new->depth <= 8) { new->truecolor = 0; new->fixedcolormap = 0; } else { goto visuals; } break; case TrueColor: new->truecolor = 1; new->fixedcolormap = 1; if (new->depth <= 8) goto smallcolor; if (new->depth > 32) { goto visuals; } break; default: visuals: printf ("Unusuported visual. Please contact authors. Maybe it will be supported in next release:)\n"); return (NULL); } new->privatecolormap = params->privatecolormap; new->attributes->colormap = new->defaultcolormap = DefaultColormap(new->display, new->screen); if (new->visual->visualid != defaultvisual->visualid) { new->privatecolormap = 1; } if ( /*!new->fixedcolormap && */ new->privatecolormap) { unsigned long pixels[256]; int i; new->attributes->colormap = XCreateColormap(new->display, RootWindow(new->display, new->screen), new->visual, AllocNone); if (new->visual->visualid == defaultvisual->visualid && new->visual->class == PseudoColor) { XAllocColorCells(new->display, new->attributes->colormap, 1, 0, 0, pixels, MAX(new->visual->map_entries, 256)); for (i = 0; i < 16; i++) { new->xcolor.c[i].pixel = pixels[i]; } XQueryColors(new->display, new->defaultcolormap, new->xcolor.c, 16); XStoreColors(new->display, new->attributes->colormap, new->xcolor.c, 16); } } new->colormap = new->attributes->colormap; new->attr_mask |= CWColormap; new->window_name = (char *) s; new->height = y; new->width = x; new->border_width = 2; new->lastx = 0; new->lasty = 0; new->font_struct = (XFontStruct *) NULL; if (params->fullscreen || params->rootwindow) { Window wtmp; int tmp; /* Get size of the root window */ XGetGeometry(new->display, RootWindow(new->display, new->screen), &wtmp, &tmp, &tmp, &new->width, &new->height, (unsigned int *) &tmp, /* border width */ (unsigned int *) &tmp); /* depth */ new->border_width = 0; } if (params->windowid != -1) { Window wtmp; int tmp; new->parent_window = params->windowid; XGetGeometry(new->display, new->parent_window, &wtmp, &tmp, &tmp, &new->width, &new->height, (unsigned int *) &tmp, /* border width */ (unsigned int *) &tmp); /* depth */ XSelectInput(new->display, new->parent_window, ResizeRedirectMask); } if (params->rootwindow) new->window = RootWindow(new->display, new->screen); else new->window = XCreateWindow(new->display, new->parent_window, 0, 0, new->width, new->height, new->border_width, new->depth, new->class, new->visual, new->attr_mask, new->attributes); classHint.res_name = (char *) "xaos"; classHint.res_class = (char *) "XaoS"; hints = XAllocWMHints(); hints->initial_state = NormalState; hints->window_group = new->window; hints->flags = (WindowGroupHint | StateHint); { int fake = 0; if (prog_argc < 2) fake = 1; if (fake == 0) if (strcmp(prog_argv[prog_argc - 2], "-driver") && strcmp(prog_argv[prog_argc - 1], "x11")) fake = 1; if (fake) { int i; faked_argv = (char **) malloc((prog_argc + 2) * sizeof(char *)); for (i = 0; i < prog_argc; i++) faked_argv[i] = prog_argv[i]; faked_argv[prog_argc] = (char *) "-driver"; faked_argv[prog_argc + 1] = (char *) "x11"; XSetWMProperties(new->display, new->window, NULL, NULL, faked_argv, prog_argc + 2, NULL, hints, &classHint); free(faked_argv); } else XSetWMProperties(new->display, new->window, NULL, NULL, prog_argv, prog_argc, NULL, hints, &classHint); } XSetIconName(new->display, new->window, "xaos"); wmDeleteWindow = XInternAtom(new->display, "WM_DELETE_WINDOW", False); XSetWMProtocols(new->display, new->window, &wmDeleteWindow, 1); new->gc = XCreateGC(new->display, new->window, 0L, &(new->xgcvalues)); XSetBackground(new->display, new->gc, BlackPixel(new->display, new->screen)); XSetForeground(new->display, new->gc, WhitePixel(new->display, new->screen)); XStoreName(new->display, new->window, new->window_name); XMapWindow(new->display, new->window); if (params->fullscreen || params->rootwindow) XSetInputFocus(new->display, new->window, RevertToNone, CurrentTime); return (new); } 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(-1); } XSetForeground(d->display, d->gc, d->xcolor.c[col - 2].pixel); break; } } void xsetpaletterange(xdisplay * d, ui_palette c, int start, int end) { int i; if (d->visual->class == StaticColor || d->visual->class == TrueColor) { for (i = start; i < end; i++) d->xcolor.c[i].pixel = i; XQueryColors(d->display, d->colormap, d->xcolor.c + start, end - start); for (i = start; i < end; i++) { c[i - start][0] = d->xcolor.c[i].red / 256; c[i - start][1] = d->xcolor.c[i].green / 256; c[i - start][2] = d->xcolor.c[i].blue / 256; } } else { for (i = start; i < end; i++) { d->xcolor.c[i].pixel = i; d->xcolor.c[i].flags = DoRed | DoGreen | DoBlue; d->xcolor.c[i].red = c[i - start][0] * 256; d->xcolor.c[i].green = c[i - start][1] * 256; d->xcolor.c[i].blue = c[i - start][2] * 256; } XStoreColors(d->display, d->colormap, d->xcolor.c + start, end - start); } } 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 ((int) 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 applications 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 ((int) 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 : (int) 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); XDestroyWindow(d->display, d->window); XCloseDisplay(d->display); free((void *) d->attributes); free((void *) d); } void xclear_screen(xdisplay * d) { XClearWindow(d->display, d->window); d->screen_changed = 1; } void xmoveto(xdisplay * d, int x, int y) { d->lastx = x, d->lasty = y; } int xsetfont(xdisplay * d, CONST char *font_name) { if (d->font_struct != (XFontStruct *) NULL) { XFreeFont(d->display, d->font_struct); } d->font_struct = XLoadQueryFont(d->display, font_name); XSetFont(d->display, d->gc, d->font_struct->fid); if (!d->font_struct) { fprintf(stderr, "could not load font: %s\n", font_name); exit(-1); } return (d->font_struct->max_bounds.ascent + d->font_struct->max_bounds.descent); } void xouttext(xdisplay * d, CONST char *string) { int sz; sz = (int) strlen(string); XDrawImageString(d->display, d->window, d->gc, d->lastx, d->lasty, string, sz); } void xresize(xdisplay * d, XEvent * ev) { XSync(d->display, False); d->width = ev->xconfigure.width; d->height = ev->xconfigure.height; } #endif