    Retrieve standard color settings in macro code

    This can be useful in macros for preparing rangeset colors related to the
    current background/foreground color settings.

    The new macro function get_colors() returns an array with the following
    indices:

    - ["default_text_fg"]     Foreground color name
    - ["default_text_bg"]     Background color name
    - ["default_select_fg"]   Foreground selection color name
    - ["default_select_bg"]   Background selection color name
    - ["default_hilite_fg"]   Foreground match-highlight color name
    - ["default_hilite_bg"]   Background match-highlight color name
    - ["default_lineno_fg"]   Foreground line number color name
    - ["default_cursor_fg"]   Foreground cursor color name

    - ["rgb_text_fg"]         Foreground color RGB value
    - ["rgb_text_bg"]         Background color RGB value
    - ["rgb_select_fg"]       Foreground selection color RGB value
    - ["rgb_select_bg"]       Background selection color RGB value
    - ["rgb_hilite_fg"]       Foreground match-highlight color RGB value
    - ["rgb_hilite_bg"]       Background match-highlight color RGB value
    - ["rgb_lineno_fg"]       Foreground line number color RGB value
    - ["rgb_cursor_fg"]       Foreground cursor color RGB value

    Currently, the RGB color value retrieval mechanism, using the text
    widget's resources, is not perfect - the following values are not set:
    rgb_select_fg, rgb_lineno_fg, rgb_cursor_fg; the following values are
    set initially, but if changed using the color settings dialog, will not
    be updated: rgb_select_bg, rgb_hilite_fg, rgb_hilite_bg.

    2008-03-29

    Added another group prefixed with "window_" for the color names used for
    the current window. Also added a function called set_color() for changing
    values. This can be done using the names starting with "window_" only, or
    formed by dropping the "rgb_" or "default_" prefix.

cd ..;diff -ur nedit_official nedit_mod
diff -ur nedit_official/source/help.c nedit_mod/source/help.c
--- nedit_official/source/help.c	2007-12-29 01:51:50.000000000 +0100
+++ nedit_mod/source/help.c	2008-03-28 23:50:08.000000000 +0100
@@ -399,7 +399,7 @@
 
         if (style == STL_NM_LINK)
             HelpStyleInfo[STYLE_INDEX(style)].color =
-                AllocColor(parent, GetPrefHelpLinkColor(), &r, &g, &b);
+                AllocFgColor(parent, GetPrefHelpLinkColor(), &r, &g, &b);
     }
 }
 
diff -ur nedit_official/source/highlight.c nedit_mod/source/highlight.c
--- nedit_official/source/highlight.c	2008-01-04 23:11:03.000000000 +0100
+++ nedit_mod/source/highlight.c	2008-03-28 23:53:07.000000000 +0100
@@ -775,12 +775,12 @@
       p->isBold = FontOfNamedStyleIsBold(pat->style); \
       p->isItalic = FontOfNamedStyleIsItalic(pat->style); \
       /* And now for the more physical stuff */ \
-      p->color = AllocColor(window->textArea, p->colorName, &r, &g, &b); \
+      p->color = AllocFgColor(window->textArea, p->colorName, &r, &g, &b); \
       p->red = r; \
       p->green = g; \
       p->blue = b; \
       if (p->bgColorName) { \
-        p->bgColor = AllocColor(window->textArea, p->bgColorName, &r, &g, &b); \
+        p->bgColor = AllocBgColor(window->textArea, p->bgColorName, &r,&g,&b); \
         p->bgRed = r; \
         p->bgGreen = g; \
         p->bgBlue = b; \
@@ -1209,64 +1209,74 @@
     return entry ? entry->styleName : "";
 }
 
+Boolean ColorValueOfPixel(WindowInfo *window, Pixel pixel,
+    int *r, int *g, int *b)
+{
+    /* pick up the color information for a pixel */
+    XColor colorDef;
+    Colormap cMap;
+    Display *display = XtDisplay(window->textArea);
+    *r = *g = *b = 0;
+    colorDef.pixel = pixel;
+    XtVaGetValues(window->textArea,
+                  XtNcolormap, &cMap,
+                  NULL);
+    if (XQueryColor(display, cMap, &colorDef)) {
+        *r = colorDef.red;
+        *g = colorDef.green;
+        *b = colorDef.blue;
+        return True;
+    }
+    return False;
+}
+
+Boolean ColorValueOfResource(WindowInfo *window, String colorResource,
+    int *r, int *g, int *b, Pixel *pixel)
+{
+    /* pick up the pixel value */
+    XtVaGetValues(window->textArea,
+                  colorResource, pixel,
+                  NULL);
+    /* now pick up the components */
+    return ColorValueOfPixel(window, *pixel, r, g, b);
+}
+
 Pixel HighlightColorValueOfCode(WindowInfo *window, int hCode,
       int *r, int *g, int *b)
 {
     styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
+    Pixel pixel;
+
     if (entry) {
         *r = entry->red;
         *g = entry->green;
         *b = entry->blue;
         return entry->color;
     }
-    else
+    else if (ColorValueOfResource(window, XtNforeground, r, g, b, &pixel))
     {
-        /* pick up foreground color of the (first) text widget of the window */
-        XColor colorDef;
-        Colormap cMap;
-        Display *display = XtDisplay(window->textArea);
-        *r = *g = *b = 0;
-        XtVaGetValues(window->textArea,
-                      XtNcolormap,   &cMap,
-                      XtNforeground, &colorDef.pixel,
-                      NULL);
-        if (XQueryColor(display, cMap, &colorDef)) {
-            *r = colorDef.red;
-            *g = colorDef.green;
-            *b = colorDef.blue;
-        }
-        return colorDef.pixel;
+        return pixel;
     }
+    return (Pixel)0;
 }
 
 Pixel GetHighlightBGColorOfCode(WindowInfo *window, int hCode,
       int *r, int *g, int *b)
 {
     styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
+    Pixel pixel;
+
     if (entry && entry->bgColorName) {
         *r = entry->bgRed;
         *g = entry->bgGreen;
         *b = entry->bgBlue;
         return entry->bgColor;
     }
-    else
+    else if (ColorValueOfResource(window, XtNbackground, r, g, b, &pixel))
     {
-        /* pick up background color of the (first) text widget of the window */
-        XColor colorDef;
-        Colormap cMap;
-        Display *display = XtDisplay(window->textArea);
-        *r = *g = *b = 0;
-        XtVaGetValues(window->textArea,
-                      XtNcolormap,   &cMap,
-                      XtNbackground, &colorDef.pixel,
-                      NULL);
-        if (XQueryColor(display, cMap, &colorDef)) {
-            *r = colorDef.red;
-            *g = colorDef.green;
-            *b = colorDef.blue;
-        }
-        return colorDef.pixel;
+        return pixel;
     }
+    return (Pixel)0;
 }
 
 /*
@@ -1956,15 +1966,22 @@
 }
 
 /*
-** use this canned function to call AllocColor() when
+** use these canned function to call AllocFg/BgColor() when
 ** the r, g & b components is not needed, thus saving
 ** the little hassle of creating the dummy variable.
 */
