/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- instance.c for the Openbox window manager Copyright (c) 2003 Ben Jansens 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. See the COPYING file for a copy of the GNU General Public License. */ #include "render.h" #include "instance.h" @interface AZInstance (AZPrivate) - (void) trueColorSetup; - (void) pseudoColorSetup; @end @implementation AZInstance - (id) initWithDisplay: (Display *) _display screen: (int) _screen { self = [super init]; display = _display; screen = _screen; depth = DefaultDepth(display, screen); visual = DefaultVisual(display, screen); colormap = DefaultColormap(display, screen); pseudo_colors = NULL; color_hash = [[NSMutableDictionary alloc] init]; switch (visual->class) { case TrueColor: [self trueColorSetup]; break; case PseudoColor: case StaticColor: case GrayScale: case StaticGray: [self pseudoColorSetup]; break; default: NSLog(@"Critical: Unsupported visual class"); RELEASE(self); return nil; } return self; } - (void) dealloc { free(pseudo_colors); DESTROY(color_hash); [super dealloc]; } - (Display *) display { return display; } - (int) screen { return screen; } - (Window) rootWindow { return RootWindow(display, screen); } - (Visual *) visual { return visual; } - (int) depth { return depth; } - (Colormap) colormap { return colormap; } - (int) redOffset { return red_offset; } - (int) greenOffset { return green_offset; } - (int) blueOffset { return blue_offset; } - (int) redShift { return red_shift; } - (int) greenShift { return green_shift; } - (int) blueShift { return blue_shift; } - (int) redMask { return red_mask; } - (int) greenMask { return green_mask; } - (int) blueMask { return blue_mask; } - (unsigned int) pseudoBPC { return pseudo_bpc; } - (XColor *) pseudoColors { return pseudo_colors; } - (NSMutableDictionary *) colorHash { return color_hash; } @end @implementation AZInstance (AZPrivate) - (void) trueColorSetup { unsigned long r_mask, g_mask, b_mask; XImage *timage = NULL; timage = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, 1, 1, 32, 0); NSAssert(timage != NULL, @"Cannot create image"); /* find the offsets for each color in the visual's masks */ red_mask = r_mask = timage->red_mask; green_mask = g_mask = timage->green_mask; blue_mask = b_mask = timage->blue_mask; red_offset = 0; green_offset = 0; blue_offset = 0; while (! (r_mask & 1)) { red_offset++; r_mask >>= 1; } while (! (g_mask & 1)) { green_offset++; g_mask >>= 1; } while (! (b_mask & 1)) { blue_offset++; b_mask >>= 1; } red_shift = green_shift = blue_shift = 8; while (r_mask) { r_mask >>= 1; red_shift--; } while (g_mask) { g_mask >>= 1; green_shift--; } while (b_mask) { b_mask >>= 1; blue_shift--; } XFree(timage); } #define RrPseudoNcolors() (1 << (pseudo_bpc * 3)) - (void) pseudoColorSetup { XColor icolors[256]; int tr, tg, tb, n, r, g, b, i, incolors, ii; unsigned long dev; int cpc, _ncolors; /* determine the number of colors and the bits-per-color */ pseudo_bpc = 2; /* XXX THIS SHOULD BE A USER OPTION */ NSAssert(pseudo_bpc >= 1, @"PseudoBPC must larger than 0"); _ncolors = RrPseudoNcolors(); if (_ncolors > 1 << depth) { NSLog(@"Warning: PseudoRenderControl: Invalid colormap size. Resizing.\n"); pseudo_bpc = 1 << (depth/3) >> 3; _ncolors = 1 << (pseudo_bpc * 3); } /* build a color cube */ pseudo_colors = calloc(sizeof(XColor), _ncolors); cpc = 1 << pseudo_bpc; /* colors per channel */ for (n = 0, r = 0; r < cpc; r++) for (g = 0; g < cpc; g++) for (b = 0; b < cpc; b++, n++) { tr = (int)(((float)(r)/(float)(cpc-1)) * 0xFF); tg = (int)(((float)(g)/(float)(cpc-1)) * 0xFF); tb = (int)(((float)(b)/(float)(cpc-1)) * 0xFF); pseudo_colors[n].red = tr | tr << 8; pseudo_colors[n].green = tg | tg << 8; pseudo_colors[n].blue = tb | tb << 8; /* used to track allocation */ pseudo_colors[n].flags = DoRed|DoGreen|DoBlue; } /* allocate the colors */ for (i = 0; i < _ncolors; i++) if (!XAllocColor(display, colormap, &pseudo_colors[i])) pseudo_colors[i].flags = 0; /* mark it as unallocated */ /* try allocate any colors that failed allocation above */ /* get the allocated values from the X server (only the first 256 XXX why!?) */ incolors = (((1 << depth) > 256) ? 256 : (1 << depth)); for (i = 0; i < incolors; i++) icolors[i].pixel = i; XQueryColors(display, colormap, icolors, incolors); /* try match unallocated ones */ for (i = 0; i < _ncolors; i++) { if (!pseudo_colors[i].flags) { /* if it wasn't allocated... */ unsigned long closest = 0xffffffff, close = 0; for (ii = 0; ii < incolors; ii++) { /* find deviations */ r = (pseudo_colors[i].red - icolors[ii].red) & 0xff; g = (pseudo_colors[i].green - icolors[ii].green) & 0xff; b = (pseudo_colors[i].blue - icolors[ii].blue) & 0xff; /* find a weighted absolute deviation */ dev = (r * r) + (g * g) + (b * b); if (dev < closest) { closest = dev; close = ii; } } pseudo_colors[i].red = icolors[close].red; pseudo_colors[i].green = icolors[close].green; pseudo_colors[i].blue = icolors[close].blue; pseudo_colors[i].pixel = icolors[close].pixel; /* try alloc this closest color, it had better succeed! */ if (XAllocColor(display, colormap, &pseudo_colors[i])) /* mark as alloced */ pseudo_colors[i].flags = DoRed|DoGreen|DoBlue; else /* wtf has gone wrong, its already alloced for chissake! */ NSAssert(0, @"Should not reach here"); } } } @end