summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorArturo Espinosa <unammx@src.gnome.org>1997-12-17 00:14:36 +0000
committerArturo Espinosa <unammx@src.gnome.org>1997-12-17 00:14:36 +0000
commit585dc6d78179c7eea1b62d5cd746d69e8aec4a32 (patch)
treef0f48dac72f730c93f25ba8df7e6b95bb06bdc08 /gdk
parentad5083714e45a676886b8289516db40bb0397056 (diff)
downloadgtk+-585dc6d78179c7eea1b62d5cd746d69e8aec4a32.tar.gz
New GdkColorContext object, ported from the XColorContext in XmHTML.
It compiles and links, but is *completely* untested. Feel free to pound on it. The idea is to do all color management (allocation, etc.) via a GdkColorContext so that apps will be friendly to 8-bit displays. GdkColorContext is supposed to work on all visual/depth combinations. This support, however, is lacking from the rest of Gdk/Gtk. I will try to work on that. - Federico
Diffstat (limited to 'gdk')
-rw-r--r--gdk/Makefile.am1
-rw-r--r--gdk/Makefile.in61
-rw-r--r--gdk/gdk.h57
-rw-r--r--gdk/gdkcc.c1679
-rw-r--r--gdk/gdkprivate.h72
-rw-r--r--gdk/gdktypes.h71
-rw-r--r--gdk/x11/gdkcc-x11.c1679
7 files changed, 3558 insertions, 62 deletions
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index 6956b30ae2..3e34aa4c23 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -6,6 +6,7 @@ lib_LTLIBRARIES = libgdk.la
libgdk_la_SOURCES = \
gdk.c \
+ gdkcc.c \
gdkcolor.c \
gdkcursor.c \
gdkdraw.c \
diff --git a/gdk/Makefile.in b/gdk/Makefile.in
index a39837c3bc..70ab78a3b1 100644
--- a/gdk/Makefile.in
+++ b/gdk/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated automatically by automake 1.2d from Makefile.am
+# Makefile.in generated automatically by automake 1.2c from Makefile.am
# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
@@ -49,12 +49,12 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
+NORMAL_INSTALL = true
+PRE_INSTALL = true
+POST_INSTALL = true
+NORMAL_UNINSTALL = true
+PRE_UNINSTALL = true
+POST_UNINSTALL = true
host_alias = @host_alias@
host_triplet = @host@
CC = @CC@
@@ -78,6 +78,7 @@ lib_LTLIBRARIES = libgdk.la
libgdk_la_SOURCES = \
gdk.c \
+ gdkcc.c \
gdkcolor.c \
gdkcursor.c \
gdkdraw.c \
@@ -145,7 +146,7 @@ X_LIBS = @X_LIBS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
libgdk_la_LIBADD =
-libgdk_la_OBJECTS = gdk.lo gdkcolor.lo gdkcursor.lo gdkdraw.lo \
+libgdk_la_OBJECTS = gdk.lo gdkcc.lo gdkcolor.lo gdkcursor.lo gdkdraw.lo \
gdkfont.lo gdkgc.lo gdkglobals.lo gdkimage.lo gdkinput.lo gdkpixmap.lo \
gdkproperty.lo gdkrectangle.lo gdkselection.lo gdkvisual.lo \
gdkwindow.lo gdkxid.lo gxid_lib.lo
@@ -165,20 +166,21 @@ DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP = --best
-DEP_FILES = .deps/gdk.P .deps/gdkcolor.P .deps/gdkcursor.P \
-.deps/gdkdraw.P .deps/gdkfont.P .deps/gdkgc.P .deps/gdkglobals.P \
-.deps/gdkimage.P .deps/gdkinput.P .deps/gdkpixmap.P .deps/gdkproperty.P \
-.deps/gdkrectangle.P .deps/gdkselection.P .deps/gdkvisual.P \
-.deps/gdkwindow.P .deps/gdkxid.P .deps/gxid.P .deps/gxid_lib.P
+DEP_FILES = .deps/gdk.P .deps/gdkcc.P .deps/gdkcolor.P \
+.deps/gdkcursor.P .deps/gdkdraw.P .deps/gdkfont.P .deps/gdkgc.P \
+.deps/gdkglobals.P .deps/gdkimage.P .deps/gdkinput.P .deps/gdkpixmap.P \
+.deps/gdkproperty.P .deps/gdkrectangle.P .deps/gdkselection.P \
+.deps/gdkvisual.P .deps/gdkwindow.P .deps/gdkxid.P .deps/gxid.P \
+.deps/gxid_lib.P
SOURCES = $(libgdk_la_SOURCES) $(gxid_SOURCES)
OBJECTS = $(libgdk_la_OBJECTS) $(gxid_OBJECTS)
default: all
.SUFFIXES:
-.SUFFIXES: .S .c .lo .o .s
+.SUFFIXES: .c .lo .o
$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu gdk/Makefile
@@ -201,8 +203,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES)
$(mkinstalldirs) $(libdir)
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
if test -f $$p; then \
- echo "$(LIBTOOL) --mode=install $(INSTALL_DATA) $$p $(libdir)/$$p"; \
- $(LIBTOOL) --mode=install $(INSTALL_DATA) $$p $(libdir)/$$p; \
+ echo "$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(libdir)/$$p"; \
+ $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(libdir)/$$p; \
else :; fi; \
done
@@ -215,12 +217,6 @@ uninstall-libLTLIBRARIES:
.c.o:
$(COMPILE) -c $<
-.s.o:
- $(COMPILE) -c $<
-
-.S.o:
- $(COMPILE) -c $<
-
mostlyclean-compile:
-rm -f *.o core
@@ -234,17 +230,11 @@ maintainer-clean-compile:
.c.lo:
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
-.s.lo:
- $(LIBTOOL) --mode=compile $(COMPILE) -c $<
-
-.S.lo:
- $(LIBTOOL) --mode=compile $(COMPILE) -c $<
-
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
- -rm -rf .libs _libs
+ -rm -rf .libs
distclean-libtool:
@@ -298,15 +288,14 @@ uninstall-gdkincludeHEADERS:
tags: TAGS
-ID: $(HEADERS) $(SOURCES) $(LISP)
- here=`pwd` && cd $(srcdir) \
- && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
- test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$(LISP)$$tags" \
- || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) $(LISP) -o $$here/TAGS)
+ test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
diff --git a/gdk/gdk.h b/gdk/gdk.h
index fb7d61e1b7..33a2054a24 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -648,6 +648,63 @@ GdkEventMask gdk_ic_get_events (GdkIC ic);
/* Miscellaneous */
void gdk_event_send_clientmessage_toall(GdkEvent *event);
+/* Color Context */
+
+GdkColorContext *gdk_color_context_new (GdkVisual *visual,
+ GdkColormap *colormap);
+
+GdkColorContext *gdk_color_context_new_mono (GdkVisual *visual,
+ GdkColormap *colormap);
+
+void gdk_color_context_free (GdkColorContext *cc);
+
+gulong gdk_color_context_get_pixel (GdkColorContext *cc,
+ gushort red,
+ gushort green,
+ gushort blue,
+ gint *failed);
+void gdk_color_context_get_pixels (GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gulong *colors,
+ gint *nallocated);
+void gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gint *used,
+ gulong *colors,
+ gint *nallocated);
+
+gint gdk_color_context_get_num_colors (GdkColorContext *cc);
+gint gdk_color_context_query_color (GdkColorContext *cc,
+ GdkColor *color);
+gint gdk_color_context_query_colors (GdkColorContext *cc,
+ GdkColor *colors,
+ gint num_colors);
+
+gint gdk_color_context_add_palette (GdkColorContext *cc,
+ GdkColor *palette,
+ gint num_palette);
+
+void gdk_color_context_init_dither (GdkColorContext *cc);
+void gdk_color_context_free_dither (GdkColorContext *cc);
+
+gulong gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
+ gushort *red,
+ gushort *green,
+ gushort *blue,
+ gint *failed);
+guchar gdk_color_context_get_index_from_palette (GdkColorContext *cc,
+ gint *red,
+ gint *green,
+ gint *blue,
+ gint *failed);
+
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gdk/gdkcc.c b/gdk/gdkcc.c
new file mode 100644
index 0000000000..0b089208d2
--- /dev/null
+++ b/gdk/gdkcc.c
@@ -0,0 +1,1679 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Color Context module
+ * Copyright 1994,1995 John L. Cwikla
+ * Copyright (C) 1997 by Ripley Software Development
+ * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
+ */
+
+/* Copyright 1994,1995 John L. Cwikla
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of John L. Cwikla or
+ * Wolfram Research, Inc not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission. John L. Cwikla and Wolfram Research, Inc make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
+ * regard to this software, including all implied warranties of
+ * merchantability and fitness, in no event shall John L. Cwikla or
+ * Wolfram Research, Inc be liable for any special, indirect or
+ * consequential damages or any damages whatsoever resulting from loss of
+ * use, data or profits, whether in an action of contract, negligence or
+ * other tortious action, arising out of or in connection with the use or
+ * performance of this software.
+ *
+ * Author:
+ * John L. Cwikla
+ * X Programmer
+ * Wolfram Research Inc.
+ *
+ * cwikla@wri.com
+ */
+
+/* NOTES:
+ *
+ * - When a CC is destroyed, remember to destroy the hash table properly.
+ */
+
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+
+#define MAX_IMAGE_COLORS 256
+
+
+static guint
+hash_color(gpointer key)
+{
+ GdkColor *color = key;
+
+ return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
+}
+
+static gint
+compare_colors(gpointer a, gpointer b)
+{
+ GdkColor *aa = a;
+ GdkColor *bb = b;
+
+ return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
+}
+
+static void
+free_hash_entry(gpointer key, gpointer value, gpointer user_data)
+{
+ g_free(key); /* key and value are the same GdkColor */
+}
+
+static int
+pixel_sort(const void *a, const void *b)
+{
+ return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
+}
+
+/* XXX: This function does an XQueryColors() the hard way, because there is
+ * no corresponding function in Gdk.
+ */
+
+static void
+my_x_query_colors(GdkColormap *colormap,
+ GdkColor *colors,
+ gint ncolors)
+{
+ XColor *xcolors;
+ gint i;
+
+ xcolors = g_new(XColor, ncolors);
+ for (i = 0; i < ncolors; i++)
+ xcolors[i].pixel = colors[i].pixel;
+
+ XQueryColors(gdk_display, GDK_COLORMAP_XCOLORMAP(colormap), xcolors, ncolors);
+
+ for (i = 0; i < ncolors; i++) {
+ colors[i].red = xcolors[i].red;
+ colors[i].green = xcolors[i].green;
+ colors[i].blue = xcolors[i].blue;
+ }
+
+ g_free(xcolors);
+}
+
+static void
+query_colors(GdkColorContextPrivate *cc)
+{
+ gint i;
+
+ cc->cmap = g_new(GdkColor, cc->num_colors);
+
+ for (i = 0; i < cc->num_colors; i++)
+ cc->cmap[i].pixel = cc->clut ? cc->clut[i] : cc->std_cmap.base_pixel + i;
+
+ my_x_query_colors(cc->colormap, cc->cmap, cc->num_colors);
+
+ qsort(cc->cmap, cc->num_colors, sizeof(GdkColor), pixel_sort);
+}
+
+static void
+init_bw(GdkColorContextPrivate *cc)
+{
+ GdkColor color;
+
+ g_warning("init_bw: failed to allocate colors, falling back to black and white");
+
+ cc->mode = GDK_CC_MODE_BW;
+
+ color.red = color.green = color.blue = 0;
+ if (!gdk_color_alloc(cc->colormap, &color))
+ cc->black_pixel = 0;
+ else
+ cc->black_pixel = color.pixel;
+
+ color.red = color.green = color.blue = 0xffff;
+ if (!gdk_color_alloc(cc->colormap, &color))
+ cc->white_pixel = cc->black_pixel ? 0 : 1;
+ else
+ cc->white_pixel = color.pixel;
+
+ cc->num_colors = 2;
+}
+
+static void
+init_gray(GdkColorContextPrivate *cc)
+{
+ GdkColor *clrs, *cstart;
+ gint i;
+ gdouble dinc;
+
+ cc->num_colors = GDK_VISUAL_XVISUAL(cc->visual)->map_entries;
+
+ cc->clut = g_new(gulong, cc->num_colors);
+ cstart = g_new(GdkColor, cc->num_colors);
+
+retrygray:
+
+ dinc = 65535.0 / (cc->num_colors - 1);
+
+ clrs = cstart;
+
+ for (i = 0; i < cc->num_colors; i++) {
+ clrs->red = clrs->green = clrs->blue = dinc * i;
+
+ if (!gdk_color_alloc(cc->colormap, clrs)) {
+ gdk_colors_free(cc->colormap, cc->clut, i, 0);
+
+ cc->num_colors /= 2;
+
+ if (cc->num_colors > 1)
+ goto retrygray;
+ else {
+ g_free(cc->clut);
+ cc->clut = NULL;
+ init_bw(cc);
+ g_free(cstart);
+ return;
+ }
+ }
+
+ cc->clut[i] = clrs++->pixel;
+ }
+
+ g_free(cstart);
+
+ /* XXX: is this the right thing to do? */
+ cc->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP(cc->colormap);
+ cc->std_cmap.base_pixel = 0;
+ cc->std_cmap.red_max = cc->num_colors - 1;
+ cc->std_cmap.green_max = 0;
+ cc->std_cmap.blue_max = 0;
+ cc->std_cmap.red_mult = 1;
+ cc->std_cmap.green_mult = 0;
+ cc->std_cmap.blue_mult = 0;
+
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+
+ query_colors(cc);
+
+ cc->mode = GDK_CC_MODE_MY_GRAY;
+}
+
+static void
+init_color(GdkColorContextPrivate *cc)
+{
+ gint cubeval;
+
+ cubeval = 1;
+ while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL(cc->visual)->map_entries)
+ cubeval++;
+ cubeval--;
+
+ cc->num_colors = cubeval * cubeval * cubeval;
+
+ cc->std_cmap.red_max = cubeval - 1;
+ cc->std_cmap.green_max = cubeval - 1;
+ cc->std_cmap.blue_max = cubeval - 1;
+ cc->std_cmap.red_mult = cubeval * cubeval;
+ cc->std_cmap.green_mult = cubeval;
+ cc->std_cmap.blue_mult = 1;
+ cc->std_cmap.base_pixel = 0;
+
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+ cc->num_colors = DisplayCells(cc->xdisplay, gdk_screen);
+
+ /* a CLUT for storing allocated pixel indices */
+
+ cc->max_colors = cc->num_colors;
+ cc->clut = g_new(gulong, cc->max_colors);
+
+ for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
+ cc->clut[cubeval] = cubeval;
+
+ query_colors(cc);
+
+ cc->mode = GDK_CC_MODE_STD_CMAP;
+}
+
+
+static void
+init_true_color(GdkColorContextPrivate *cc)
+{
+ gulong rmask, gmask, bmask;
+
+ cc->mode = GDK_CC_MODE_TRUE;
+
+ /* Red */
+
+ rmask = cc->masks.red = cc->visual->red_mask;
+
+ cc->shifts.red = 0;
+ cc->bits.red = 0;
+
+ while (!(rmask & 1)) {
+ rmask >>= 1;
+ cc->shifts.red++;
+ }
+
+ while (rmask & 1) {
+ rmask >>= 1;
+ cc->bits.red++;
+ }
+
+ /* Green */
+
+ gmask = cc->masks.green = cc->visual->green_mask;
+
+ cc->shifts.green = 0;
+ cc->bits.green = 0;
+
+ while (!(gmask & 1)) {
+ gmask >>= 1;
+ cc->shifts.green++;
+ }
+
+ while (gmask & 1) {
+ gmask >>= 1;
+ cc->bits.green++;
+ }
+
+ /* Blue */
+
+ bmask = cc->masks.blue = cc->visual->blue_mask;
+
+ cc->shifts.blue = 0;
+ cc->bits.blue = 0;
+
+ while (!(bmask & 1)) {
+ bmask >>= 1;
+ cc->shifts.blue++;
+ }
+
+ while (bmask & 1) {
+ bmask >>= 1;
+ cc->bits.blue++;
+ }
+
+ cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+}
+
+static void
+init_direct_color(GdkColorContextPrivate *cc)
+{
+ gint n, count;
+ GdkColor *clrs, *cstart;
+ gulong rval, gval, bval;
+ gulong *rtable;
+ gulong *gtable;
+ gulong *btable;
+ gdouble dinc;
+
+ init_true_color(cc); /* for shift stuff */
+
+ rval = cc->visual->red_mask >> cc->shifts.red;
+ gval = cc->visual->green_mask >> cc->shifts.green;
+ bval = cc->visual->blue_mask >> cc->shifts.blue;
+
+ rtable = g_new(gulong, rval + 1);
+ gtable = g_new(gulong, gval + 1);
+ btable = g_new(gulong, bval + 1);
+
+ cc->max_entry = MAX(rval, gval);
+ cc->max_entry = MAX(cc->max_entry, bval);
+
+ cstart = g_new(GdkColor, cc->max_entry + 1);
+ cc->clut = g_new(gulong, cc->max_entry + 1);
+
+retrydirect:
+
+ for (n = 0; n < rval; n++)
+ rtable[n] = rval ? (65535.0 / rval * n) : 0;
+
+ for (n = 0; n < gval; n++)
+ gtable[n] = gval ? (65535.0 / gval * n) : 0;
+
+ for (n = 0; n < bval; n++)
+ btable[n] = bval ? (65535.0 / bval * n) : 0;
+
+ cc->max_entry = MAX(rval, gval);
+ cc->max_entry = MAX(cc->max_entry, bval);
+
+ count = 0;
+ clrs = cstart;
+ cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
+
+ for (n = 0; n < cc->max_entry; n++) {
+ dinc = (double) n / cc->max_entry;
+
+ clrs->red = rtable[(int) (dinc * rval)];
+ clrs->green = gtable[(int) (dinc * gval)];
+ clrs->blue = btable[(int) (dinc * bval)];
+
+ if (gdk_color_alloc(cc->colormap, clrs)) {
+ cc->clut[count++] = clrs->pixel;
+ clrs++;
+ } else {
+ gdk_colors_free(cc->colormap, cc->clut, count, 0);
+
+ rval >>= 1;
+ gval >>= 1;
+ bval >>= 1;
+
+ cc->masks.red = (cc->masks.red >> 1) & cc->visual->red_mask;
+ cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
+ cc->masks.blue = (cc->masks.blue >> 1) & cc->visual->blue_mask;
+
+ cc->shifts.red++;
+ cc->shifts.green++;
+ cc->shifts.blue++;
+
+ cc->bits.red--;
+ cc->bits.green--;
+ cc->bits.blue--;
+
+ cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
+
+ if (cc->num_colors >1)
+ goto retrydirect;
+ else {
+ g_free(cc->clut);
+ cc->clut = NULL;
+ init_bw(cc);
+ break;
+ }
+ }
+ }
+
+ /* Update allocated color count; original num_colors is max_entry, which
+ * is not necessarily the same as the really allocated number of colors.
+ */
+
+ cc->num_colors = count;
+
+ g_free(rtable);
+ g_free(gtable);
+ g_free(btable);
+ g_free(cstart);
+}
+
+static void
+init_palette(GdkColorContextPrivate *cc)
+{
+ /* restore correct mode for this cc */
+
+ switch (cc->visual->type) {
+ case GDK_VISUAL_STATIC_GRAY:
+ case GDK_VISUAL_GRAYSCALE:
+ if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
+ cc->mode = GDK_CC_MODE_BW;
+ else
+ cc->mode = GDK_CC_MODE_MY_GRAY;
+ break;
+
+ case GDK_VISUAL_TRUE_COLOR:
+ case GDK_VISUAL_DIRECT_COLOR:
+ cc->mode = GDK_CC_MODE_TRUE;
+ break;
+
+ case GDK_VISUAL_STATIC_COLOR:
+ case GDK_VISUAL_PSEUDO_COLOR:
+ cc->mode = GDK_CC_MODE_STD_CMAP;
+ break;
+
+ default:
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ break;
+ }
+
+ /* previous palette */
+
+ if (cc->num_palette)
+ g_free(cc->palette);
+
+ if (cc->fast_dither)
+ g_free(cc->fast_dither);
+
+ /* clear hash table if present */
+
+ if (cc->color_hash) {
+ /* XXX: quick-and-dirty way to remove everything */
+
+ g_hash_table_destroy(cc->color_hash);
+ cc->color_hash = g_hash_table_new(hash_color, compare_colors);
+ }
+
+ cc->palette = NULL;
+ cc->num_palette = 0;
+ cc->fast_dither = NULL;
+}
+
+GdkColorContext *
+gdk_color_context_new(GdkVisual *visual,
+ GdkColormap *colormap)
+{
+ gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
+ GdkColorContextPrivate *cc;
+ gint retry_count;
+ GdkColormap *default_colormap;
+
+ g_assert(visual != NULL);
+ g_assert(colormap != NULL);
+
+ cc = g_new(GdkColorContextPrivate, 1);
+
+ cc->xdisplay = gdk_display;
+ cc->visual = visual;
+ cc->colormap = colormap;
+ cc->clut = NULL;
+ cc->cmap = NULL;
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ cc->need_to_free_colormap = FALSE;
+
+ cc->color_hash = NULL;
+ cc->palette = NULL;
+ cc->num_palette = 0;
+ cc->fast_dither = NULL;
+
+ default_colormap = gdk_colormap_get_system();
+
+ retry_count = 0;
+
+ while (retry_count < 2) {
+ /* Only create a private colormap if the visual found isn't equal
+ * to the default visual and we don't have a private colormap,
+ * -or- if we are instructed to create a private colormap (which
+ * never is the case for XmHTML).
+ */
+
+ if (use_private_colormap
+ || ((cc->visual != gdk_visual_get_system()) /* default visual? */
+ && (GDK_COLORMAP_XCOLORMAP(colormap) == GDK_COLORMAP_XCOLORMAP(default_colormap)))) {
+ g_warning("gdk_color_context_new: non-default visual detected, "
+ "using private colormap");
+
+ cc->colormap = gdk_colormap_new(cc->visual, FALSE);
+
+ cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP(colormap)
+ != GDK_COLORMAP_XCOLORMAP(default_colormap));
+ }
+
+ switch (visual->type) {
+ case GDK_VISUAL_STATIC_GRAY:
+ case GDK_VISUAL_GRAYSCALE:
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is %s",
+ (visual->type == GDK_VISUAL_STATIC_GRAY) ?
+ "GDK_VISUAL_STATIC_GRAY" :
+ "GDK_VISUAL_GRAYSCALE");
+
+ if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
+ init_bw(cc);
+ else
+ init_gray(cc);
+
+ break;
+
+ case GDK_VISUAL_TRUE_COLOR: /* shifts */
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is "
+ "GDK_VISUAL_TRUE_COLOR");
+
+ init_true_color(cc);
+ break;
+
+ case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is "
+ "GDK_VISUAL_DIRECT_COLOR");
+
+ init_direct_color(cc);
+ break;
+
+ case GDK_VISUAL_STATIC_COLOR:
+ case GDK_VISUAL_PSEUDO_COLOR:
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is %s",
+ (visual->type == GDK_VISUAL_STATIC_COLOR) ?
+ "GDK_VISUAL_STATIC_COLOR" :
+ "GDK_VISUAL_PSEUDO_COLOR");
+
+ init_color(cc);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1)) {
+ use_private_colormap = TRUE;
+ retry_count++;
+ } else
+ break;
+ }
+
+ /* no. of colors allocated yet */
+
+ cc->num_allocated = 0;
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: screen depth is %i, no. of colors is %i",
+ cc->visual->depth, cc->num_colors);
+
+ /* check if we need to initialize a hash table */
+
+ if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
+ cc->color_hash = g_hash_table_new(hash_color, compare_colors);
+
+ return (GdkColorContext *) cc;
+}
+
+GdkColorContext *
+gdk_color_context_new_mono(GdkVisual *visual,
+ GdkColormap *colormap)
+{
+ GdkColorContextPrivate *cc;
+
+ g_assert(visual != NULL);
+ g_assert(colormap != NULL);
+
+ cc = g_new(GdkColorContextPrivate, 1);
+
+ cc->xdisplay = gdk_display;
+ cc->visual = visual;
+ cc->colormap = colormap;
+ cc->clut = NULL;
+ cc->cmap = NULL;
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ cc->need_to_free_colormap = FALSE;
+
+ init_bw(cc);
+
+ return (GdkColorContext *) cc;
+}
+
+/* This doesn't currently free black/white, hmm... */
+
+void
+gdk_color_context_free(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ if ((ccp->visual->type == GDK_VISUAL_STATIC_COLOR)
+ || (ccp->visual->type == GDK_VISUAL_PSEUDO_COLOR)) {
+ gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_allocated, 0);
+ g_free(ccp->clut);
+ } else if (ccp->clut != NULL) {
+ gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_colors, 0);
+ g_free(ccp->clut);
+ }
+
+ if (ccp->cmap != NULL)
+ g_free(ccp->cmap);
+
+ if (ccp->need_to_free_colormap)
+ gdk_colormap_destroy(ccp->colormap);
+
+ /* free any palette that has been associated with this GdkColorContext */
+
+ init_palette(ccp);
+
+ if (ccp->color_hash) {
+ g_hash_table_foreach(ccp->color_hash,
+ free_hash_entry,
+ NULL);
+ g_hash_table_destroy(ccp->color_hash);
+ }
+
+ g_free(cc);
+}
+
+gulong
+gdk_color_context_get_pixel(GdkColorContext *cc,
+ gushort red,
+ gushort green,
+ gushort blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ switch (ccp->mode) {
+ case GDK_CC_MODE_BW: {
+ gdouble value;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ value = red / 65535.0 * 0.30
+ + green / 65535.0 * 0.59
+ + blue / 65535.0 * 0.11;
+
+ if (value > 0.5)
+ return ccp->white_pixel;
+
+ return ccp->black_pixel;
+ }
+
+ case GDK_CC_MODE_MY_GRAY: {
+ gulong ired, igreen, iblue;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ red = red * 0.30 + green * 0.59 + blue * 0.11;
+ green = 0;
+ blue = 0;
+
+ if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff)
+ > ccp->std_cmap.red_max)
+ ired = ccp->std_cmap.red_max;
+
+ ired *= ccp->std_cmap.red_mult;
+
+ if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff)
+ > ccp->std_cmap.green_max)
+ igreen = ccp->std_cmap.green_max;
+
+ igreen *= ccp->std_cmap.green_mult;
+
+ if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff)
+ > ccp->std_cmap.blue_max)
+ iblue = ccp->std_cmap.blue_max;
+
+ iblue *= ccp->std_cmap.blue_mult;
+
+ if (ccp->clut != NULL)
+ return ccp->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
+
+ return ccp->std_cmap.base_pixel + ired + igreen + iblue;
+ }
+
+ case GDK_CC_MODE_TRUE: {
+ gulong ired, igreen, iblue;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ if (ccp->clut == NULL) {
+ red >>= 16 - ccp->bits.red;
+ green >>= 16 - ccp->bits.green;
+ blue >>= 16 - ccp->bits.blue;
+
+ ired = (red << ccp->shifts.red) & ccp->masks.red;
+ igreen = (green << ccp->shifts.green) & ccp->masks.green;
+ iblue = (blue << ccp->shifts.blue) & ccp->masks.blue;
+
+ return ired | igreen | iblue;
+ }
+
+ ired = ccp->clut[red * ccp->max_entry / 65535] & ccp->masks.red;
+ igreen = ccp->clut[green * ccp->max_entry / 65535] & ccp->masks.green;
+ iblue = ccp->clut[blue * ccp->max_entry / 65535] & ccp->masks.blue;
+
+ return ired | igreen | iblue;
+ }
+
+ case GDK_CC_MODE_PALETTE:
+ return gdk_color_context_get_pixel_from_palette(cc, &red, &green, &blue, failed);
+
+ case GDK_CC_MODE_STD_CMAP:
+ default: {
+ GdkColor color;
+ GdkColor *result;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ color.red = red;
+ color.green = green;
+ color.blue = blue;
+
+ result = g_hash_table_lookup(ccp->color_hash, &color);
+
+ if (!result) {
+ color.red = red;
+ color.green = green;
+ color.blue = blue;
+ color.pixel = 0;
+
+ if (!gdk_color_alloc(ccp->colormap, &color))
+ *failed = TRUE;
+ else {
+ GdkColor *cnew;
+
+ /* XXX: the following comment comes directly from
+ * XCC.c. I don't know if it is relevant for
+ * gdk_color_alloc() as it is for XAllocColor()
+ * - Federico
+ */
+ /*
+ * I can't figure this out entirely, but it *is* possible
+ * that XAllocColor succeeds, even if the number of
+ * allocations we've made exceeds the number of available
+ * colors in the current colormap. And therefore it
+ * might be necessary for us to resize the CLUT.
+ */
+
+ if (ccp->num_allocated == ccp->max_colors) {
+ ccp->max_colors *= 2;
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixel: "
+ "resizing CLUT to %i entries",
+ ccp->max_colors);
+
+ ccp->clut = g_realloc(ccp->clut,
+ ccp->max_colors * sizeof(gulong));
+ }
+
+ /* Key and value are the same color structure */
+
+ cnew = g_new(GdkColor, 1);
+ *cnew = color;
+ g_hash_table_insert(ccp->color_hash, cnew, cnew);
+
+ ccp->clut[ccp->num_allocated] = color.pixel;
+ ccp->num_allocated++;
+ return color.pixel;
+ }
+ }
+
+ return result->pixel;
+ }
+ }
+}
+
+void
+gdk_color_context_get_pixels(GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gulong *colors,
+ gint *nallocated)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, k, idx;
+ gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+ gint bad_alloc = FALSE;
+ gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+ GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+ gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+
+ g_assert(cc != NULL);
+ g_assert(reds != NULL);
+ g_assert(greens != NULL);
+ g_assert(blues != NULL);
+ g_assert(colors != NULL);
+ g_assert(nallocated != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
+ memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
+ memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
+
+ /* Will only have a value if used by the progressive image loader */
+
+ ncols = *nallocated;
+
+ *nallocated = 0;
+
+ /* First allocate all pixels */
+
+ for (i = 0; i < ncolors; i++) {
+ /* colors[i] is only zero if the pixel at that location hasn't
+ * been allocated yet. This is a sanity check required for proper
+ * color allocation by the progressive image loader
+ */
+
+ if (colors[i] == 0) {
+ defs[i].red = reds[i];
+ defs[i].green = greens[i];
+ defs[i].blue = blues[i];
+
+ colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i],
+ &bad_alloc);
+
+ /* successfully allocated, store it */
+
+ if (!bad_alloc) {
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+ } else
+ failed[nopen++] = i;
+ }
+ }
+
+ *nallocated = ncols;
+
+ /* all colors available, all done */
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got all %i colors; "
+ "(%i colors allocated so far", ncolors, ccp->num_allocated);
+
+ return;
+ }
+
+ /* The fun part. We now try to allocate the colors we couldn't allocate
+ * directly. The first step will map a color onto its nearest color
+ * that has been allocated (either by us or someone else). If any colors
+ * remain unallocated, we map these onto the colors that we have allocated
+ * ourselves.
+ */
+
+ /* read up to MAX_IMAGE_COLORS colors of the current colormap */
+
+ cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
+
+ /* see if the colormap has any colors to read */
+
+ if (cmapsize < 0) {
+ g_warning("gdk_color_context_get_pixels: oops! no colors available, "
+ "your images will look *really* ugly.");
+
+ return;
+ }
+
+#ifdef DEBUG
+ exact_col = ncols;
+#endif
+
+ /* initialize pixels */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].pixel = i;
+ cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+ }
+
+ /* read the colormap */
+
+ my_x_query_colors(ccp->colormap, cmap, cmapsize);
+
+ /* speedup: downscale here instead of in the matching code */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].red >>= 8;
+ cmap[i].green >>= 8;
+ cmap[i].blue >>= 8;
+ }
+
+ /* get a close match for any unallocated colors */
+
+ counter = nopen;
+ nopen = 0;
+ idx = 0;
+
+ do {
+ gint d, j, mdist, close, ri, gi, bi;
+ gint rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* Store these vals. Small performance increase as this skips three
+ * indexing operations in the loop code.
+ */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* Walk all colors in the colormap and see which one is the
+ * closest. Uses plain least squares.
+ */
+
+ for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
+ rd = ri - cmap[j].red;
+ gd = gi - cmap[j].green;
+ bd = bi - cmap[j].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = j;
+ mdist = d;
+ }
+ }
+
+ if (close != -1) {
+ rd = cmap[close].red;
+ gd = cmap[close].green;
+ bd = cmap[close].blue;
+
+ /* allocate */
+
+ colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
+
+ /* store */
+
+ if (!bad_alloc) {
+ defs[i] = cmap[close];
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+#ifdef DEBUG
+ close_col++;
+#endif
+ } else
+ failed[nopen++] = i;
+ } else
+ failed[nopen++] = i;
+ /* deal with in next stage if allocation failed */
+ } while (++idx < counter);
+
+ *nallocated = ncols;
+
+ /* This is the maximum no. of allocated colors. See also the nopen == 0
+ * note above.
+ */
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got %i colors, %i exact and "
+ "%i close (%i colors allocated so far)",
+ ncolors, exact_col, close_col, ccp->num_allocated);
+
+ return;
+ }
+
+ /* Now map any remaining unallocated pixels into the colors we did get */
+
+ idx = 0;
+
+ do {
+ gint d, mdist, close, ri, gi, bi;
+ gint j, rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* store */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* search allocated colors */
+
+ for (j = 0; (j < ncols) && (mdist != 0); j++) {
+ k = allocated[j];
+
+ rd = ri - defs[k].red;
+ gd = gi - defs[k].green;
+ bd = bi - defs[k].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = k;
+ mdist = d;
+ }
+ }
+
+ if (close < 0) {
+ /* too bad, map to black */
+
+ defs[i].pixel = ccp->black_pixel;
+ defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef DEBUG
+ black_col++;
+#endif
+ } else {
+ defs[i] = defs[close];
+#ifdef DEBUG
+ subst_col++;
+#endif
+ }
+
+ colors[i] = defs[i].pixel;
+ } while (++idx < nopen);
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
+ "%i substituted, %i to black (%i colors allocated so far)",
+ ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
+}
+
+void
+gdk_color_context_get_pixels_incremental(GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gint *used,
+ gulong *colors,
+ gint *nallocated)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, k, idx;
+ gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+ gint bad_alloc = FALSE;
+ gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+ GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+ gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+
+ g_assert(cc != NULL);
+ g_assert(reds != NULL);
+ g_assert(greens != NULL);
+ g_assert(blues != NULL);
+ g_assert(used != NULL);
+ g_assert(colors != NULL);
+ g_assert(nallocated != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
+ memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
+ memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
+
+ /* Will only have a value if used by the progressive image loader */
+
+ ncols = *nallocated;
+
+ *nallocated = 0;
+
+ /* First allocate all pixels */
+
+ for (i = 0; i < ncolors; i++) {
+ /* used[i] is only -1 if the pixel at that location hasn't
+ * been allocated yet. This is a sanity check required for proper
+ * color allocation by the progressive image loader.
+ * When colors[i] == 0 it indicates the slot is available for
+ * allocation.
+ */
+
+ if (used[i] != FALSE) {
+ if (colors[i] == 0) {
+ defs[i].red = reds[i];
+ defs[i].green = greens[i];
+ defs[i].blue = blues[i];
+
+ colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i], &bad_alloc);
+
+ /* successfully allocated, store it */
+
+ if (!bad_alloc) {
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+ } else
+ failed[nopen++] = i;
+ }
+#ifdef DEBUG
+ else
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "pixel at slot %i already allocated, skipping", i);
+#endif
+ }
+ }
+
+ *nallocated = ncols;
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: got all %i colors "
+ "(%i colors allocated so far)",
+ ncolors, ccp->num_allocated);
+
+ return;
+ }
+
+ cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
+
+ if (cmapsize < 0) {
+ g_warning("gdk_color_context_get_pixels_incremental: oops! "
+ "No colors available images will look *really* ugly.");
+ return;
+ }
+
+#ifdef DEBUG
+ exact_col = ncols;
+#endif
+
+ /* initialize pixels */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].pixel = i;
+ cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+ }
+
+ /* read and downscale */
+
+ my_x_query_colors(ccp->colormap, cmap, cmapsize);
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].red >>= 8;
+ cmap[i].green >>= 8;
+ cmap[i].blue >>= 8;
+ }
+
+ /* now match any unallocated colors */
+
+ counter = nopen;
+ nopen = 0;
+ idx = 0;
+
+ do {
+ gint d, j, mdist, close, ri, gi, bi;
+ gint rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* store */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
+ rd = ri - cmap[j].red;
+ gd = gi - cmap[j].green;
+ bd = bi - cmap[j].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = j;
+ mdist = d;
+ }
+ }
+
+ if (close != -1) {
+ rd = cmap[close].red;
+ gd = cmap[close].green;
+ bd = cmap[close].blue;
+
+ /* allocate */
+
+ colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
+
+ /* store */
+
+ if (!bad_alloc) {
+ defs[i] = cmap[close];
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+#ifdef DEBUG
+ close_col++;
+#endif
+ } else
+ failed[nopen++] = i;
+ } else
+ failed[nopen++] = i;
+ /* deal with in next stage if allocation failed */
+ } while (++idx < counter);
+
+ *nallocated = ncols;
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "got %i colors, %i exact and %i close "
+ "(%i colors allocated so far)",
+ ncolors, exact_col, close_col, ccp->num_allocated);
+
+ return;
+ }
+
+ /* map remaining unallocated pixels into colors we did get */
+
+ idx = 0;
+
+ do {
+ gint d, mdist, close, ri, gi, bi;
+ gint j, rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* search allocated colors */
+
+ for (j = 0; (j < ncols) && (mdist != 0); j++) {
+ k = allocated[j];
+
+ /* downscale */
+
+ rd = ri - defs[k].red;
+ gd = gi - defs[k].green;
+ bd = bi - defs[k].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = k;
+ mdist = d;
+ }
+ }
+
+ if (close < 0) {
+ /* too bad, map to black */
+
+ defs[i].pixel = ccp->black_pixel;
+ defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef DEBUG
+ black_col++;
+#endif
+ } else {
+ defs[i] = defs[close];
+#ifdef DEBUG
+ subst_col++;
+#endif
+ }
+
+ colors[i] = defs[i].pixel;
+ } while (++idx < nopen);
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "got %i colors, %i exact, %i close, %i substituted, %i to black "
+ "(%i colors allocated so far)",
+ ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
+}
+
+gint
+gdk_color_context_get_num_colors(GdkColorContext *cc)
+{
+ g_assert(cc != NULL);
+
+ return ((GdkColorContextPrivate *) cc)->num_colors;
+}
+
+gint
+gdk_color_context_query_color(GdkColorContext *cc,
+ GdkColor *color)
+{
+ return gdk_color_context_query_colors(cc, color, 1);
+}
+
+gint
+gdk_color_context_query_colors(GdkColorContext *cc,
+ GdkColor *colors,
+ gint num_colors)
+{
+ GdkColorContextPrivate *ccp;
+ gint i;
+ GdkColor *tc;
+
+ g_assert(cc != NULL);
+ g_assert(colors != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ switch (ccp->mode) {
+ case GDK_CC_MODE_BW:
+ for (i = 0, tc = colors; i < num_colors; i++, tc++) {
+ if (tc->pixel == ccp->white_pixel)
+ tc->red = tc->green = tc->blue = 65535;
+ else
+ tc->red = tc->green = tc->blue = 0;
+ }
+ break;
+
+ case GDK_CC_MODE_TRUE:
+ if (ccp->clut == NULL)
+ for (i = 0, tc = colors; i < num_colors; i++, tc++) {
+ tc->red = (tc->pixel & ccp->masks.red) * 65535 / ccp->masks.red;
+ tc->green = (tc->pixel & ccp->masks.green) * 65535 / ccp->masks.green;
+ tc->blue = (tc->pixel & ccp->masks.blue) * 65535 / ccp->masks.blue;
+ }
+ else {
+ my_x_query_colors(ccp->colormap, colors, num_colors);
+ return 1;
+ }
+ break;
+
+ case GDK_CC_MODE_STD_CMAP:
+ default:
+ if (ccp->cmap == NULL) {
+ my_x_query_colors(ccp->colormap, colors, num_colors);
+ return 1;
+ } else {
+ gint first, last, half;
+ gulong half_pixel;
+
+ for (i = 0, tc = colors; i < num_colors; i++) {
+ first = 0;
+ last = ccp->num_colors - 1;
+
+ while (first <= last) {
+ half = (first + last) / 2;
+ half_pixel = ccp->cmap[half].pixel;
+
+ if (tc->pixel == half_pixel) {
+ tc->red = ccp->cmap[half].red;
+ tc->green = ccp->cmap[half].green;
+ tc->blue = ccp->cmap[half].blue;
+ first = last + 1; /* false break */
+ } else {
+ if (tc->pixel > half_pixel)
+ first = half + 1;
+ else
+ last = half - 1;
+ }
+ }
+ }
+ return 1;
+ }
+ break;
+ }
+ return 1;
+}
+
+gint
+gdk_color_context_add_palette(GdkColorContext *cc,
+ GdkColor *palette,
+ gint num_palette)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, j, erg;
+ gushort r, g, b;
+ gulong pixel[1];
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ /* initialize this palette (will also erase previous palette as well) */
+
+ init_palette(ccp);
+
+ /* restore previous mode if we aren't adding a new palette */
+
+ if (num_palette == 0) {
+ /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
+
+ /* XXX: here, the hash table is already initialized */
+
+ return 0;
+ }
+
+ /* Initialize a hash table for this palette (we need one for allocating
+ * the pixels in the palette using the current settings)
+ */
+
+ if (ccp->color_hash == NULL)
+ ccp->color_hash = g_hash_table_new(hash_color, compare_colors);
+
+ /* copy incoming palette */
+
+ ccp->palette = g_new0(GdkColor, num_palette);
+
+ j = 0;
+
+ for (i = 0; i < num_palette; i++) {
+ erg = 0;
+ pixel[0] = 0;
+
+ /* try to allocate this color */
+
+ r = palette[i].red;
+ g = palette[i].green;
+ b = palette[i].blue;
+
+ gdk_color_context_get_pixels(cc, &r, &g, &b, 1, pixel, &erg);
+
+ /* only store if we succeed */
+
+ if (erg) {
+ /* store in palette */
+
+ ccp->palette[j].red = r;
+ ccp->palette[j].green = g;
+ ccp->palette[j].blue = b;
+ ccp->palette[j].pixel = pixel[0];
+
+ /* move to next slot */
+
+ j++;
+ }
+ }
+
+ /* resize to fit */
+
+ if (j != num_palette)
+ ccp->palette = g_realloc(ccp->palette, j * sizeof(GdkColor));
+
+ /* clear the hash table, we don't use it when dithering */
+
+ if (ccp->color_hash) {
+ g_hash_table_destroy(ccp->color_hash);
+ ccp->color_hash = NULL;
+ }
+
+ /* store real palette size */
+
+ ccp->num_palette = j;
+
+ /* switch to palette mode */
+
+ ccp->mode = GDK_CC_MODE_PALETTE;
+
+ /* sort palette */
+
+ qsort(ccp->palette, ccp->num_palette, sizeof(GdkColor), pixel_sort);
+
+ ccp->fast_dither = NULL;
+
+ return j;
+}
+
+void
+gdk_color_context_init_dither(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+ gint rr, gg, bb, err, erg, erb;
+ gint success = FALSE;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ /* now we can initialize the fast dither matrix */
+
+ if(ccp->fast_dither == NULL)
+ ccp->fast_dither = g_new(GdkColorContextDither, 1);
+
+ /* Fill it. We ignore unsuccessful allocations, they are just mapped
+ * to black instead */
+
+ for (rr = 0; rr < 32; rr++)
+ for (gg = 0; gg < 32; gg++)
+ for (bb = 0; bb < 32; bb++) {
+ err = (rr << 3) | (rr >> 2);
+ erg = (gg << 3) | (gg >> 2);
+ erb = (bb << 3) | (bb >> 2);
+
+ ccp->fast_dither->fast_rgb[rr][gg][bb] =
+ gdk_color_context_get_index_from_palette(cc, &err, &erg, &erb, &success);
+ ccp->fast_dither->fast_err[rr][gg][bb] = err;
+ ccp->fast_dither->fast_erg[rr][gg][bb] = erg;
+ ccp->fast_dither->fast_erb[rr][gg][bb] = erb;
+ }
+}
+
+void
+gdk_color_context_free_dither(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ if (ccp->fast_dither)
+ g_free(ccp->fast_dither);
+
+ ccp->fast_dither = NULL;
+}
+
+gulong
+gdk_color_context_get_pixel_from_palette(GdkColorContext *cc,
+ gushort *red,
+ gushort *green,
+ gushort *blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+ gulong pixel = 0;
+ gint dif, dr, dg, db, j = -1;
+ gint mindif = 0x7fffffff;
+ gint err = 0, erg = 0, erb = 0;
+ gint i;
+
+ g_assert(cc != NULL);
+ g_assert(red != NULL);
+ g_assert(green != NULL);
+ g_assert(blue != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ for (i = 0; i < ccp->num_palette; i++) {
+ dr = *red - ccp->palette[i].red;
+ dg = *green - ccp->palette[i].green;
+ db = *blue - ccp->palette[i].blue;
+
+ dif = dr * dr + dg * dg + db * db;
+
+ if (dif < mindif) {
+ mindif = dif;
+ j = i;
+ pixel = ccp->palette[i].pixel;
+ err = dr;
+ erg = dg;
+ erb = db;
+
+ if (mindif == 0)
+ break;
+ }
+ }
+
+ /* we failed to map onto a color */
+
+ if (j == -1)
+ *failed = TRUE;
+ else {
+ *red = ABS(err);
+ *green = ABS(erg);
+ *blue = ABS(erb);
+ }
+
+ return pixel;
+}
+
+guchar
+gdk_color_context_get_index_from_palette(GdkColorContext *cc,
+ gint *red,
+ gint *green,
+ gint *blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+ gint dif, dr, dg, db, j = -1;
+ gint mindif = 0x7fffffff;
+ gint err = 0, erg = 0, erb = 0;
+ gint i;
+
+ g_assert(cc != NULL);
+ g_assert(red != NULL);
+ g_assert(green != NULL);
+ g_assert(blue != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ for (i = 0; i < ccp->num_palette; i++) {
+ dr = *red - ccp->palette[i].red;
+ dg = *green - ccp->palette[i].green;
+ db = *blue - ccp->palette[i].blue;
+
+ dif = dr * dr + dg * dg + db * db;
+
+ if (dif < mindif) {
+ mindif = dif;
+ j = i;
+ err = dr;
+ erg = dg;
+ erb = db;
+
+ if (mindif == 0)
+ break;
+ }
+ }
+
+ /* we failed to map onto a color */
+
+ if (j == -1) {
+ *failed = TRUE;
+ j = 0;
+ } else {
+ /* return error fractions */
+
+ *red = err;
+ *green = erg;
+ *blue = erb;
+ }
+
+ return j;
+}
diff --git a/gdk/gdkprivate.h b/gdk/gdkprivate.h
index 9c0e9918d4..e15ef6a239 100644
--- a/gdk/gdkprivate.h
+++ b/gdk/gdkprivate.h
@@ -35,14 +35,15 @@ extern "C" {
#endif /* __cplusplus */
-typedef struct _GdkWindowPrivate GdkWindowPrivate;
-typedef struct _GdkWindowPrivate GdkPixmapPrivate;
-typedef struct _GdkImagePrivate GdkImagePrivate;
-typedef struct _GdkGCPrivate GdkGCPrivate;
-typedef struct _GdkColormapPrivate GdkColormapPrivate;
-typedef struct _GdkVisualPrivate GdkVisualPrivate;
-typedef struct _GdkFontPrivate GdkFontPrivate;
-typedef struct _GdkCursorPrivate GdkCursorPrivate;
+typedef struct _GdkWindowPrivate GdkWindowPrivate;
+typedef struct _GdkWindowPrivate GdkPixmapPrivate;
+typedef struct _GdkImagePrivate GdkImagePrivate;
+typedef struct _GdkGCPrivate GdkGCPrivate;
+typedef struct _GdkColormapPrivate GdkColormapPrivate;
+typedef struct _GdkVisualPrivate GdkVisualPrivate;
+typedef struct _GdkFontPrivate GdkFontPrivate;
+typedef struct _GdkCursorPrivate GdkCursorPrivate;
+typedef struct _GdkColorContextPrivate GdkColorContextPrivate;
struct _GdkWindowPrivate
@@ -151,7 +152,7 @@ typedef struct _GdkDndGlobals GdkDndGlobals;
#ifdef USE_XIM
-struct _GdkICPrivate
+struct _GdkICPrivate
{
XIC xic;
GdkIMStyle style;
@@ -161,6 +162,59 @@ typedef struct _GdkICPrivate GdkICPrivate;
#endif /* USE_XIM */
+struct _GdkColorContextPrivate
+{
+ GdkColorContext color_context;
+ Display *xdisplay;
+ GdkVisual *visual;
+ GdkColormap *colormap;
+
+ gint num_colors; /* available no. of colors in colormap */
+ gint max_colors; /* maximum no. of colors */
+ gint num_allocated; /* no. of allocated colors */
+
+ GdkColorContextMode mode;
+ gint need_to_free_colormap;
+ GdkAtom std_cmap_atom;
+
+ XStandardColormap std_cmap;
+ gulong *clut; /* color look-up table */
+ GdkColor *cmap; /* colormap */
+
+ GHashTable *color_hash; /* hash table of allocated colors */
+ GdkColor *palette; /* preallocated palette */
+ gint num_palette; /* size of palette */
+
+ GdkColorContextDither *fast_dither; /* fast dither matrix */
+
+ struct
+ {
+ gint red;
+ gint green;
+ gint blue;
+ } shifts;
+
+ struct
+ {
+ gulong red;
+ gulong green;
+ gulong blue;
+ } masks;
+
+
+ struct {
+ gint red;
+ gint green;
+ gint blue;
+ } bits;
+
+ gulong max_entry;
+
+ gulong black_pixel;
+ gulong white_pixel;
+};
+
+
void gdk_window_init (void);
void gdk_visual_init (void);
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index 8f8022f773..be2a60dedd 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -40,23 +40,25 @@ extern "C" {
/* Type definitions for the basic structures.
*/
-typedef gulong GdkAtom;
-typedef struct _GdkColor GdkColor;
-typedef struct _GdkColormap GdkColormap;
-typedef struct _GdkVisual GdkVisual;
-typedef struct _GdkWindowAttr GdkWindowAttr;
-typedef struct _GdkWindow GdkWindow;
-typedef struct _GdkWindow GdkPixmap;
-typedef struct _GdkWindow GdkBitmap;
-typedef struct _GdkWindow GdkDrawable;
-typedef struct _GdkImage GdkImage;
-typedef struct _GdkGCValues GdkGCValues;
-typedef struct _GdkGC GdkGC;
-typedef struct _GdkPoint GdkPoint;
-typedef struct _GdkRectangle GdkRectangle;
-typedef struct _GdkSegment GdkSegment;
-typedef struct _GdkFont GdkFont;
-typedef struct _GdkCursor GdkCursor;
+typedef gulong GdkAtom;
+typedef struct _GdkColor GdkColor;
+typedef struct _GdkColormap GdkColormap;
+typedef struct _GdkVisual GdkVisual;
+typedef struct _GdkWindowAttr GdkWindowAttr;
+typedef struct _GdkWindow GdkWindow;
+typedef struct _GdkWindow GdkPixmap;
+typedef struct _GdkWindow GdkBitmap;
+typedef struct _GdkWindow GdkDrawable;
+typedef struct _GdkImage GdkImage;
+typedef struct _GdkGCValues GdkGCValues;
+typedef struct _GdkGC GdkGC;
+typedef struct _GdkPoint GdkPoint;
+typedef struct _GdkRectangle GdkRectangle;
+typedef struct _GdkSegment GdkSegment;
+typedef struct _GdkFont GdkFont;
+typedef struct _GdkCursor GdkCursor;
+typedef struct _GdkColorContextDither GdkColorContextDither;
+typedef struct _GdkColorContext GdkColorContext;
typedef struct _GdkEventAny GdkEventAny;
typedef struct _GdkEventExpose GdkEventExpose;
@@ -566,6 +568,28 @@ typedef void (*GdkInputFunction) (gpointer data,
gint source,
GdkInputCondition condition);
+
+/* Color Context modes.
+ *
+ * GDK_CC_MODE_UNDEFINED - unknown
+ * GDK_CC_MODE_BW - default B/W
+ * GDK_CC_MODE_STD_CMAP - has a standard colormap
+ * GDK_CC_MODE_TRUE - is a TrueColor/DirectColor visual
+ * GDK_CC_MODE_MY_GRAY - my grayramp
+ * GDK_CC_MODE_PALETTE - has a pre-allocated palette
+ */
+
+typedef enum
+{
+ GDK_CC_MODE_UNDEFINED,
+ GDK_CC_MODE_BW,
+ GDK_CC_MODE_STD_CMAP,
+ GDK_CC_MODE_TRUE,
+ GDK_CC_MODE_MY_GRAY,
+ GDK_CC_MODE_PALETTE
+} GdkColorContextMode;
+
+
/* The color type.
* A color consists of red, green and blue values in the
* range 0-65535 and a pixel value. The pixel value is highly
@@ -718,6 +742,19 @@ struct _GdkCursor
GdkCursorType type;
};
+struct _GdkColorContextDither
+{
+ gint fast_rgb[32][32][32]; /* quick look-up table for faster rendering */
+ gint fast_err[32][32][32]; /* internal RGB error information */
+ gint fast_erg[32][32][32];
+ gint fast_erb[32][32][32];
+};
+
+struct _GdkColorContext
+{
+ gint dummy;
+};
+
/* Types for XInput support */
struct _GdkDeviceInfo
diff --git a/gdk/x11/gdkcc-x11.c b/gdk/x11/gdkcc-x11.c
new file mode 100644
index 0000000000..0b089208d2
--- /dev/null
+++ b/gdk/x11/gdkcc-x11.c
@@ -0,0 +1,1679 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Color Context module
+ * Copyright 1994,1995 John L. Cwikla
+ * Copyright (C) 1997 by Ripley Software Development
+ * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
+ */
+
+/* Copyright 1994,1995 John L. Cwikla
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of John L. Cwikla or
+ * Wolfram Research, Inc not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission. John L. Cwikla and Wolfram Research, Inc make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
+ * regard to this software, including all implied warranties of
+ * merchantability and fitness, in no event shall John L. Cwikla or
+ * Wolfram Research, Inc be liable for any special, indirect or
+ * consequential damages or any damages whatsoever resulting from loss of
+ * use, data or profits, whether in an action of contract, negligence or
+ * other tortious action, arising out of or in connection with the use or
+ * performance of this software.
+ *
+ * Author:
+ * John L. Cwikla
+ * X Programmer
+ * Wolfram Research Inc.
+ *
+ * cwikla@wri.com
+ */
+
+/* NOTES:
+ *
+ * - When a CC is destroyed, remember to destroy the hash table properly.
+ */
+
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+
+#define MAX_IMAGE_COLORS 256
+
+
+static guint
+hash_color(gpointer key)
+{
+ GdkColor *color = key;
+
+ return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
+}
+
+static gint
+compare_colors(gpointer a, gpointer b)
+{
+ GdkColor *aa = a;
+ GdkColor *bb = b;
+
+ return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
+}
+
+static void
+free_hash_entry(gpointer key, gpointer value, gpointer user_data)
+{
+ g_free(key); /* key and value are the same GdkColor */
+}
+
+static int
+pixel_sort(const void *a, const void *b)
+{
+ return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
+}
+
+/* XXX: This function does an XQueryColors() the hard way, because there is
+ * no corresponding function in Gdk.
+ */
+
+static void
+my_x_query_colors(GdkColormap *colormap,
+ GdkColor *colors,
+ gint ncolors)
+{
+ XColor *xcolors;
+ gint i;
+
+ xcolors = g_new(XColor, ncolors);
+ for (i = 0; i < ncolors; i++)
+ xcolors[i].pixel = colors[i].pixel;
+
+ XQueryColors(gdk_display, GDK_COLORMAP_XCOLORMAP(colormap), xcolors, ncolors);
+
+ for (i = 0; i < ncolors; i++) {
+ colors[i].red = xcolors[i].red;
+ colors[i].green = xcolors[i].green;
+ colors[i].blue = xcolors[i].blue;
+ }
+
+ g_free(xcolors);
+}
+
+static void
+query_colors(GdkColorContextPrivate *cc)
+{
+ gint i;
+
+ cc->cmap = g_new(GdkColor, cc->num_colors);
+
+ for (i = 0; i < cc->num_colors; i++)
+ cc->cmap[i].pixel = cc->clut ? cc->clut[i] : cc->std_cmap.base_pixel + i;
+
+ my_x_query_colors(cc->colormap, cc->cmap, cc->num_colors);
+
+ qsort(cc->cmap, cc->num_colors, sizeof(GdkColor), pixel_sort);
+}
+
+static void
+init_bw(GdkColorContextPrivate *cc)
+{
+ GdkColor color;
+
+ g_warning("init_bw: failed to allocate colors, falling back to black and white");
+
+ cc->mode = GDK_CC_MODE_BW;
+
+ color.red = color.green = color.blue = 0;
+ if (!gdk_color_alloc(cc->colormap, &color))
+ cc->black_pixel = 0;
+ else
+ cc->black_pixel = color.pixel;
+
+ color.red = color.green = color.blue = 0xffff;
+ if (!gdk_color_alloc(cc->colormap, &color))
+ cc->white_pixel = cc->black_pixel ? 0 : 1;
+ else
+ cc->white_pixel = color.pixel;
+
+ cc->num_colors = 2;
+}
+
+static void
+init_gray(GdkColorContextPrivate *cc)
+{
+ GdkColor *clrs, *cstart;
+ gint i;
+ gdouble dinc;
+
+ cc->num_colors = GDK_VISUAL_XVISUAL(cc->visual)->map_entries;
+
+ cc->clut = g_new(gulong, cc->num_colors);
+ cstart = g_new(GdkColor, cc->num_colors);
+
+retrygray:
+
+ dinc = 65535.0 / (cc->num_colors - 1);
+
+ clrs = cstart;
+
+ for (i = 0; i < cc->num_colors; i++) {
+ clrs->red = clrs->green = clrs->blue = dinc * i;
+
+ if (!gdk_color_alloc(cc->colormap, clrs)) {
+ gdk_colors_free(cc->colormap, cc->clut, i, 0);
+
+ cc->num_colors /= 2;
+
+ if (cc->num_colors > 1)
+ goto retrygray;
+ else {
+ g_free(cc->clut);
+ cc->clut = NULL;
+ init_bw(cc);
+ g_free(cstart);
+ return;
+ }
+ }
+
+ cc->clut[i] = clrs++->pixel;
+ }
+
+ g_free(cstart);
+
+ /* XXX: is this the right thing to do? */
+ cc->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP(cc->colormap);
+ cc->std_cmap.base_pixel = 0;
+ cc->std_cmap.red_max = cc->num_colors - 1;
+ cc->std_cmap.green_max = 0;
+ cc->std_cmap.blue_max = 0;
+ cc->std_cmap.red_mult = 1;
+ cc->std_cmap.green_mult = 0;
+ cc->std_cmap.blue_mult = 0;
+
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+
+ query_colors(cc);
+
+ cc->mode = GDK_CC_MODE_MY_GRAY;
+}
+
+static void
+init_color(GdkColorContextPrivate *cc)
+{
+ gint cubeval;
+
+ cubeval = 1;
+ while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL(cc->visual)->map_entries)
+ cubeval++;
+ cubeval--;
+
+ cc->num_colors = cubeval * cubeval * cubeval;
+
+ cc->std_cmap.red_max = cubeval - 1;
+ cc->std_cmap.green_max = cubeval - 1;
+ cc->std_cmap.blue_max = cubeval - 1;
+ cc->std_cmap.red_mult = cubeval * cubeval;
+ cc->std_cmap.green_mult = cubeval;
+ cc->std_cmap.blue_mult = 1;
+ cc->std_cmap.base_pixel = 0;
+
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+ cc->num_colors = DisplayCells(cc->xdisplay, gdk_screen);
+
+ /* a CLUT for storing allocated pixel indices */
+
+ cc->max_colors = cc->num_colors;
+ cc->clut = g_new(gulong, cc->max_colors);
+
+ for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
+ cc->clut[cubeval] = cubeval;
+
+ query_colors(cc);
+
+ cc->mode = GDK_CC_MODE_STD_CMAP;
+}
+
+
+static void
+init_true_color(GdkColorContextPrivate *cc)
+{
+ gulong rmask, gmask, bmask;
+
+ cc->mode = GDK_CC_MODE_TRUE;
+
+ /* Red */
+
+ rmask = cc->masks.red = cc->visual->red_mask;
+
+ cc->shifts.red = 0;
+ cc->bits.red = 0;
+
+ while (!(rmask & 1)) {
+ rmask >>= 1;
+ cc->shifts.red++;
+ }
+
+ while (rmask & 1) {
+ rmask >>= 1;
+ cc->bits.red++;
+ }
+
+ /* Green */
+
+ gmask = cc->masks.green = cc->visual->green_mask;
+
+ cc->shifts.green = 0;
+ cc->bits.green = 0;
+
+ while (!(gmask & 1)) {
+ gmask >>= 1;
+ cc->shifts.green++;
+ }
+
+ while (gmask & 1) {
+ gmask >>= 1;
+ cc->bits.green++;
+ }
+
+ /* Blue */
+
+ bmask = cc->masks.blue = cc->visual->blue_mask;
+
+ cc->shifts.blue = 0;
+ cc->bits.blue = 0;
+
+ while (!(bmask & 1)) {
+ bmask >>= 1;
+ cc->shifts.blue++;
+ }
+
+ while (bmask & 1) {
+ bmask >>= 1;
+ cc->bits.blue++;
+ }
+
+ cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
+ cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
+ cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
+}
+
+static void
+init_direct_color(GdkColorContextPrivate *cc)
+{
+ gint n, count;
+ GdkColor *clrs, *cstart;
+ gulong rval, gval, bval;
+ gulong *rtable;
+ gulong *gtable;
+ gulong *btable;
+ gdouble dinc;
+
+ init_true_color(cc); /* for shift stuff */
+
+ rval = cc->visual->red_mask >> cc->shifts.red;
+ gval = cc->visual->green_mask >> cc->shifts.green;
+ bval = cc->visual->blue_mask >> cc->shifts.blue;
+
+ rtable = g_new(gulong, rval + 1);
+ gtable = g_new(gulong, gval + 1);
+ btable = g_new(gulong, bval + 1);
+
+ cc->max_entry = MAX(rval, gval);
+ cc->max_entry = MAX(cc->max_entry, bval);
+
+ cstart = g_new(GdkColor, cc->max_entry + 1);
+ cc->clut = g_new(gulong, cc->max_entry + 1);
+
+retrydirect:
+
+ for (n = 0; n < rval; n++)
+ rtable[n] = rval ? (65535.0 / rval * n) : 0;
+
+ for (n = 0; n < gval; n++)
+ gtable[n] = gval ? (65535.0 / gval * n) : 0;
+
+ for (n = 0; n < bval; n++)
+ btable[n] = bval ? (65535.0 / bval * n) : 0;
+
+ cc->max_entry = MAX(rval, gval);
+ cc->max_entry = MAX(cc->max_entry, bval);
+
+ count = 0;
+ clrs = cstart;
+ cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
+
+ for (n = 0; n < cc->max_entry; n++) {
+ dinc = (double) n / cc->max_entry;
+
+ clrs->red = rtable[(int) (dinc * rval)];
+ clrs->green = gtable[(int) (dinc * gval)];
+ clrs->blue = btable[(int) (dinc * bval)];
+
+ if (gdk_color_alloc(cc->colormap, clrs)) {
+ cc->clut[count++] = clrs->pixel;
+ clrs++;
+ } else {
+ gdk_colors_free(cc->colormap, cc->clut, count, 0);
+
+ rval >>= 1;
+ gval >>= 1;
+ bval >>= 1;
+
+ cc->masks.red = (cc->masks.red >> 1) & cc->visual->red_mask;
+ cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
+ cc->masks.blue = (cc->masks.blue >> 1) & cc->visual->blue_mask;
+
+ cc->shifts.red++;
+ cc->shifts.green++;
+ cc->shifts.blue++;
+
+ cc->bits.red--;
+ cc->bits.green--;
+ cc->bits.blue--;
+
+ cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
+
+ if (cc->num_colors >1)
+ goto retrydirect;
+ else {
+ g_free(cc->clut);
+ cc->clut = NULL;
+ init_bw(cc);
+ break;
+ }
+ }
+ }
+
+ /* Update allocated color count; original num_colors is max_entry, which
+ * is not necessarily the same as the really allocated number of colors.
+ */
+
+ cc->num_colors = count;
+
+ g_free(rtable);
+ g_free(gtable);
+ g_free(btable);
+ g_free(cstart);
+}
+
+static void
+init_palette(GdkColorContextPrivate *cc)
+{
+ /* restore correct mode for this cc */
+
+ switch (cc->visual->type) {
+ case GDK_VISUAL_STATIC_GRAY:
+ case GDK_VISUAL_GRAYSCALE:
+ if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
+ cc->mode = GDK_CC_MODE_BW;
+ else
+ cc->mode = GDK_CC_MODE_MY_GRAY;
+ break;
+
+ case GDK_VISUAL_TRUE_COLOR:
+ case GDK_VISUAL_DIRECT_COLOR:
+ cc->mode = GDK_CC_MODE_TRUE;
+ break;
+
+ case GDK_VISUAL_STATIC_COLOR:
+ case GDK_VISUAL_PSEUDO_COLOR:
+ cc->mode = GDK_CC_MODE_STD_CMAP;
+ break;
+
+ default:
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ break;
+ }
+
+ /* previous palette */
+
+ if (cc->num_palette)
+ g_free(cc->palette);
+
+ if (cc->fast_dither)
+ g_free(cc->fast_dither);
+
+ /* clear hash table if present */
+
+ if (cc->color_hash) {
+ /* XXX: quick-and-dirty way to remove everything */
+
+ g_hash_table_destroy(cc->color_hash);
+ cc->color_hash = g_hash_table_new(hash_color, compare_colors);
+ }
+
+ cc->palette = NULL;
+ cc->num_palette = 0;
+ cc->fast_dither = NULL;
+}
+
+GdkColorContext *
+gdk_color_context_new(GdkVisual *visual,
+ GdkColormap *colormap)
+{
+ gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
+ GdkColorContextPrivate *cc;
+ gint retry_count;
+ GdkColormap *default_colormap;
+
+ g_assert(visual != NULL);
+ g_assert(colormap != NULL);
+
+ cc = g_new(GdkColorContextPrivate, 1);
+
+ cc->xdisplay = gdk_display;
+ cc->visual = visual;
+ cc->colormap = colormap;
+ cc->clut = NULL;
+ cc->cmap = NULL;
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ cc->need_to_free_colormap = FALSE;
+
+ cc->color_hash = NULL;
+ cc->palette = NULL;
+ cc->num_palette = 0;
+ cc->fast_dither = NULL;
+
+ default_colormap = gdk_colormap_get_system();
+
+ retry_count = 0;
+
+ while (retry_count < 2) {
+ /* Only create a private colormap if the visual found isn't equal
+ * to the default visual and we don't have a private colormap,
+ * -or- if we are instructed to create a private colormap (which
+ * never is the case for XmHTML).
+ */
+
+ if (use_private_colormap
+ || ((cc->visual != gdk_visual_get_system()) /* default visual? */
+ && (GDK_COLORMAP_XCOLORMAP(colormap) == GDK_COLORMAP_XCOLORMAP(default_colormap)))) {
+ g_warning("gdk_color_context_new: non-default visual detected, "
+ "using private colormap");
+
+ cc->colormap = gdk_colormap_new(cc->visual, FALSE);
+
+ cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP(colormap)
+ != GDK_COLORMAP_XCOLORMAP(default_colormap));
+ }
+
+ switch (visual->type) {
+ case GDK_VISUAL_STATIC_GRAY:
+ case GDK_VISUAL_GRAYSCALE:
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is %s",
+ (visual->type == GDK_VISUAL_STATIC_GRAY) ?
+ "GDK_VISUAL_STATIC_GRAY" :
+ "GDK_VISUAL_GRAYSCALE");
+
+ if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
+ init_bw(cc);
+ else
+ init_gray(cc);
+
+ break;
+
+ case GDK_VISUAL_TRUE_COLOR: /* shifts */
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is "
+ "GDK_VISUAL_TRUE_COLOR");
+
+ init_true_color(cc);
+ break;
+
+ case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is "
+ "GDK_VISUAL_DIRECT_COLOR");
+
+ init_direct_color(cc);
+ break;
+
+ case GDK_VISUAL_STATIC_COLOR:
+ case GDK_VISUAL_PSEUDO_COLOR:
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: visual class is %s",
+ (visual->type == GDK_VISUAL_STATIC_COLOR) ?
+ "GDK_VISUAL_STATIC_COLOR" :
+ "GDK_VISUAL_PSEUDO_COLOR");
+
+ init_color(cc);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1)) {
+ use_private_colormap = TRUE;
+ retry_count++;
+ } else
+ break;
+ }
+
+ /* no. of colors allocated yet */
+
+ cc->num_allocated = 0;
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_new: screen depth is %i, no. of colors is %i",
+ cc->visual->depth, cc->num_colors);
+
+ /* check if we need to initialize a hash table */
+
+ if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
+ cc->color_hash = g_hash_table_new(hash_color, compare_colors);
+
+ return (GdkColorContext *) cc;
+}
+
+GdkColorContext *
+gdk_color_context_new_mono(GdkVisual *visual,
+ GdkColormap *colormap)
+{
+ GdkColorContextPrivate *cc;
+
+ g_assert(visual != NULL);
+ g_assert(colormap != NULL);
+
+ cc = g_new(GdkColorContextPrivate, 1);
+
+ cc->xdisplay = gdk_display;
+ cc->visual = visual;
+ cc->colormap = colormap;
+ cc->clut = NULL;
+ cc->cmap = NULL;
+ cc->mode = GDK_CC_MODE_UNDEFINED;
+ cc->need_to_free_colormap = FALSE;
+
+ init_bw(cc);
+
+ return (GdkColorContext *) cc;
+}
+
+/* This doesn't currently free black/white, hmm... */
+
+void
+gdk_color_context_free(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ if ((ccp->visual->type == GDK_VISUAL_STATIC_COLOR)
+ || (ccp->visual->type == GDK_VISUAL_PSEUDO_COLOR)) {
+ gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_allocated, 0);
+ g_free(ccp->clut);
+ } else if (ccp->clut != NULL) {
+ gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_colors, 0);
+ g_free(ccp->clut);
+ }
+
+ if (ccp->cmap != NULL)
+ g_free(ccp->cmap);
+
+ if (ccp->need_to_free_colormap)
+ gdk_colormap_destroy(ccp->colormap);
+
+ /* free any palette that has been associated with this GdkColorContext */
+
+ init_palette(ccp);
+
+ if (ccp->color_hash) {
+ g_hash_table_foreach(ccp->color_hash,
+ free_hash_entry,
+ NULL);
+ g_hash_table_destroy(ccp->color_hash);
+ }
+
+ g_free(cc);
+}
+
+gulong
+gdk_color_context_get_pixel(GdkColorContext *cc,
+ gushort red,
+ gushort green,
+ gushort blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ switch (ccp->mode) {
+ case GDK_CC_MODE_BW: {
+ gdouble value;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ value = red / 65535.0 * 0.30
+ + green / 65535.0 * 0.59
+ + blue / 65535.0 * 0.11;
+
+ if (value > 0.5)
+ return ccp->white_pixel;
+
+ return ccp->black_pixel;
+ }
+
+ case GDK_CC_MODE_MY_GRAY: {
+ gulong ired, igreen, iblue;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ red = red * 0.30 + green * 0.59 + blue * 0.11;
+ green = 0;
+ blue = 0;
+
+ if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff)
+ > ccp->std_cmap.red_max)
+ ired = ccp->std_cmap.red_max;
+
+ ired *= ccp->std_cmap.red_mult;
+
+ if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff)
+ > ccp->std_cmap.green_max)
+ igreen = ccp->std_cmap.green_max;
+
+ igreen *= ccp->std_cmap.green_mult;
+
+ if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff)
+ > ccp->std_cmap.blue_max)
+ iblue = ccp->std_cmap.blue_max;
+
+ iblue *= ccp->std_cmap.blue_mult;
+
+ if (ccp->clut != NULL)
+ return ccp->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
+
+ return ccp->std_cmap.base_pixel + ired + igreen + iblue;
+ }
+
+ case GDK_CC_MODE_TRUE: {
+ gulong ired, igreen, iblue;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ if (ccp->clut == NULL) {
+ red >>= 16 - ccp->bits.red;
+ green >>= 16 - ccp->bits.green;
+ blue >>= 16 - ccp->bits.blue;
+
+ ired = (red << ccp->shifts.red) & ccp->masks.red;
+ igreen = (green << ccp->shifts.green) & ccp->masks.green;
+ iblue = (blue << ccp->shifts.blue) & ccp->masks.blue;
+
+ return ired | igreen | iblue;
+ }
+
+ ired = ccp->clut[red * ccp->max_entry / 65535] & ccp->masks.red;
+ igreen = ccp->clut[green * ccp->max_entry / 65535] & ccp->masks.green;
+ iblue = ccp->clut[blue * ccp->max_entry / 65535] & ccp->masks.blue;
+
+ return ired | igreen | iblue;
+ }
+
+ case GDK_CC_MODE_PALETTE:
+ return gdk_color_context_get_pixel_from_palette(cc, &red, &green, &blue, failed);
+
+ case GDK_CC_MODE_STD_CMAP:
+ default: {
+ GdkColor color;
+ GdkColor *result;
+
+ red <<= 8;
+ green <<= 8;
+ blue <<= 8;
+
+ color.red = red;
+ color.green = green;
+ color.blue = blue;
+
+ result = g_hash_table_lookup(ccp->color_hash, &color);
+
+ if (!result) {
+ color.red = red;
+ color.green = green;
+ color.blue = blue;
+ color.pixel = 0;
+
+ if (!gdk_color_alloc(ccp->colormap, &color))
+ *failed = TRUE;
+ else {
+ GdkColor *cnew;
+
+ /* XXX: the following comment comes directly from
+ * XCC.c. I don't know if it is relevant for
+ * gdk_color_alloc() as it is for XAllocColor()
+ * - Federico
+ */
+ /*
+ * I can't figure this out entirely, but it *is* possible
+ * that XAllocColor succeeds, even if the number of
+ * allocations we've made exceeds the number of available
+ * colors in the current colormap. And therefore it
+ * might be necessary for us to resize the CLUT.
+ */
+
+ if (ccp->num_allocated == ccp->max_colors) {
+ ccp->max_colors *= 2;
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixel: "
+ "resizing CLUT to %i entries",
+ ccp->max_colors);
+
+ ccp->clut = g_realloc(ccp->clut,
+ ccp->max_colors * sizeof(gulong));
+ }
+
+ /* Key and value are the same color structure */
+
+ cnew = g_new(GdkColor, 1);
+ *cnew = color;
+ g_hash_table_insert(ccp->color_hash, cnew, cnew);
+
+ ccp->clut[ccp->num_allocated] = color.pixel;
+ ccp->num_allocated++;
+ return color.pixel;
+ }
+ }
+
+ return result->pixel;
+ }
+ }
+}
+
+void
+gdk_color_context_get_pixels(GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gulong *colors,
+ gint *nallocated)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, k, idx;
+ gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+ gint bad_alloc = FALSE;
+ gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+ GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+ gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+
+ g_assert(cc != NULL);
+ g_assert(reds != NULL);
+ g_assert(greens != NULL);
+ g_assert(blues != NULL);
+ g_assert(colors != NULL);
+ g_assert(nallocated != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
+ memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
+ memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
+
+ /* Will only have a value if used by the progressive image loader */
+
+ ncols = *nallocated;
+
+ *nallocated = 0;
+
+ /* First allocate all pixels */
+
+ for (i = 0; i < ncolors; i++) {
+ /* colors[i] is only zero if the pixel at that location hasn't
+ * been allocated yet. This is a sanity check required for proper
+ * color allocation by the progressive image loader
+ */
+
+ if (colors[i] == 0) {
+ defs[i].red = reds[i];
+ defs[i].green = greens[i];
+ defs[i].blue = blues[i];
+
+ colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i],
+ &bad_alloc);
+
+ /* successfully allocated, store it */
+
+ if (!bad_alloc) {
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+ } else
+ failed[nopen++] = i;
+ }
+ }
+
+ *nallocated = ncols;
+
+ /* all colors available, all done */
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got all %i colors; "
+ "(%i colors allocated so far", ncolors, ccp->num_allocated);
+
+ return;
+ }
+
+ /* The fun part. We now try to allocate the colors we couldn't allocate
+ * directly. The first step will map a color onto its nearest color
+ * that has been allocated (either by us or someone else). If any colors
+ * remain unallocated, we map these onto the colors that we have allocated
+ * ourselves.
+ */
+
+ /* read up to MAX_IMAGE_COLORS colors of the current colormap */
+
+ cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
+
+ /* see if the colormap has any colors to read */
+
+ if (cmapsize < 0) {
+ g_warning("gdk_color_context_get_pixels: oops! no colors available, "
+ "your images will look *really* ugly.");
+
+ return;
+ }
+
+#ifdef DEBUG
+ exact_col = ncols;
+#endif
+
+ /* initialize pixels */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].pixel = i;
+ cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+ }
+
+ /* read the colormap */
+
+ my_x_query_colors(ccp->colormap, cmap, cmapsize);
+
+ /* speedup: downscale here instead of in the matching code */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].red >>= 8;
+ cmap[i].green >>= 8;
+ cmap[i].blue >>= 8;
+ }
+
+ /* get a close match for any unallocated colors */
+
+ counter = nopen;
+ nopen = 0;
+ idx = 0;
+
+ do {
+ gint d, j, mdist, close, ri, gi, bi;
+ gint rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* Store these vals. Small performance increase as this skips three
+ * indexing operations in the loop code.
+ */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* Walk all colors in the colormap and see which one is the
+ * closest. Uses plain least squares.
+ */
+
+ for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
+ rd = ri - cmap[j].red;
+ gd = gi - cmap[j].green;
+ bd = bi - cmap[j].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = j;
+ mdist = d;
+ }
+ }
+
+ if (close != -1) {
+ rd = cmap[close].red;
+ gd = cmap[close].green;
+ bd = cmap[close].blue;
+
+ /* allocate */
+
+ colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
+
+ /* store */
+
+ if (!bad_alloc) {
+ defs[i] = cmap[close];
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+#ifdef DEBUG
+ close_col++;
+#endif
+ } else
+ failed[nopen++] = i;
+ } else
+ failed[nopen++] = i;
+ /* deal with in next stage if allocation failed */
+ } while (++idx < counter);
+
+ *nallocated = ncols;
+
+ /* This is the maximum no. of allocated colors. See also the nopen == 0
+ * note above.
+ */
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got %i colors, %i exact and "
+ "%i close (%i colors allocated so far)",
+ ncolors, exact_col, close_col, ccp->num_allocated);
+
+ return;
+ }
+
+ /* Now map any remaining unallocated pixels into the colors we did get */
+
+ idx = 0;
+
+ do {
+ gint d, mdist, close, ri, gi, bi;
+ gint j, rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* store */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* search allocated colors */
+
+ for (j = 0; (j < ncols) && (mdist != 0); j++) {
+ k = allocated[j];
+
+ rd = ri - defs[k].red;
+ gd = gi - defs[k].green;
+ bd = bi - defs[k].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = k;
+ mdist = d;
+ }
+ }
+
+ if (close < 0) {
+ /* too bad, map to black */
+
+ defs[i].pixel = ccp->black_pixel;
+ defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef DEBUG
+ black_col++;
+#endif
+ } else {
+ defs[i] = defs[close];
+#ifdef DEBUG
+ subst_col++;
+#endif
+ }
+
+ colors[i] = defs[i].pixel;
+ } while (++idx < nopen);
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
+ "%i substituted, %i to black (%i colors allocated so far)",
+ ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
+}
+
+void
+gdk_color_context_get_pixels_incremental(GdkColorContext *cc,
+ gushort *reds,
+ gushort *greens,
+ gushort *blues,
+ gint ncolors,
+ gint *used,
+ gulong *colors,
+ gint *nallocated)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, k, idx;
+ gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+ gint bad_alloc = FALSE;
+ gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+ GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+ gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+
+ g_assert(cc != NULL);
+ g_assert(reds != NULL);
+ g_assert(greens != NULL);
+ g_assert(blues != NULL);
+ g_assert(used != NULL);
+ g_assert(colors != NULL);
+ g_assert(nallocated != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
+ memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
+ memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
+
+ /* Will only have a value if used by the progressive image loader */
+
+ ncols = *nallocated;
+
+ *nallocated = 0;
+
+ /* First allocate all pixels */
+
+ for (i = 0; i < ncolors; i++) {
+ /* used[i] is only -1 if the pixel at that location hasn't
+ * been allocated yet. This is a sanity check required for proper
+ * color allocation by the progressive image loader.
+ * When colors[i] == 0 it indicates the slot is available for
+ * allocation.
+ */
+
+ if (used[i] != FALSE) {
+ if (colors[i] == 0) {
+ defs[i].red = reds[i];
+ defs[i].green = greens[i];
+ defs[i].blue = blues[i];
+
+ colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i], &bad_alloc);
+
+ /* successfully allocated, store it */
+
+ if (!bad_alloc) {
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+ } else
+ failed[nopen++] = i;
+ }
+#ifdef DEBUG
+ else
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "pixel at slot %i already allocated, skipping", i);
+#endif
+ }
+ }
+
+ *nallocated = ncols;
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: got all %i colors "
+ "(%i colors allocated so far)",
+ ncolors, ccp->num_allocated);
+
+ return;
+ }
+
+ cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
+
+ if (cmapsize < 0) {
+ g_warning("gdk_color_context_get_pixels_incremental: oops! "
+ "No colors available images will look *really* ugly.");
+ return;
+ }
+
+#ifdef DEBUG
+ exact_col = ncols;
+#endif
+
+ /* initialize pixels */
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].pixel = i;
+ cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+ }
+
+ /* read and downscale */
+
+ my_x_query_colors(ccp->colormap, cmap, cmapsize);
+
+ for (i = 0; i < cmapsize; i++) {
+ cmap[i].red >>= 8;
+ cmap[i].green >>= 8;
+ cmap[i].blue >>= 8;
+ }
+
+ /* now match any unallocated colors */
+
+ counter = nopen;
+ nopen = 0;
+ idx = 0;
+
+ do {
+ gint d, j, mdist, close, ri, gi, bi;
+ gint rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ /* store */
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
+ rd = ri - cmap[j].red;
+ gd = gi - cmap[j].green;
+ bd = bi - cmap[j].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = j;
+ mdist = d;
+ }
+ }
+
+ if (close != -1) {
+ rd = cmap[close].red;
+ gd = cmap[close].green;
+ bd = cmap[close].blue;
+
+ /* allocate */
+
+ colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
+
+ /* store */
+
+ if (!bad_alloc) {
+ defs[i] = cmap[close];
+ defs[i].pixel = colors[i];
+ allocated[ncols++] = colors[i];
+#ifdef DEBUG
+ close_col++;
+#endif
+ } else
+ failed[nopen++] = i;
+ } else
+ failed[nopen++] = i;
+ /* deal with in next stage if allocation failed */
+ } while (++idx < counter);
+
+ *nallocated = ncols;
+
+ if ((ncols == ncolors) || (nopen == 0)) {
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "got %i colors, %i exact and %i close "
+ "(%i colors allocated so far)",
+ ncolors, exact_col, close_col, ccp->num_allocated);
+
+ return;
+ }
+
+ /* map remaining unallocated pixels into colors we did get */
+
+ idx = 0;
+
+ do {
+ gint d, mdist, close, ri, gi, bi;
+ gint j, rd, gd, bd;
+
+ i = failed[idx];
+
+ mdist = 1000000;
+ close = -1;
+
+ ri = reds[i];
+ gi = greens[i];
+ bi = blues[i];
+
+ /* search allocated colors */
+
+ for (j = 0; (j < ncols) && (mdist != 0); j++) {
+ k = allocated[j];
+
+ /* downscale */
+
+ rd = ri - defs[k].red;
+ gd = gi - defs[k].green;
+ bd = bi - defs[k].blue;
+
+ d = rd * rd + gd * gd + bd * bd;
+
+ if (d < mdist) {
+ close = k;
+ mdist = d;
+ }
+ }
+
+ if (close < 0) {
+ /* too bad, map to black */
+
+ defs[i].pixel = ccp->black_pixel;
+ defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef DEBUG
+ black_col++;
+#endif
+ } else {
+ defs[i] = defs[close];
+#ifdef DEBUG
+ subst_col++;
+#endif
+ }
+
+ colors[i] = defs[i].pixel;
+ } while (++idx < nopen);
+
+ if (gdk_debug_level >= 1)
+ g_print("gdk_color_context_get_pixels_incremental: "
+ "got %i colors, %i exact, %i close, %i substituted, %i to black "
+ "(%i colors allocated so far)",
+ ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
+}
+
+gint
+gdk_color_context_get_num_colors(GdkColorContext *cc)
+{
+ g_assert(cc != NULL);
+
+ return ((GdkColorContextPrivate *) cc)->num_colors;
+}
+
+gint
+gdk_color_context_query_color(GdkColorContext *cc,
+ GdkColor *color)
+{
+ return gdk_color_context_query_colors(cc, color, 1);
+}
+
+gint
+gdk_color_context_query_colors(GdkColorContext *cc,
+ GdkColor *colors,
+ gint num_colors)
+{
+ GdkColorContextPrivate *ccp;
+ gint i;
+ GdkColor *tc;
+
+ g_assert(cc != NULL);
+ g_assert(colors != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ switch (ccp->mode) {
+ case GDK_CC_MODE_BW:
+ for (i = 0, tc = colors; i < num_colors; i++, tc++) {
+ if (tc->pixel == ccp->white_pixel)
+ tc->red = tc->green = tc->blue = 65535;
+ else
+ tc->red = tc->green = tc->blue = 0;
+ }
+ break;
+
+ case GDK_CC_MODE_TRUE:
+ if (ccp->clut == NULL)
+ for (i = 0, tc = colors; i < num_colors; i++, tc++) {
+ tc->red = (tc->pixel & ccp->masks.red) * 65535 / ccp->masks.red;
+ tc->green = (tc->pixel & ccp->masks.green) * 65535 / ccp->masks.green;
+ tc->blue = (tc->pixel & ccp->masks.blue) * 65535 / ccp->masks.blue;
+ }
+ else {
+ my_x_query_colors(ccp->colormap, colors, num_colors);
+ return 1;
+ }
+ break;
+
+ case GDK_CC_MODE_STD_CMAP:
+ default:
+ if (ccp->cmap == NULL) {
+ my_x_query_colors(ccp->colormap, colors, num_colors);
+ return 1;
+ } else {
+ gint first, last, half;
+ gulong half_pixel;
+
+ for (i = 0, tc = colors; i < num_colors; i++) {
+ first = 0;
+ last = ccp->num_colors - 1;
+
+ while (first <= last) {
+ half = (first + last) / 2;
+ half_pixel = ccp->cmap[half].pixel;
+
+ if (tc->pixel == half_pixel) {
+ tc->red = ccp->cmap[half].red;
+ tc->green = ccp->cmap[half].green;
+ tc->blue = ccp->cmap[half].blue;
+ first = last + 1; /* false break */
+ } else {
+ if (tc->pixel > half_pixel)
+ first = half + 1;
+ else
+ last = half - 1;
+ }
+ }
+ }
+ return 1;
+ }
+ break;
+ }
+ return 1;
+}
+
+gint
+gdk_color_context_add_palette(GdkColorContext *cc,
+ GdkColor *palette,
+ gint num_palette)
+{
+ GdkColorContextPrivate *ccp;
+ gint i, j, erg;
+ gushort r, g, b;
+ gulong pixel[1];
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ /* initialize this palette (will also erase previous palette as well) */
+
+ init_palette(ccp);
+
+ /* restore previous mode if we aren't adding a new palette */
+
+ if (num_palette == 0) {
+ /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
+
+ /* XXX: here, the hash table is already initialized */
+
+ return 0;
+ }
+
+ /* Initialize a hash table for this palette (we need one for allocating
+ * the pixels in the palette using the current settings)
+ */
+
+ if (ccp->color_hash == NULL)
+ ccp->color_hash = g_hash_table_new(hash_color, compare_colors);
+
+ /* copy incoming palette */
+
+ ccp->palette = g_new0(GdkColor, num_palette);
+
+ j = 0;
+
+ for (i = 0; i < num_palette; i++) {
+ erg = 0;
+ pixel[0] = 0;
+
+ /* try to allocate this color */
+
+ r = palette[i].red;
+ g = palette[i].green;
+ b = palette[i].blue;
+
+ gdk_color_context_get_pixels(cc, &r, &g, &b, 1, pixel, &erg);
+
+ /* only store if we succeed */
+
+ if (erg) {
+ /* store in palette */
+
+ ccp->palette[j].red = r;
+ ccp->palette[j].green = g;
+ ccp->palette[j].blue = b;
+ ccp->palette[j].pixel = pixel[0];
+
+ /* move to next slot */
+
+ j++;
+ }
+ }
+
+ /* resize to fit */
+
+ if (j != num_palette)
+ ccp->palette = g_realloc(ccp->palette, j * sizeof(GdkColor));
+
+ /* clear the hash table, we don't use it when dithering */
+
+ if (ccp->color_hash) {
+ g_hash_table_destroy(ccp->color_hash);
+ ccp->color_hash = NULL;
+ }
+
+ /* store real palette size */
+
+ ccp->num_palette = j;
+
+ /* switch to palette mode */
+
+ ccp->mode = GDK_CC_MODE_PALETTE;
+
+ /* sort palette */
+
+ qsort(ccp->palette, ccp->num_palette, sizeof(GdkColor), pixel_sort);
+
+ ccp->fast_dither = NULL;
+
+ return j;
+}
+
+void
+gdk_color_context_init_dither(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+ gint rr, gg, bb, err, erg, erb;
+ gint success = FALSE;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ /* now we can initialize the fast dither matrix */
+
+ if(ccp->fast_dither == NULL)
+ ccp->fast_dither = g_new(GdkColorContextDither, 1);
+
+ /* Fill it. We ignore unsuccessful allocations, they are just mapped
+ * to black instead */
+
+ for (rr = 0; rr < 32; rr++)
+ for (gg = 0; gg < 32; gg++)
+ for (bb = 0; bb < 32; bb++) {
+ err = (rr << 3) | (rr >> 2);
+ erg = (gg << 3) | (gg >> 2);
+ erb = (bb << 3) | (bb >> 2);
+
+ ccp->fast_dither->fast_rgb[rr][gg][bb] =
+ gdk_color_context_get_index_from_palette(cc, &err, &erg, &erb, &success);
+ ccp->fast_dither->fast_err[rr][gg][bb] = err;
+ ccp->fast_dither->fast_erg[rr][gg][bb] = erg;
+ ccp->fast_dither->fast_erb[rr][gg][bb] = erb;
+ }
+}
+
+void
+gdk_color_context_free_dither(GdkColorContext *cc)
+{
+ GdkColorContextPrivate *ccp;
+
+ g_assert(cc != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ if (ccp->fast_dither)
+ g_free(ccp->fast_dither);
+
+ ccp->fast_dither = NULL;
+}
+
+gulong
+gdk_color_context_get_pixel_from_palette(GdkColorContext *cc,
+ gushort *red,
+ gushort *green,
+ gushort *blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+ gulong pixel = 0;
+ gint dif, dr, dg, db, j = -1;
+ gint mindif = 0x7fffffff;
+ gint err = 0, erg = 0, erb = 0;
+ gint i;
+
+ g_assert(cc != NULL);
+ g_assert(red != NULL);
+ g_assert(green != NULL);
+ g_assert(blue != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ for (i = 0; i < ccp->num_palette; i++) {
+ dr = *red - ccp->palette[i].red;
+ dg = *green - ccp->palette[i].green;
+ db = *blue - ccp->palette[i].blue;
+
+ dif = dr * dr + dg * dg + db * db;
+
+ if (dif < mindif) {
+ mindif = dif;
+ j = i;
+ pixel = ccp->palette[i].pixel;
+ err = dr;
+ erg = dg;
+ erb = db;
+
+ if (mindif == 0)
+ break;
+ }
+ }
+
+ /* we failed to map onto a color */
+
+ if (j == -1)
+ *failed = TRUE;
+ else {
+ *red = ABS(err);
+ *green = ABS(erg);
+ *blue = ABS(erb);
+ }
+
+ return pixel;
+}
+
+guchar
+gdk_color_context_get_index_from_palette(GdkColorContext *cc,
+ gint *red,
+ gint *green,
+ gint *blue,
+ gint *failed)
+{
+ GdkColorContextPrivate *ccp;
+ gint dif, dr, dg, db, j = -1;
+ gint mindif = 0x7fffffff;
+ gint err = 0, erg = 0, erb = 0;
+ gint i;
+
+ g_assert(cc != NULL);
+ g_assert(red != NULL);
+ g_assert(green != NULL);
+ g_assert(blue != NULL);
+ g_assert(failed != NULL);
+
+ ccp = (GdkColorContextPrivate *) cc;
+
+ *failed = FALSE;
+
+ for (i = 0; i < ccp->num_palette; i++) {
+ dr = *red - ccp->palette[i].red;
+ dg = *green - ccp->palette[i].green;
+ db = *blue - ccp->palette[i].blue;
+
+ dif = dr * dr + dg * dg + db * db;
+
+ if (dif < mindif) {
+ mindif = dif;
+ j = i;
+ err = dr;
+ erg = dg;
+ erb = db;
+
+ if (mindif == 0)
+ break;
+ }
+ }
+
+ /* we failed to map onto a color */
+
+ if (j == -1) {
+ *failed = TRUE;
+ j = 0;
+ } else {
+ /* return error fractions */
+
+ *red = err;
+ *green = erg;
+ *blue = erb;
+ }
+
+ return j;
+}