-Pixel AllocateColor(Widget w, const char *colorName)
+Pixel AllocateFgColor(Widget w, const char *colorName)
 {
     int dummy;
     
-    return AllocColor(w, colorName, &dummy, &dummy, &dummy);
+    return AllocFgColor(w, colorName, &dummy, &dummy, &dummy);
+}
+
+Pixel AllocateBgColor(Widget w, const char *colorName)
+{
+    int dummy;
+    
+    return AllocBgColor(w, colorName, &dummy, &dummy, &dummy);
 }
 
 /*
@@ -1973,18 +1990,13 @@
 ** the colormap is full and there's no suitable substitute, print an error on
 ** stderr, and return the widget's foreground color as a backup.
 */
+/* WE SHOULD REALLY PUT THIS ELSEWHERE - THE textDisp WIDGET USES IT TOO */
 
-Pixel AllocColor(Widget w, const char *colorName, int *r, int *g, int *b)
+Pixel AllocFgColor(Widget w, const char *colorName, int *r, int *g, int *b)
 {
-    XColor       colorDef;
-    XColor      *allColorDefs;
-    Display     *display = XtDisplay(w);
     Colormap     cMap;
-    Pixel        foreground, bestPixel;
-    double       small = 1.0e9;
+    Pixel    foreground;
     int          depth;
-    unsigned int ncolors;
-    unsigned long i, best = 0;    /* pixel value */
     
     /* Get the correct colormap for compatability with the "best" visual
        feature in 5.2.  Default visual of screen is no good here. */
@@ -1995,18 +2007,50 @@
                   XtNforeground, &foreground,
                   NULL);
 
-    bestPixel = foreground; /* Our last fallback */
+    return AllocColorDef(w, colorName, r, g, b, cMap, depth, foreground);
+}
+
+Pixel AllocBgColor(Widget w, const char *colorName, int *r, int *g, int *b)
+{
+    Colormap cMap;
+    Pixel    background;
+    int      depth;
+
+    /* Get the correct colormap for compatability with the "best" visual
+       feature in 5.2.  Default visual of screen is no good here. */
+
+    XtVaGetValues(w,
+                  XtNcolormap,   &cMap,
+                  XtNdepth,      &depth,
+                  XtNbackground, &background,
+                  NULL);
+
+    return AllocColorDef(w, colorName, r, g, b, cMap, depth, background);
+}
+
+Pixel AllocColorDef(Widget w, const char *colorName, int *r, int *g, int *b,
+    Colormap cMap, int depth, Pixel defaultColor)
+{
+    XColor       colorDef;
+    XColor      *allColorDefs;
+    Display     *display = XtDisplay(w);
+    Pixel        bestPixel;
+    double       small = 1.0e9;
+    unsigned int ncolors;
+    unsigned long i, best = 0;    /* pixel value */
+
+    bestPixel = defaultColor; /* Our last fallback */
 
     /* First, check for valid syntax */        
     if (! XParseColor(display, cMap, colorName, &colorDef)) {
         fprintf(stderr, "NEdit: Color name %s not in database\n",  colorName);
-        colorDef.pixel = foreground;
+        colorDef.pixel = defaultColor;
         if (XQueryColor(display, cMap, &colorDef)) {
             *r = colorDef.red;
 	    *g = colorDef.green;
 	    *b = colorDef.blue;
         }
-        return foreground;
+        return defaultColor;
     }
 
     /* Attempt allocation of the exact color. */
@@ -2019,21 +2063,17 @@
 
     /* ---------- Allocation failed, the colormap may be full. ---------- */
 
-#if 0
-    printf("Couldn't allocate %d %d %d\n", colorDef.red, colorDef.green, colorDef.blue);
-#endif
- 
     /* We can't do the nearest-match on other than 8 bit visuals because
        it just takes too long.  */
 
     if (depth > 8) {             /* Oh no! */
-        colorDef.pixel = foreground;
+        colorDef.pixel = defaultColor;
         if (XQueryColor(display, cMap, &colorDef)) {
 	    *r = colorDef.red;
 	    *g = colorDef.green;
 	    *b = colorDef.blue;
         }
-        return foreground;
+        return defaultColor;
     }
 
     /* Get the entire colormap so we can find the closest one. */
@@ -2065,13 +2105,6 @@
     if (XAllocColor(display, cMap, &allColorDefs[best]))
         bestPixel = allColorDefs[best].pixel;
 
-#if 0
-    printf("Got %d %d %d, ", allColorDefs[best].red,
-                             allColorDefs[best].green,
-                             allColorDefs[best].blue);
-    printf("That's %f off\n", small);
-#endif
-
     *r = allColorDefs[best].red;
     *g = allColorDefs[best].green;
     *b = allColorDefs[best].blue;
@@ -2080,6 +2113,19 @@
 }
 
 /*
+** Return true if the color name supplied appears valid.
+*/
+int AllocColorNameIsValid(Widget w, const char *colorName)
+{
+    Colormap cMap;
+    Display *display = XtDisplay(w);
+    XColor colorDef;
+
+    XtVaGetValues(w, XtNcolormap, &cMap, NULL);
+    return XParseColor(display, cMap, colorName, &colorDef);
+}
+
+/*
 ** Get the character before position "pos" in buffer "buf"
 */
 static char getPrevChar(textBuffer *buf, int pos)
