Mercurial > hg > xemacs-beta
diff lwlib/lwlib-colors.c @ 3094:ad2f4ae9895b
[xemacs-hg @ 2005-11-26 11:45:47 by stephent]
Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Sat, 26 Nov 2005 11:46:25 +0000 |
parents | |
children | a6c778975d7d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwlib/lwlib-colors.c Sat Nov 26 11:46:25 2005 +0000 @@ -0,0 +1,361 @@ +/* Color data structures for X and Xft. + +Copyright (C) 2004 Free Software Foundation, Inc. + +Author: Stephen J. Turnbull <stephen@xemacs.org> +Created: 24 Jul 2004 by Stephen J. Turnbull + +This file is part of XEmacs. + +XEmacs 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, or (at your option) any +later version. + +XEmacs 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 XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in GNU Emacs. */ + +#include <config.h> +#include <limits.h> /* for ULONG_MAX */ +#include <stdlib.h> /* for malloc() */ +#include <stdio.h> +#include <X11/Xlib.h> +#include <X11/IntrinsicP.h> +#include <X11/ShellP.h> /* for ShellWidget */ +#include "lwlib-colors.h" + +static int debug_colors = 1; + +#ifdef __cplusplus +#define X_CLASSFIELD c_class +#else +#define X_CLASSFIELD class +#endif + +#define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ + ? ((unsigned long) (x)) : ((unsigned long) (y))) + +/* WIDGET is an Xt widget, VISUAL and DEPTH are return values */ +void +visual_info_from_widget (Widget widget, Visual **visual, int *depth) +{ + /* grab the visual and depth from the nearest shell ancestor */ + Widget p = XtParent(widget); + + *visual = CopyFromParent; + *depth = -1; + while (*visual == CopyFromParent && p) + { + if (XtIsShell(p)) + { + *visual = ((ShellWidget)p)->shell.visual; + *depth = p->core.depth; + } + p = XtParent(p); + } + if (*visual == CopyFromParent || !*visual) + { + if (debug_colors > 1) + fprintf (stderr, "\nvisual_info_from_widget:" + " failed, using DefaultVisualOfScreen"); + *visual = DefaultVisualOfScreen (XtScreen (widget)); + *depth = DefaultDepthOfScreen (XtScreen (widget)); + } + else if (debug_colors > 1) + fprintf (stderr, "\nvisual_info_from_widget: succeeded"); +} + +/* Do we need all this hair on modern hardware? */ + +/* Replacement for XAllocColor() that tries to return the nearest + available color if the colormap is full. Original was from FSFmacs, + but rewritten by Jareth Hein <jareth@camelot-soft.com> 97/11/25 + Modified by Lee Kindness <lkindness@csl.co.uk> 31/08/99 to handle previous + total failure which was due to a read/write colorcell being the nearest + match - tries the next nearest... + + Return value is 1 for normal success, 2 for nearest color success, + 3 for Non-deallocable success. */ +int +x_allocate_nearest_color (Display *display, Colormap colormap, + Visual *visual, XColor *color_def) +{ + int status; + + /* #### [[Apparently this is often called with data derived from a widget + with no ShellWidget ancestor, or before the shell has a visual. + Currently this recovery code is in xlwmenu.c and xlwscrollbar.c, but + likely should come here.]] + I suspect the problem is that the visual-tracing code was improperly + written, missing a level of indirection. + CopyFromParent == NULL in XFree86/Darwin. + */ + if (visual == CopyFromParent || !visual) + { + Screen *screen = DefaultScreenOfDisplay (display); + fprintf (stderr, "\nx_allocate_nearest_color: bad visual (%08lx)", + (unsigned long) visual); + visual = DefaultVisualOfScreen (screen); + } + + if (visual->X_CLASSFIELD == DirectColor || visual->X_CLASSFIELD == TrueColor) + { + if (XAllocColor (display, colormap, color_def) != 0) + { + status = 1; + } + else + { + /* We're dealing with a TrueColor/DirectColor visual, so play games + with the RGB values in the XColor struct. */ + /* #### JH: I'm not sure how a call to XAllocColor can fail in a + TrueColor or DirectColor visual, so I will just reformat the + request to match the requirements of the visual, and re-issue + the request. If this fails for anybody, I wanna know about it + so I can come up with a better plan */ + + unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk; + junk = visual->red_mask; + rshift = 0; + while ((junk & 0x1) == 0) { + junk = junk >> 1; + rshift ++; + } + rbits = 0; + while (junk != 0) { + junk = junk >> 1; + rbits++; + } + junk = visual->green_mask; + gshift = 0; + while ((junk & 0x1) == 0) { + junk = junk >> 1; + gshift ++; + } + gbits = 0; + while (junk != 0) { + junk = junk >> 1; + gbits++; + } + junk = visual->blue_mask; + bshift = 0; + while ((junk & 0x1) == 0) { + junk = junk >> 1; + bshift ++; + } + bbits = 0; + while (junk != 0) { + junk = junk >> 1; + bbits++; + } + + color_def->red = color_def->red >> (16 - rbits); + color_def->green = color_def->green >> (16 - gbits); + color_def->blue = color_def->blue >> (16 - bbits); + if (XAllocColor (display, colormap, color_def) != 0) + status = 1; + else + { + int rd, gr, bl; + /* #### JH: I'm punting here, knowing that doing this will at + least draw the color correctly. However, unless we convert + all of the functions that allocate colors (graphics + libraries, etc) to use this function doing this is very + likely to cause problems later... */ + + if (rbits > 8) + rd = color_def->red << (rbits - 8); + else + rd = color_def->red >> (8 - rbits); + if (gbits > 8) + gr = color_def->green << (gbits - 8); + else + gr = color_def->green >> (8 - gbits); + if (bbits > 8) + bl = color_def->blue << (bbits - 8); + else + bl = color_def->blue >> (8 - bbits); + color_def->pixel = (rd << rshift) | (gr << gshift) | (bl << + bshift); + status = 3; + } + } + } + else + { + XColor *cells = NULL; + /* JH: I can't believe there's no way to go backwards from a + colormap ID and get its visual and number of entries, but X + apparently isn't built that way... */ + int no_cells = visual->map_entries; + status = 0; + + if (XAllocColor (display, colormap, color_def) != 0) + status = 1; + else while( status != 2 ) + { + /* If we got to this point, the colormap is full, so we're + going to try and get the next closest color. The algorithm used + is a least-squares matching, which is what X uses for closest + color matching with StaticColor visuals. */ + int nearest; + long nearest_delta, trial_delta; + int x; + + if( cells == NULL ) + { + /* #### this could be annoyingly slow + tell me again why lwlib can't use alloca & friends? */ + cells = (XColor *) malloc (sizeof(XColor)*no_cells); + for (x = 0; x < no_cells; x++) + cells[x].pixel = x; + + /* read the current colormap */ + XQueryColors (display, colormap, cells, no_cells); + } + + nearest = 0; + /* I'm assuming CSE so I'm not going to condense this. */ + nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8)) + * ((color_def->red >> 8) - (cells[0].red >> 8))) + + + (((color_def->green >> 8) - (cells[0].green >> 8)) + * ((color_def->green >> 8) - (cells[0].green >> + 8))) + + + (((color_def->blue >> 8) - (cells[0].blue >> 8)) + * ((color_def->blue >> 8) - (cells[0].blue >> + 8)))); + for (x = 1; x < no_cells; x++) + { + trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8)) + * ((color_def->red >> 8) - (cells[x].red >> 8))) + + + (((color_def->green >> 8) - (cells[x].green >> 8)) + * ((color_def->green >> 8) - (cells[x].green >> + 8))) + + + (((color_def->blue >> 8) - (cells[x].blue >> 8)) + * ((color_def->blue >> 8) - (cells[x].blue >> + 8)))); + + /* less? Ignore cells marked as previously failing */ + if( (trial_delta < nearest_delta) && + (cells[x].pixel != ULONG_MAX) ) + { + nearest = x; + nearest_delta = trial_delta; + } + } + color_def->red = cells[nearest].red; + color_def->green = cells[nearest].green; + color_def->blue = cells[nearest].blue; + if (XAllocColor (display, colormap, color_def) != 0) + status = 2; + else + /* LSK: Either the colour map has changed since + * we read it, or the colour is allocated + * read/write... Mark this cmap entry so it's + * ignored in the next iteration. + */ + cells[nearest].pixel = ULONG_MAX; + } + } + return status; +} + +#if 0 +/* Replacement for XAllocColor() that tries to return the nearest + available color if the colormap is full. From GNU Emacs. + #### Review this to see if there's anything our hairy version could use. */ + +int +FIXME_allocate_nearest_color (Display *display, Colormap screen_colormap, + XColor *color_def) +{ + int status = XAllocColor (display, screen_colormap, color_def); + if (status) + return status; + + { + /* If we got to this point, the colormap is full, so we're + going to try to get the next closest color. + The algorithm used is a least-squares matching, which is + what X uses for closest color matching with StaticColor visuals. */ + + int nearest, x; + unsigned long nearest_delta = ULONG_MAX; + + int no_cells = XDisplayCells (display, XDefaultScreen (display)); + /* Don't use alloca here because lwlib doesn't have the + necessary configuration information that src does. */ + XColor *cells = (XColor *) malloc (sizeof (XColor) * no_cells); + + for (x = 0; x < no_cells; x++) + cells[x].pixel = x; + + XQueryColors (display, screen_colormap, cells, no_cells); + + for (nearest = 0, x = 0; x < no_cells; x++) + { + long dred = (color_def->red >> 8) - (cells[x].red >> 8); + long dgreen = (color_def->green >> 8) - (cells[x].green >> 8); + long dblue = (color_def->blue >> 8) - (cells[x].blue >> 8); + unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue; + + if (delta < nearest_delta) + { + nearest = x; + nearest_delta = delta; + } + } + color_def->red = cells[nearest].red; + color_def->green = cells[nearest].green; + color_def->blue = cells[nearest].blue; + free (cells); + return XAllocColor (display, screen_colormap, color_def); + } +} +#endif + + +#ifdef USE_XFT + +XftColor +xft_convert_color (Display *dpy, Colormap cmap, Visual *visual, int c, int dim) +{ + static XColor color; /* #### why is this static ?? */ + XftColor result; + + color.pixel = c; + XQueryColor(dpy, cmap, &color); + + if (dim) + { + color.red = MINL (65535, color.red * 1.5); + color.green = MINL (65535, color.green * 1.5); + color.blue = MINL (65535, color.blue * 1.5); + x_allocate_nearest_color (dpy, cmap, visual, &color); + } + + result.pixel = color.pixel; + result.color.red = color.red; + result.color.green = color.green; + result.color.blue = color.blue; + result.color.alpha = 0xffff; + + return result; +} + +#endif /* USE_XFT */ + +/* end of lwlib-colors.c */