/* Part of XPCE --- The SWI-Prolog GUI toolkit Author: Jan Wielemaker and Anjo Anjewierden E-mail: jan@swi.psy.uva.nl WWW: http://www.swi.psy.uva.nl/projects/xpce/ Copyright (c) 1995-2013, University of Amsterdam All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define USE_CONVERTED_COLOURS 1; #include "include.h" #ifdef USE_CONVERTED_COLOURS #include "xcolours.c" #else #include #endif static HashTable ColourNames; /* name --> rgb (packed in Int) */ static HashTable X11ColourNames; /* rgb --> X11-name */ static status ws_alloc_colour(ColourMap cm, Colour c); static void ws_unalloc_colour(ColourMap cm, Colour c); #ifdef USE_CONVERTED_COLOURS static HashTable LoadColourNames() { if ( !ColourNames ) { xcolourdef *cd; ColourNames = globalObject(NAME_colourNames, ClassHashTable, EAV); for(cd = x11_colours; cd->name; cd++) { COLORREF rgb = RGB(cd->red, cd->green, cd->blue); char buf[100]; const char *s = cd->name; char *q = buf; for( ; *s; s++ ) { if ( *s == ' ' ) *q++ = '_'; else *q++ = tolower(*s); } *q = '\0'; appendHashTable(ColourNames, CtoKeyword(buf), toInt(rgb)); } ws_system_colours(CurrentDisplay(NIL)); } return ColourNames; } #else /*USE_CONVERTED_COLOURS*/ static HashTable LoadColourNames() { if ( !ColourNames ) { FileObj f = answerObject(ClassFile, CtoName("$PCEHOME/lib/rgb.txt"), EAV); ColourNames = globalObject(NAME_colourNames, ClassHashTable, EAV); if ( send(f, NAME_open, NAME_read, EAV) ) { char line[256]; int r, g, b; char name[80]; while( fgets(line, sizeof(line), f->fd) ) { switch( sscanf(line, "%d%d%d%[^\n]", &r, &g, &b, name) ) { case 4: { char *s; char *e; COLORREF rgb; Name cname; for(s=name; *s && *s <= ' '; s++) ; for(e = s + strlen(s); e > s && e[-1] <= ' '; e--) ; *e = EOS; for(e=s; *e; e++) { if ( isupper(*e) ) *e = tolower(*e); else if ( *e == ' ' ) *e = '_'; } cname = CtoKeyword(s); rgb = RGB(r, g, b); appendHashTable(ColourNames, cname, toInt(rgb)); DEBUG(NAME_colour, Cprintf("%s --> 0x%lx\n", pp(cname), (long) rgb)); break; } } } send(f, NAME_close, EAV); } } return ColourNames; } #endif /*USE_CONVERTED_COLOURS*/ #if O_XPM #ifdef USE_CONVERTED_COLOURS static HashTable LoadX11ColourNames() { if ( !X11ColourNames ) { xcolourdef *cd; X11ColourNames = globalObject(CtoName("_x11_colour_names"), ClassHashTable, EAV); for(cd = x11_colours; cd->name; cd++) { COLORREF rgb = RGB(cd->red, cd->green, cd->blue); appendHashTable(X11ColourNames, toInt(rgb), CtoName(cd->name)); } } return X11ColourNames; } #else /*USE_CONVERTED_COLOURS*/ static HashTable LoadX11ColourNames() { if ( !X11ColourNames ) { FileObj f = answerObject(ClassFile, CtoName("$PCEHOME/lib/rgb.txt"), EAV); X11ColourNames = globalObject(CtoName("_x11_colour_names"), ClassHashTable, EAV); if ( send(f, NAME_open, NAME_read, EAV) ) { char line[256]; int r, g, b; char name[80]; while( fgets(line, sizeof(line), f->fd) ) { switch( sscanf(line, "%d%d%d%[^\n]", &r, &g, &b, name) ) { case 4: { char *s; char *e; COLORREF rgb; for(s=name; *s && *s <= ' '; s++) ; for(e = s + strlen(s); e > s && e[-1] <= ' '; e--) ; *e = EOS; rgb = RGB(r, g, b); appendHashTable(X11ColourNames, toInt(rgb), CtoName(s)); break; } } } send(f, NAME_close, EAV); } } return X11ColourNames; } #endif /*USE_CONVERTED_COLOURS*/ int xpmGetRGBfromName(char *inname, int *r, int *g, int *b) { char name[256]; char *q = name, *s = inname; Name cname; Int pcergb; for( ;*s; s++, q++) { if ( isupper(*s) ) *q = tolower(*s); else if ( *s == ' ' ) *q = '_'; else *q = *s; } *q = EOS; cname = CtoKeyword(name); if ( (pcergb = getMemberHashTable(LoadColourNames(), cname)) ) { COLORREF rgb = valInt(pcergb); *r = GetRValue(rgb); *g = GetGValue(rgb); *b = GetBValue(rgb); } else { *r = 255; /* nothing there, return red */ *g = *b = 0; } return 1; /* we have it */ } int xpmReadRgbNames(char *rgb_fname, void *rgbn) { return valInt(LoadX11ColourNames()->size); } void xpmFreeRgbNames(void *rgbn, int rgbn_max) { } char * xpmGetRgbName(void *rgbn, int rgbn_max, int red, int green, int blue) { Int rgb = toInt(RGB(red, green, blue)); HashTable ht = LoadX11ColourNames(); Name name; if ( rgb == ZERO ) return "black"; /* otherwise these come as gray0 */ if ( rgb == toInt(RGB(255,255,255)) ) return "white"; /* and gray100 */ if ( (name = getMemberHashTable(ht, rgb)) ) return strName(name); return NULL; } #endif /*O_XPM*/ static Name canonical_colour_name(Name in) { char *s = strName(in); char buf[100]; int left = sizeof(buf); char *q = buf; int changed = 0; for( ; *s && --left > 0; s++, q++ ) { if ( *s == ' ' ) { *q = '_'; changed++; } else if ( isupper(*s) ) { *q = tolower(*s); changed++; } else *q = *s; } if ( left && changed ) { *q = EOS; return CtoKeyword(buf); } return in; } status ws_colour_name(DisplayObj d, Name name) { HashTable ht = LoadColourNames(); if ( getMemberHashTable(ht, name) || getMemberHashTable(ht, canonical_colour_name(name)) ) succeed; fail; } status ws_create_colour(Colour c, DisplayObj d) { Int Rgb; if ( c->kind == NAME_named ) { HashTable ht = LoadColourNames(); if ( (Rgb = getMemberHashTable(ht, c->name)) || (Rgb = getMemberHashTable(ht, canonical_colour_name(c->name))) ) { COLORREF rgb = (COLORREF) valInt(Rgb); int r = GetRValue(rgb) * 257; int g = GetGValue(rgb) * 257; int b = GetBValue(rgb) * 257; assign(c, red, toInt(r)); assign(c, green, toInt(g)); assign(c, blue, toInt(b)); registerXrefObject(c, d, (void *)(uintptr_t)rgb); } else fail; } else { COLORREF rgb = RGB(valInt(c->red)/256, valInt(c->green)/256, valInt(c->blue)/256); registerXrefObject(c, d, (void *)(uintptr_t)rgb); } if ( instanceOfObject(d->colour_map, ClassColourMap) && d->colour_map->read_only == OFF ) ws_alloc_colour(d->colour_map, c); succeed; } void ws_uncreate_colour(Colour c, DisplayObj d) { if ( isDefault(d) ) d = CurrentDisplay(NIL); if ( instanceOfObject(d->colour_map, ClassColourMap) && d->colour_map->read_only == OFF ) ws_unalloc_colour(d->colour_map, c); unregisterXrefObject(c, d); } Colour ws_pixel_to_colour(DisplayObj d, unsigned long pixel) { fail; } struct system_colour { char *name; int id; }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Windows system colors as obtained from GetSysColor(). Updated with new colors at Jul 23, 2005 using MSVC 6.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static struct system_colour window_colours[] = { { "sys_scrollbar_background", COLOR_BTNFACE }, { "sys_dialog_background", COLOR_MENU }, { "sys_dialog_foreground", COLOR_MENUTEXT }, { "sys_window_background", COLOR_WINDOW }, { "sys_window_foreground", COLOR_WINDOWTEXT }, { "sys_relief", COLOR_BTNFACE }, { "sys_shadow", COLOR_BTNSHADOW }, { "sys_inactive", COLOR_GRAYTEXT }, { "win_3ddkshadow", COLOR_3DDKSHADOW }, { "win_3dface", COLOR_3DFACE }, { "win_3dhighlight", COLOR_3DHIGHLIGHT }, { "win_3dhilight", COLOR_3DHILIGHT }, { "win_3dlight", COLOR_3DLIGHT }, { "win_3dshadow", COLOR_3DSHADOW }, { "win_activeborder", COLOR_ACTIVEBORDER }, { "win_activecaption", COLOR_ACTIVECAPTION }, { "win_activecaption", COLOR_ACTIVECAPTION }, { "win_appworkspace", COLOR_APPWORKSPACE }, { "win_background", COLOR_BACKGROUND }, { "win_btnface", COLOR_BTNFACE }, { "win_btnhighlight", COLOR_BTNHIGHLIGHT }, { "win_btnhilight", COLOR_BTNHILIGHT }, { "win_btnshadow", COLOR_BTNSHADOW }, { "win_btntext", COLOR_BTNTEXT }, { "win_captiontext", COLOR_CAPTIONTEXT }, { "win_desktop", COLOR_DESKTOP }, #ifdef COLOR_GRADIENTACTIVECAPTION { "win_gradientactivecaption", COLOR_GRADIENTACTIVECAPTION }, { "win_gradientinactivecaption", COLOR_GRADIENTINACTIVECAPTION }, #endif { "win_graytext", COLOR_GRAYTEXT }, { "win_highlight", COLOR_HIGHLIGHT }, { "win_highlighttext", COLOR_HIGHLIGHTTEXT }, #ifdef COLOR_HOTLIGHT { "win_hotlight", COLOR_HOTLIGHT }, #endif { "win_inactiveborder", COLOR_INACTIVEBORDER }, { "win_inactivecaption", COLOR_INACTIVECAPTION }, { "win_inactivecaptiontext", COLOR_INACTIVECAPTIONTEXT }, { "win_infobk", COLOR_INFOBK }, { "win_infotext", COLOR_INFOTEXT }, { "win_menu", COLOR_MENU }, { "win_menutext", COLOR_MENUTEXT }, { "win_scrollbar", COLOR_SCROLLBAR }, { "win_window", COLOR_WINDOW }, { "win_windowframe", COLOR_WINDOWFRAME }, { "win_windowtext", COLOR_WINDOWTEXT }, { NULL, 0 } }; Colour ws_system_colour(DisplayObj d, const char *name, COLORREF rgb) { Name ref = CtoKeyword(name); int r = GetRValue(rgb); int g = GetGValue(rgb); int b = GetBValue(rgb); Colour c; r = r*256 + r; g = g*256 + g; b = b*256 + b; if ( (c = newObject(ClassColour, ref, toInt(r), toInt(g), toInt(b), EAV)) ) { lockObject(c, ON); registerXrefObject(c, d, (void *)(uintptr_t)rgb); } return c; } void ws_system_colours(DisplayObj d) { struct system_colour *sc = window_colours; for( ; sc->name; sc++ ) { DWORD rgb = GetSysColor(sc->id); ws_system_colour(d, sc->name, rgb); } } /******************************* * COLOURMAPS * *******************************/ #undef offset #define offset(s, f) ((intptr_t)&((s *)NULL)->f) static void ws_open_colourmap(ColourMap cm); void setPaletteColourMap(ColourMap cm, HPALETTE hpal) { getWsCmdata(cm)->hpal = hpal; } HPALETTE getPaletteColourMap(ColourMap cm) { WsCmdata data = getWsCmdata(cm); if ( !data->hpal ) ws_open_colourmap(cm); return data->hpal; } static HPALETTE getExistingPaletteColourMap(ColourMap cm) { if ( cm->ws_ref ) return getWsCmdata(cm)->hpal; return NULL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CreateCCPalette(int size) Create a cubic colourmap. The 6x6x6 (216) map created by this function is the same as used by Netscape on 8-bit displays. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static HPALETTE CreateCCPalette(int size) { int le = size * size * size; LOGPALETTE *lp = pceMalloc(offset(LOGPALETTE, palPalEntry[le])); int i, r, g, b; PALETTEENTRY *pe = &lp->palPalEntry[0]; BYTE *intensity = alloca(size * sizeof(BYTE)); HPALETTE hpal; lp->palVersion = 0x300; lp->palNumEntries = le; for(i=0; ipeRed = intensity[r]; pe->peGreen = intensity[g]; pe->peBlue = intensity[b]; pe->peFlags = 0; pe++; } } } if ( !(hpal = CreatePalette(lp)) ) Cprintf("Failed to create color cube with %d entries\n", le); return hpal; } static void ws_open_colourmap(ColourMap cm) { if ( !getExistingPaletteColourMap(cm) && notNil(cm->colours) ) { int size = valInt(cm->colours->size); LOGPALETTE *lp = pceMalloc(offset(LOGPALETTE, palPalEntry[size])); PALETTEENTRY *pe = &lp->palPalEntry[0]; HPALETTE hpal; int n, nc = 0; DisplayObj d = CurrentDisplay(NIL); for(n=0; ncolours->elements[n]; if ( isName(c) && (c = checkType(c, TypeColour, NIL)) ) elementVector(cm->colours, toInt(n+1), c); if ( instanceOfObject(c, ClassColour) ) { if ( c->kind == NAME_named ) ws_create_colour(c, d); pe->peRed = valInt(c->red) >> 8; pe->peGreen = valInt(c->green) >> 8; pe->peBlue = valInt(c->blue) >> 8; pe->peFlags = 0; pe++; nc++; } else Cprintf("%s is not a colour\n", pp(c)); } lp->palVersion = 0x300; lp->palNumEntries = nc; DEBUG(NAME_colourMap, Cprintf("Created %s with %d colours\n", pp(cm), nc)); if ( !(hpal = CreatePalette(lp)) ) Cprintf("%s: failed to create logpalette\n", pp(cm)); setPaletteColourMap(cm, hpal); } } WsCmdata getWsCmdata(ColourMap cm) { if ( !cm->ws_ref ) { cm->ws_ref = alloc(sizeof(struct ws_cmdata)); memset(cm->ws_ref, 0, sizeof(struct ws_cmdata)); } return cm->ws_ref; } void ws_colour_cube(ColourMap cm, int size) { HPALETTE hpal; if ( size < 1 ) /* nonsence value */ size = 2; if ( size > 6 ) /* too large */ size = 6; hpal = CreateCCPalette(size); setPaletteColourMap(cm, hpal); } static Int XIntensity(BYTE wi) { unsigned i = (unsigned)wi; i = (i << 8) + i; return toInt(i); } void ws_colour_map_colours(ColourMap cm) { if ( isNil(cm->colours) ) { int entries; PALETTEENTRY *lpe; int n; if ( cm->name == NAME_system ) /* system palette */ { HDC hdc = GetDC(NULL); entries = GetSystemPaletteEntries(hdc, 0, 1<<16, NULL); lpe = alloca(entries * sizeof(PALETTEENTRY)); GetSystemPaletteEntries(hdc, 0, entries, lpe); ReleaseDC(NULL, hdc); } else /* normal palette */ { HPALETTE hpal; if ( cm->name == NAME_static || cm->name == NAME_pce ) hpal = GetStockObject(DEFAULT_PALETTE); else hpal = getPaletteColourMap(cm); if ( !hpal ) return; entries = GetPaletteEntries(hpal, 0, 1<<16, NULL); lpe = alloca(entries * sizeof(PALETTEENTRY)); GetPaletteEntries(hpal, 0, entries, lpe); } assign(cm, colours, newObject(ClassVector, EAV)); elementVector(cm->colours, ONE, NIL); elementVector(cm->colours, toInt(entries), NIL); for(n=0; ncolours, toInt(n+1), newObject(ClassColour, DEFAULT, XIntensity(lpe[n].peRed), XIntensity(lpe[n].peGreen), XIntensity(lpe[n].peBlue), EAV)); } } } status ws_create_colour_map(ColourMap cm, DisplayObj d) { fail; } status ws_uncreate_colour_map(ColourMap cm, DisplayObj d) { fail; } status ws_unlink_colour_map(ColourMap cm) { WsCmdata data; if ( (data = cm->ws_ref) ) { cm->ws_ref = NULL; if ( data->hpal ) DeleteObject(data->hpal); if ( data->jpeg_cmap ) free_jpeg_cmap(data->jpeg_cmap); unalloc(sizeof(struct ws_cmdata), data); } succeed; } /******************************* *EXPERIMENTAL COLOUR ALLOCATION* *******************************/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Allocate a colour in the XPCE central colourmap. At the moment, the map is filled, and colours are not changed afterwards. It would be better to collect all colours and now and then build an optimal palette from the defined colours. How does one do that? Also, all device dependant (read: based on this colourmap) images would need to be updated (or all images should be stored as DIB images). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static status ws_alloc_colour(ColourMap cm, Colour c) { HPALETTE hpal; Int i; if ( isNil(cm->colours) ) ws_colour_map_colours(cm); if ( getIndexVector(cm->colours, c) ) succeed; /* already there (basically for my own colours) */ if ( (i=getIndexVector(cm->colours, NIL)) ) elementVector(cm->colours, i, c); else appendVector(cm->colours, 1, (Any *)&c); delRefObj(c); if ( (hpal=getExistingPaletteColourMap(cm)) ) { PALETTEENTRY peentry; PALETTEENTRY *pe = &peentry; int ne = valInt(cm->colours->size); pe->peRed = valInt(c->red) >> 8; pe->peGreen = valInt(c->green) >> 8; pe->peBlue = valInt(c->blue) >> 8; pe->peFlags = 0; if ( i ) { if ( SetPaletteEntries(hpal, valInt(i)-1, 1, pe) != 1 ) { DEBUG(NAME_colour, Cprintf("Failed to set %s at index %d of %s\n", pp(c), valInt(i)-1, pp(cm))); fail; } DEBUG(NAME_colour, Cprintf("Reused colour entry %d for %s\n", valInt(i)-1, pp(c))); } else { if ( ResizePalette(hpal, ne) ) { if ( SetPaletteEntries(hpal, ne-1, 1, pe) != 1 ) { DEBUG(NAME_colour, Cprintf("Failed to add %s to %s\n", pp(c), pp(cm))); fail; } } else { DEBUG(NAME_colour, Cprintf("Failed to extend %s\n", pp(cm))); fail; } } } succeed; } static void ws_unalloc_colour(ColourMap cm, Colour c) { if ( notNil(cm->colours) ) { Int i; if ( (i = getIndexVector(cm->colours, c)) ) { addRefObj(c); elementVector(cm->colours, i, NIL); } } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Check whether the display supports colourmaps. Got this from http://www.compuphase.com/palette.htm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ status ws_has_colourmap(DisplayObj d) { HDC hdc = GetDC(NULL); int rc = GetDeviceCaps(hdc,RASTERCAPS); int bits = GetDeviceCaps(hdc,BITSPIXEL); int planes = GetDeviceCaps(hdc,PLANES); ReleaseDC(NULL, hdc); bits *= planes; /* bits == flat number of bits per pixel */ /* The only hardware modes that use a palette are modes * with 2, 4, 16 and 256 colours. * Microsoft Windows supports palette operations only * on displays with 256 colours. That is, in 16-colour * mode, you cannot use the palette. * So you only need to check for the RC_PALETTE bit if * the number of bits per pixel is 8. */ return (rc & RC_PALETTE) != 0 && bits == 8; }