diff -ur nedit_official/source/highlight.h nedit_mod/source/highlight.h
--- nedit_official/source/highlight.h	2008-01-04 23:11:03.000000000 +0100
+++ nedit_mod/source/highlight.h	2008-03-28 23:47:47.000000000 +0100
@@ -70,8 +70,12 @@
 void RemoveWidgetHighlight(Widget widget);
 void UpdateHighlightStyles(WindowInfo *window);
 int TestHighlightPatterns(patternSet *patSet);
-Pixel AllocateColor(Widget w, const char *colorName);
-Pixel AllocColor(Widget w, const char *colorName, int *r, int *g, int *b);
+Pixel AllocateFgColor(Widget w, const char *colorName);
+Pixel AllocateBgColor(Widget w, const char *colorName);
+Pixel AllocFgColor(Widget w, const char *colorName, int *r, int *g, int *b);
+Pixel AllocBgColor(Widget w, const char *colorName, int *r, int *g, int *b);
+Pixel AllocColorDef(Widget w, const char *colorName, int *r, int *g, int *b,
+    Colormap cMap, int depth, Pixel defaultColor);
 void* GetHighlightInfo(WindowInfo *window, int pos);
 highlightPattern *FindPatternOfWindow(WindowInfo *window, char *name);
 int HighlightCodeOfPos(WindowInfo *window, int pos);
@@ -79,6 +83,10 @@
 int StyleLengthOfCodeFromPos(WindowInfo *window, int pos, const char **checkStyleName);
 char *HighlightNameOfCode(WindowInfo *window, int hCode);
 char *HighlightStyleOfCode(WindowInfo *window, int hCode);
+Boolean ColorValueOfPixel(WindowInfo *window, Pixel pixel,
+    int *r, int *g, int *b);
+Boolean ColorValueOfResource(WindowInfo *window, String colorResource,
+    int *r, int *g, int *b, Pixel *pixel);
 Pixel HighlightColorValueOfCode(WindowInfo *window, int hCode,
       int *r, int *g, int *b);
 Pixel GetHighlightBGColorOfCode(WindowInfo *window, int hCode,
diff -ur nedit_official/source/macro.c nedit_mod/source/macro.c
--- nedit_official/source/macro.c	2007-10-04 18:04:25.000000000 +0200
+++ nedit_mod/source/macro.c	2008-03-28 23:58:43.000000000 +0100
@@ -395,6 +395,12 @@
         DataValue *result, char **errMsg);
 static int getPatternAtPosMS(WindowInfo *window, DataValue *argList, int nArgs,
         DataValue *result, char **errMsg);
+static int getsetColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg, int minArgs, int maxArgs);
+static int getColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg);
+static int setColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg);
 
 static int fillStyleResult(DataValue *result, char **errMsg,
         WindowInfo *window, char *styleName, Boolean preallocatedStyleName,
@@ -422,6 +428,7 @@
         rangesetInfoMS, rangesetRangeMS, rangesetIncludesPosMS,
         rangesetSetColorMS, rangesetSetNameMS, rangesetSetModeMS,
         rangesetGetByNameMS,
+        getColorsMS, setColorsMS,
         getPatternByNameMS, getPatternAtPosMS,
         getStyleByNameMS, getStyleAtPosMS, filenameDialogMS
     };
@@ -441,6 +448,7 @@
         "rangeset_info", "rangeset_range", "rangeset_includes",
         "rangeset_set_color", "rangeset_set_name", "rangeset_set_mode",
         "rangeset_get_by_name",
+        "get_colors",
         "get_pattern_by_name", "get_pattern_at_pos",
         "get_style_by_name", "get_style_at_pos", "filename_dialog"
     };
@@ -5004,7 +5012,8 @@
     char *color, *name, *mode;
     DataValue element;
     int label = 0;
-    
+    Pixel *pixel;
+
     if (nArgs != 1)
       return wrongNArgsErr(errMsg);
         
@@ -5017,7 +5026,8 @@
         rangeset = RangesetFetch(rangesetTable, label);
     }
 
-    RangesetGetInfo(rangeset, &defined, &label, &count, &color, &name, &mode);
+    RangesetGetInfo(rangeset, &defined, &label, &count,
+                    &color, &name, &mode, &pixel);
     
     /* set up result */    
     result->tag = ARRAY_TAG;
@@ -5038,7 +5048,17 @@
         M_FAILURE("Failed to allocate array value \"color\" in %s");
     if (!ArrayInsert(result, PERM_ALLOC_STR("color"), &element))
         M_FAILURE("Failed to insert array element \"color\" in %s");
-  
+    if (pixel) {
+        int r, g, b;
+        char colorValue[20];
+        if (ColorValueOfPixel(window, *pixel, &r, &g, &b)) {
+            sprintf(colorValue, "#%02x%02x%02x", r/256, g/256, b/256);
+            if (!AllocNStringCpy(&element.val.str, colorValue) ||
+                !ArrayInsert(result, PERM_ALLOC_STR("rgb"), &element))
+                M_FAILURE("Failed to insert array element \"rgb\" in %s");
+        }
+    }
+
     element.tag = STRING_TAG;
     if (!AllocNStringCpy(&element.val.str, name))
         M_FAILURE("Failed to allocate array value \"name\" in %s");
@@ -5177,9 +5197,10 @@
 }
 
 /*
-** Set the color of a range set's ranges. it is ignored if the color cannot be
-** found/applied. If no color is applied, any current color is removed. Returns
-** true if the rangeset is valid.
+** Set the color of a range set's ranges. If the color name is empty, the
+** current color is removed. If the color name is invalid, the function returns
+** false. Otherwise the color is applied to the range set. Fails if the
+** the rangeset is invalid.
 */
 static int rangesetSetColorMS(WindowInfo *window, DataValue *argList,
       int nArgs, DataValue *result, char **errMsg)
@@ -5187,9 +5208,10 @@
     char stringStorage[1][TYPE_INT_STR_SIZE(int)];
     textBuffer *buffer = window->buffer;
     RangesetTable *rangesetTable = buffer->rangesetTable;
-    Rangeset *rangeset;
+    Rangeset *rangeset = NULL;
     char *color_name;
     int label = 0;
+    int isOK = 1;
 
     if (nArgs != 2) {
         return wrongNArgsErr(errMsg);
@@ -5200,11 +5222,10 @@
         M_FAILURE("First parameter is an invalid rangeset label in %s");
     }
 
-    if (rangesetTable == NULL) {
-        M_FAILURE("Rangeset does not exist in %s");
+    if (rangesetTable != NULL) {
+        rangeset = RangesetFetch(rangesetTable, label);
     }
 
-    rangeset = RangesetFetch(rangesetTable, label);
     if (rangeset == NULL) {
         M_FAILURE("Rangeset does not exist in %s");
     }
@@ -5212,14 +5233,19 @@
     color_name = "";
     if (rangeset != NULL) {
         if (!readStringArg(argList[1], &color_name, stringStorage[0], errMsg)) {
-            M_FAILURE("Second parameter is not a color name string in %s");
+            M_FAILURE("Second (color name) parameter is not a string in %s");
         }
     }
-    
-    RangesetAssignColorName(rangeset, color_name);
-            
+    if (*color_name) {
+        isOK = AllocColorNameIsValid(window->textArea, color_name);
+    }
+    if (isOK) {
+        RangesetAssignColorName(rangeset, color_name);
+    }
+
     /* set up result */
-    result->tag = NO_TAG;
+    result->tag = INT_TAG;
+    result->val.n = isOK;
     return True;
 }
 
@@ -5676,6 +5702,239 @@
         HighlightStyleOfCode(window, patCode), bufferPos);
 }
 
+/*
+** Return 0 for filter not in name, -1 for filter in name and 1 for filter
+** matches a "window_" name up to its end. See getColorsMS().
+*/
+static int getColorNamesMatch(const char *name, const char *filter)
+{
+    const char *pos = strstr(name, filter);
+    size_t nameLen = strlen(name);
+    size_t filterLen = strlen(filter);
+    int isWindow;
+
+    static const char windowStr[] = "window_";
+    static const size_t windowLen = sizeof windowStr - 1;
+    
+    if (!pos)
+        return 0; /* no match */
+
+    isWindow = (strncmp(name, windowStr, windowLen) == 0);
+    if (isWindow) {
+        if (pos + filterLen == name + nameLen &&
+            pos <= name + windowLen) {
+            return 1; /* filter matches at least everything after "window_" */
+        }
+    }
+    return -1; /* partial match */
+}
+
+/*
+** Returns an array containing information about the window's colors. The keys
+** have the form "(default|window|rgb)_attribute_(fg|bg)" where the attribute
+** part is one of:
+**      "text" (normal text fg/bg colors),
+**      "select" (primary selection fg/bg colors),
+**      "hilite" (bracket-match highlighting fg/bg colors),
+**      "lineno" (line number fg color),
+**      "cursor" (text cursor fg color),
+**      "wrapmargin" (wrap margin indicator fg color)
+** The prefixes are:
+**      "default" (default preference color for attribute)
+**      "window" (current window's color)
+**      "rgb" (a string built from 2 digit hexadecimal values for the red, green
+**             and blue components of the window's assigned color value)
+**
+** You can provide a filter to avoid returning all values: if the filter text
+** is found in the name, that name and its value are added to the array result.
+**
+** You can provide new values for window color values by placing a value
+** parameter after the filter, which, in this case, must match everything
+** following the first underscore.
+** 
+**      a = get_colors()
+**      a = get_colors("window")
+**      a = get_colors("text")
+**      a = get_colors("fg")
+**      colorName = get_colors("text_fg")
+**      colorName = get_colors("default_text_fg")
+**      colorName = set_colors("text_fg", "darkblue")
+**      colorName = set_colors("window_text_fg", "darkblue")
+**      colorName = set_colors("default_text_fg", "darkblue")   # fails
+**      a = set_colors("text", "darkblue")                      # fails
+*/
+static int getColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg)
+{
+    return getsetColorsMS(window, argList, nArgs, result,  errMsg, 0, 1);
+}
+static int setColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg)
+{
+    return getsetColorsMS(window, argList, nArgs, result,  errMsg, 2, 2);
+}
+
+static int getsetColorsMS(WindowInfo *window, DataValue *argList, int nArgs,
+        DataValue *result, char **errMsg, int minArgs, int maxArgs)
+{
+    char stringStorage[2][TYPE_INT_STR_SIZE(int)];
+    DataValue DV;
+    char colorValue[20];
+    int r, g, b;
+    int i, nMatch, nFound, foundIndex;
+    char *filter, *value, *foundName;
+    WindowColor *colorVals = window->colors.colorVals;
+
+    typedef struct NameToColorVal_ {
+        char *name;
+        int index;
+    } NameToColorVal;
+    static NameToColorVal default_colors[] = {
+        { PERM_ALLOC_STR("default_text_fg"),       TEXT_FG_COLOR       },
+        { PERM_ALLOC_STR("default_text_bg"),       TEXT_BG_COLOR       },
+        { PERM_ALLOC_STR("default_select_fg"),     SELECT_FG_COLOR     },
+        { PERM_ALLOC_STR("default_select_bg"),     SELECT_BG_COLOR     },
+        { PERM_ALLOC_STR("default_hilite_fg"),     HILITE_FG_COLOR     },
+        { PERM_ALLOC_STR("default_hilite_bg"),     HILITE_BG_COLOR     },
+        { PERM_ALLOC_STR("default_lineno_fg"),     LINENO_FG_COLOR     },
+        { PERM_ALLOC_STR("default_cursor_fg"),     CURSOR_FG_COLOR     },
+        { NULL,                                    0 }
+    };
+    static NameToColorVal window_colors[] = {
+        { PERM_ALLOC_STR("window_text_fg"),       TEXT_FG_COLOR       },
+        { PERM_ALLOC_STR("window_text_bg"),       TEXT_BG_COLOR       },
+        { PERM_ALLOC_STR("window_select_fg"),     SELECT_FG_COLOR     },
+        { PERM_ALLOC_STR("window_select_bg"),     SELECT_BG_COLOR     },
+        { PERM_ALLOC_STR("window_hilite_fg"),     HILITE_FG_COLOR     },
+        { PERM_ALLOC_STR("window_hilite_bg"),     HILITE_BG_COLOR     },
+        { PERM_ALLOC_STR("window_lineno_fg"),     LINENO_FG_COLOR     },
+        { PERM_ALLOC_STR("window_cursor_fg"),     CURSOR_FG_COLOR     },
+        { NULL,                                   0 }
+    };
+    static NameToColorVal color_rgb[] = {
+        { PERM_ALLOC_STR("rgb_text_fg"),        TEXT_FG_COLOR       },
+        { PERM_ALLOC_STR("rgb_text_bg"),        TEXT_BG_COLOR       },
+        { PERM_ALLOC_STR("rgb_select_fg"),      SELECT_FG_COLOR     },
+        { PERM_ALLOC_STR("rgb_select_bg"),      SELECT_BG_COLOR     },
+        { PERM_ALLOC_STR("rgb_hilite_fg"),      HILITE_FG_COLOR     },
+        { PERM_ALLOC_STR("rgb_hilite_bg"),      HILITE_BG_COLOR     },
+        { PERM_ALLOC_STR("rgb_lineno_fg"),      LINENO_FG_COLOR     },
+        { PERM_ALLOC_STR("rgb_cursor_fg"),      CURSOR_FG_COLOR     },
+        { NULL,                                 0 }
+    };
+    static NameToColorVal *nameToColorValTables[] = {
+        default_colors,
+        window_colors,
+        color_rgb,
+        NULL
+    };
+    NameToColorVal *p;
+
+    filter = value = foundName = NULL;
+    foundIndex = 0;
+
+    if (nArgs < minArgs || maxArgs < nArgs) {
+        return wrongNArgsErr(errMsg);
+    }
+    if (nArgs > 0) {
+        if (!readStringArg(argList[0], &filter, stringStorage[0], errMsg)) {
+            M_FAILURE("First parameter (color name filter) not a string in %s");
+        }
+    }
+    if (nArgs > 1) {
+        if (!readStringArg(argList[1], &value, stringStorage[1], errMsg)) {
+            M_FAILURE("Second parameter (new color value) not a string in %s");
+        }
+    }
+
+    /* the following array entries will be strings */
+    DV.tag = STRING_TAG;
+
+    /* with filters, count how many entries match - don't bother beyond 2
+       matches or an exact match */
+    nMatch = nFound = 0;
+    if (filter && value) {
+        for (i = 0; nameToColorValTables[i] && nMatch < 2 && nFound < 1; ++i) {
+            p = nameToColorValTables[i];
+            for (; p->name && nMatch < 2 && nFound < 1; ++p) {
+                int res = getColorNamesMatch(p->name, filter);
+                nMatch += (res < 0);    /* partial match */
+                if (res > 0) {          /* full match */
+                    ++nFound;
+                    foundIndex = p->index;
+                    foundName = p->name;
+                }
+            }
+        }
+    }
+
+    if (!nFound && value) {
+        /* inexact match for a setting operation: invalid */
+        M_FAILURE("No exact color attribute match for setting in %s");
+        return False;
+    }
+    if (nFound && value) {
+        result->tag = STRING_TAG;
+        if (AllocColorNameIsValid(window->textArea, value)) {
+            /* set the new color (foreground if attr name ends with "_fg" */
+            const char *fg = strstr(foundName, "_fg");
+            RecalcColor(&colorVals[foundIndex], window->textArea, value,
+                        fg && strcmp(fg, "_fg") == 0);
+            WindowColorsUpdate(window);
+            /* deal with result: pass back the color value string */
+            AllocNStringCpy(&result->val.str, value);
+        }
+        else {
+            /* invalid color name: pass back current value */
+            AllocNStringCpy(&result->val.str, colorVals[foundIndex].name);
+        }
+        return True;
+    }
+
+    /* initialize array */
+    result->tag = ARRAY_TAG;
+    result->val.arrayPtr = ArrayNew();
+
+    /* insert default color names */
+    for (p = default_colors; p->name; ++p) {
+        if (filter && !getColorNamesMatch(p->name, filter))
+            continue;
+        AllocNStringCpy(&DV.val.str, GetPrefColorName(p->index));
+        M_STR_ALLOC_ASSERT(DV);
+        if (!ArrayInsert(result, p->name, &DV)) {
+            M_ARRAY_INSERT_FAILURE();
+        }
+    }
+
+    /* insert window color names */
+    for (p =window_colors; p->name; ++p) {
+        if (filter && !getColorNamesMatch(p->name, filter))
+            continue;
+        AllocNStringCpy(&DV.val.str, colorVals[p->index].name);
+        M_STR_ALLOC_ASSERT(DV);
+        if (!ArrayInsert(result, p->name, &DV)) {
+            M_ARRAY_INSERT_FAILURE();
+        }
+    }
+
+    /* insert color values */
+    for (p = color_rgb; p->name; ++p) {
+        if (filter && !getColorNamesMatch(p->name, filter))
+            continue;
+        if (ColorValueOfPixel(window, colorVals[p->index].pixel, &r, &g, &b))
+        {
+            sprintf(colorValue, "#%02x%02x%02x", r/256, g/256, b/256);
+            AllocNStringCpy(&DV.val.str, colorValue);
+            M_STR_ALLOC_ASSERT(DV);
+            if (!ArrayInsert(result, p->name, &DV)) {
+                M_ARRAY_INSERT_FAILURE();
+            }
+        }
+    }
+
+    return True;
+}
+
 static int wrongNArgsErr(char **errMsg)
 {
     *errMsg = "Wrong number of arguments to function %s";
diff -ur nedit_official/source/nedit.h nedit_mod/source/nedit.h
--- nedit_official/source/nedit.h	2008-01-04 23:11:03.000000000 +0100
+++ nedit_mod/source/nedit.h	2008-03-28 22:48:54.000000000 +0100
@@ -255,6 +255,18 @@
     UserMenuList ubmcMenuList;        /* list of all background menu items */
 } UserBGMenuCache;
 
+/* The WindowColors structure holds onton names and values of all colors used
+   by a window's text widget.
+ */
+typedef struct WindowColor_ {
+    char name[MAX_COLOR_LEN];
+    Pixel pixel;
+} WindowColor;
+
+typedef struct WindowColors_ {
+    WindowColor colorVals[NUM_COLORS];
+} WindowColors;
+
 /* The WindowInfo structure holds the information on a Document. A number
    of 'tabbed' documents may reside within a shell window, hence some of 
    its members are of 'shell-level'; namely the find/replace dialogs, the
@@ -557,6 +569,8 @@
     UserBGMenuCache  userBGMenuCache;   /* shell & macro menu are shared over all
                                            "tabbed" documents, while each document
                                            has its own background menu. */
+
+    WindowColors colors;                /* colors used for the text widget */
 } WindowInfo;
 
 extern WindowInfo *WindowList;
diff -ur nedit_official/source/preferences.c nedit_mod/source/preferences.c
--- nedit_official/source/preferences.c	2008-01-14 21:39:20.000000000 +0100
+++ nedit_mod/source/preferences.c	2008-03-28 23:52:13.000000000 +0100
@@ -4363,9 +4363,9 @@
     origFontName = XmTextGetString(fontTextW);
 
     /* Get the values from the defaults */
-    fgPixel = AllocColor(parent, GetPrefColorName(TEXT_FG_COLOR),
+    fgPixel = AllocFgColor(parent, GetPrefColorName(TEXT_FG_COLOR),
             &dummy, &dummy, &dummy);
-    bgPixel = AllocColor(parent, GetPrefColorName(TEXT_BG_COLOR),
+    bgPixel = AllocBgColor(parent, GetPrefColorName(TEXT_BG_COLOR),
             &dummy, &dummy, &dummy);
 
     newFontName = FontSel(parent, PREF_FIXED, origFontName, fgPixel, bgPixel);
diff -ur nedit_official/source/rangeset.c nedit_mod/source/rangeset.c
--- nedit_official/source/rangeset.c	2008-02-11 20:50:53.000000000 +0100
+++ nedit_mod/source/rangeset.c	2008-03-28 22:51:31.000000000 +0100
@@ -693,7 +693,8 @@
 ** Get information about rangeset.
 */
 void RangesetGetInfo(Rangeset *rangeset, int *defined, int *label, 
-        int *count, char **color, char **name, char **mode)
+        int *count, char **color, char **name, char **mode,
+        Pixel **pixel)
 {
     if (rangeset == NULL) {
         *defined = False;
@@ -702,6 +703,7 @@
         *color = "";
         *name = "";
         *mode = "";
+        *pixel = (Pixel *)0;
     }
     else {
         *defined = True;
@@ -710,6 +712,7 @@
         *color = rangeset->color_name ? rangeset->color_name : "";
         *name = rangeset->name ? rangeset->name : "";
         *mode = rangeset->update_name;
+        *pixel = (rangeset->color_set == 1) ? &rangeset->color : (Pixel *)0;
     }
 }
 
@@ -1148,6 +1151,14 @@
     return 1;
 }
 
+/*
+** Return the color name, if any.
+*/
+
+char *RangesetGetColorName(Rangeset *rangeset)
+{
+    return rangeset->color_name;
+}
 
 /*
 ** Return the name, if any.
diff -ur nedit_official/source/rangeset.h nedit_mod/source/rangeset.h
--- nedit_official/source/rangeset.h	2008-01-04 23:11:04.000000000 +0100
+++ nedit_mod/source/rangeset.h	2008-03-28 22:53:24.000000000 +0100
@@ -53,7 +53,8 @@
 int RangesetRemoveBetween(Rangeset *rangeset, int start, int end);
 int RangesetGetNRanges(Rangeset *rangeset);
 void RangesetGetInfo(Rangeset *rangeset, int *defined, int *label, 
-        int *count, char **color, char **name, char **mode);
+        int *count, char **color, char **name, char **mode,
+        Pixel **pixel);
 RangesetTable *RangesetTableAlloc(textBuffer *buf);
 RangesetTable *RangesetTableFree(RangesetTable *table);
 RangesetTable *RangesetTableClone(RangesetTable *srcTable,
@@ -71,6 +72,7 @@
 int RangesetIndex1ofPos(RangesetTable *table, int pos, int needs_color);
 int RangesetAssignColorName(Rangeset *rangeset, char *color_name);
 int RangesetAssignColorPixel(Rangeset *rangeset, Pixel color, int ok);
+char *RangesetGetColorName(Rangeset *rangeset);
 char *RangesetGetName(Rangeset *rangeset);
 int RangesetAssignName(Rangeset *rangeset, char *name);
 int RangesetGetColorValid(Rangeset *rangeset, Pixel *color);
diff -ur nedit_official/source/textDisp.c nedit_mod/source/textDisp.c
--- nedit_official/source/textDisp.c	2008-01-04 23:31:48.000000000 +0100
+++ nedit_mod/source/textDisp.c	2008-03-28 23:52:08.000000000 +0100
@@ -3662,7 +3662,7 @@
 {
     int r,g,b;
     *ok = 1;
-    return AllocColor(w, colorName, &r, &g, &b);
+    return AllocBgColor(w, colorName, &r, &g, &b);
 }
 
 static Pixel getRangesetColor(textDisp *textD, int ind, Pixel bground)
diff -ur nedit_official/source/window.c nedit_mod/source/window.c
--- nedit_official/source/window.c	2008-03-03 23:32:24.000000000 +0100
+++ nedit_mod/source/window.c	2008-03-28 23:52:17.000000000 +0100
@@ -145,6 +145,8 @@
    0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x84, 0x01, 0xc4, 0x00, 0x64, 0x00,
    0xc4, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00};
 
+static WindowColors emptyColors = {};
+
 extern void _XmDismissTearOff(Widget, XtPointer, XtPointer);
 
 static void hideTooltip(Widget tab);
@@ -312,6 +314,7 @@
     window->macroCmdData = NULL;
     window->smartIndentData = NULL;
     window->languageMode = PLAIN_LANGUAGE_MODE;
+    window->colors = emptyColors;
     window->iSearchHistIndex = 0;
     window->iSearchStartPos = -1;
     window->replaceLastRegexCase   = TRUE;
@@ -850,8 +853,8 @@
        we try to use the 'standard' color */
     tooltipLabel = XtNameToWidget(tab, "*BubbleLabel");
     XtVaSetValues(tooltipLabel,
-    	    XmNbackground, AllocateColor(tab, GetPrefTooltipBgColor()),
-    	    XmNforeground, AllocateColor(tab, NEDIT_DEFAULT_FG),
+    	    XmNbackground, AllocateBgColor(tab, GetPrefTooltipBgColor()),
+    	    XmNforeground, AllocateFgColor(tab, NEDIT_DEFAULT_FG),
 	    NULL);
 
     /* put borders around tooltip. BubbleButton use 
@@ -1189,7 +1192,6 @@
     int i, focusPane, emTabDist, wrapMargin, lineNumCols, totalHeight=0;
     char *delimiters;
     Widget text = NULL;
-    textDisp *textD, *newTextD;
     
     /* Don't create new panes if we're already at the limit */
     if (window->nPanes >= MAX_PANES)
@@ -1231,16 +1233,7 @@
     window->textPanes[window->nPanes++] = text;
 
     /* Fix up the colors */
-    textD = ((TextWidget)window->textArea)->text.textD;
-    newTextD = ((TextWidget)text)->text.textD;
-    XtVaSetValues(text,
-                XmNforeground, textD->fgPixel,
-                XmNbackground, textD->bgPixel,
-                NULL);
-    TextDSetColors( newTextD, textD->fgPixel, textD->bgPixel, 
-            textD->selectFGPixel, textD->selectBGPixel, textD->highlightFGPixel,
-            textD->highlightBGPixel, textD->lineNumFGPixel, 
-            textD->cursorFGPixel );
+    WindowColorsToTextArea(window, text);
     
     /* Set the minimum pane height in the new pane */
     UpdateMinPaneHeights(window);
@@ -1874,53 +1867,71 @@
     UpdateMinPaneHeights(window);
 }
 
-void SetColors(WindowInfo *window, const char *textFg, const char *textBg,
-        const char *selectFg, const char *selectBg, const char *hiliteFg, 
-        const char *hiliteBg, const char *lineNoFg, const char *cursorFg)
+void RecalcColor(WindowColor *winColor, Widget w, const char *colorName,
+        int isFgColor)
+{
+    if (strcmp(winColor->name, colorName) != 0) {
+        if (strlen(colorName) >= MAX_COLOR_LEN) /* name won't fit */
+            colorName = "";
+        strcpy(winColor->name, colorName);
+    }
+    winColor->pixel = isFgColor ? AllocateFgColor(w, colorName)
+                                : AllocateBgColor(w, colorName);
+}
+
+void WindowColorsToTextArea(WindowInfo *window, Widget textArea)
 {
-    int i, dummy;
-    Pixel   textFgPix   = AllocColor( window->textArea, textFg, 
-                    &dummy, &dummy, &dummy),
-            textBgPix   = AllocColor( window->textArea, textBg, 
-                    &dummy, &dummy, &dummy),
-            selectFgPix = AllocColor( window->textArea, selectFg, 
-                    &dummy, &dummy, &dummy),
-            selectBgPix = AllocColor( window->textArea, selectBg, 
-                    &dummy, &dummy, &dummy),
-            hiliteFgPix = AllocColor( window->textArea, hiliteFg, 
-                    &dummy, &dummy, &dummy),
-            hiliteBgPix = AllocColor( window->textArea, hiliteBg, 
-                    &dummy, &dummy, &dummy),
-            lineNoFgPix = AllocColor( window->textArea, lineNoFg, 
-                    &dummy, &dummy, &dummy),
-            cursorFgPix = AllocColor( window->textArea, cursorFg, 
-                    &dummy, &dummy, &dummy);
-    textDisp *textD;
+    WindowColors *cs = &window->colors;
+    textDisp *textD = ((TextWidget)textArea)->text.textD;
+
+    XtVaSetValues(textArea, XmNforeground, cs->colorVals[TEXT_FG_COLOR].pixel,
+                            XmNbackground, cs->colorVals[TEXT_BG_COLOR].pixel,
+                            NULL);
+    TextDSetColors(textD, cs->colorVals[TEXT_FG_COLOR].pixel,
+                          cs->colorVals[TEXT_BG_COLOR].pixel,
+                          cs->colorVals[SELECT_FG_COLOR].pixel,
+                          cs->colorVals[SELECT_BG_COLOR].pixel,
+                          cs->colorVals[HILITE_FG_COLOR].pixel,
+                          cs->colorVals[HILITE_BG_COLOR].pixel,
+                          cs->colorVals[LINENO_FG_COLOR].pixel,
+                          cs->colorVals[CURSOR_FG_COLOR].pixel);
+}
+
+void WindowColorsUpdate(WindowInfo *window)
+{
+    int i;
 
     /* Update the main pane */
-    XtVaSetValues(window->textArea,
-            XmNforeground, textFgPix,
-            XmNbackground, textBgPix,
-            NULL);
-    textD = ((TextWidget)window->textArea)->text.textD;
-    TextDSetColors( textD, textFgPix, textBgPix, selectFgPix, selectBgPix, 
-            hiliteFgPix, hiliteBgPix, lineNoFgPix, cursorFgPix );
+    WindowColorsToTextArea(window, window->textArea);
     /* Update any additional panes */
-    for (i=0; i<window->nPanes; i++) {
-        XtVaSetValues(window->textPanes[i],
-                XmNforeground, textFgPix,
-                XmNbackground, textBgPix,
-                NULL);
-        textD = ((TextWidget)window->textPanes[i])->text.textD;
-        TextDSetColors( textD, textFgPix, textBgPix, selectFgPix, selectBgPix, 
-                hiliteFgPix, hiliteBgPix, lineNoFgPix, cursorFgPix );
+    for (i = 0; i < window->nPanes; i++) {
+        WindowColorsToTextArea(window, window->textPanes[i]);
     }
-    
+
     /* Redo any syntax highlighting */
     if (window->highlightData != NULL)
         UpdateHighlightStyles(window);
 }
 
+void SetColors(WindowInfo *window, const char *textFg, const char *textBg,
+        const char *selectFg, const char *selectBg, const char *hiliteFg,
+        const char *hiliteBg, const char *lineNoFg, const char *cursorFg)
+{
+    WindowColors *cs = &window->colors;
+    Widget w = window->textArea;
+
+    RecalcColor(&cs->colorVals[TEXT_FG_COLOR],       w, textFg,   True),
+    RecalcColor(&cs->colorVals[TEXT_BG_COLOR],       w, textBg,   False),
+    RecalcColor(&cs->colorVals[SELECT_FG_COLOR],     w, selectFg, True),
+    RecalcColor(&cs->colorVals[SELECT_BG_COLOR],     w, selectBg, False),
+    RecalcColor(&cs->colorVals[HILITE_FG_COLOR],     w, hiliteFg, True),
+    RecalcColor(&cs->colorVals[HILITE_BG_COLOR],     w, hiliteBg, False),
+    RecalcColor(&cs->colorVals[LINENO_FG_COLOR],     w, lineNoFg, True),
+    RecalcColor(&cs->colorVals[CURSOR_FG_COLOR],     w, cursorFg, True),
+
+    WindowColorsUpdate(window);
+}
+
 /*
 ** Set insert/overstrike mode
 */
@@ -4135,7 +4146,6 @@
     char *delimiters;
     Widget text;
     selection sel;
-    textDisp *textD, *newTextD;
     
     /* transfer the primary selection */
     memcpy(&sel, &orgWin->buffer->primary, sizeof(selection));
@@ -4175,7 +4185,6 @@
     
     
     /* clone split panes, if any */
-    textD = ((TextWidget)window->textArea)->text.textD;
     if (window->nPanes) {
 	/* Unmanage & remanage the panedWindow so it recalculates pane 
            heights */
@@ -4195,13 +4204,7 @@
 	    window->textPanes[i] = text;
 
             /* Fix up the colors */
-            newTextD = ((TextWidget)text)->text.textD;
-            XtVaSetValues(text, XmNforeground, textD->fgPixel,
-                    XmNbackground, textD->bgPixel, NULL);
-            TextDSetColors(newTextD, textD->fgPixel, textD->bgPixel, 
-                    textD->selectFGPixel, textD->selectBGPixel,
-                    textD->highlightFGPixel,textD->highlightBGPixel,
-                    textD->lineNumFGPixel, textD->cursorFGPixel);
+            WindowColorsToTextArea(window, text);
 	}
         
 	/* Set the minimum pane height in the new pane */
@@ -4282,6 +4285,7 @@
     params[3] = orgWin->boldItalicFontName;
     XtCallActionProc(window->textArea, "set_fonts", NULL, params, 4);
 
+    window->colors = orgWin->colors;
     SetBacklightChars(window, orgWin->backlightCharTypes);
     
     /* Clone rangeset info.
@@ -4418,7 +4422,9 @@
     
     /* Create a new window */
     cloneWin = CreateWindow(window->filename, NULL, False);
-    
+
+    cloneWin->colors = window->colors;
+
     /* CreateWindow() simply adds the new window's pointer to the
        head of WindowList. We need to adjust the detached window's 
        pointer, so that macro functions such as focus_window("last")
@@ -4432,6 +4438,7 @@
     /* these settings should follow the detached document.
        must be done before cloning window, else the height 
        of split panes may not come out correctly */
+    cloneWin->colors = window->colors;
     ShowISearchLine(cloneWin, window->showISearchLine);
     ShowStatsLine(cloneWin, window->showStats);
 
diff -ur nedit_official/source/window.h nedit_mod/source/window.h
--- nedit_official/source/window.h	2008-01-04 23:11:05.000000000 +0100
+++ nedit_mod/source/window.h	2008-03-28 23:11:54.000000000 +0100
@@ -51,6 +51,10 @@
 void SetShowMatching(WindowInfo *window, int state);
 void SetFonts(WindowInfo *window, const char *fontName, const char *italicName,
 	const char *boldName, const char *boldItalicName);
+void RecalcColor(WindowColor *winColor, Widget w, const char *colorName,
+        int isFgColor);
+void WindowColorsToTextArea(WindowInfo *window, Widget textArea);
+void WindowColorsUpdate(WindowInfo *window);
 void SetColors(WindowInfo *window, const char *textFg, const char *textBg,  
         const char *selectFg, const char *selectBg, const char *hiliteFg, 
         const char *hiliteBg, const char *lineNoFg, const char *cursorFg);
