home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
x
/
xtici.zip
/
xtici
/
resources.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-28
|
38KB
|
1,346 lines
/*
* Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
* All Rights Reserved
*
* This file is a component of an X Window System client which uses the Xcms
* Color Management System. TekColor is a trademark of Tektronix, Inc. The
* TekColor Editor is the subject of U.S. and foreign patents pending. The
* term "TekHVC" designates a particular color space that is the subject of
* U.S. Patent No. 4,985,853 (equivalent foreign patents pending).
* Permission is hereby granted to use, copy, modify, sell, and otherwise
* distribute this software and its documentation for the X Window System
* environment, for any purpose and without fee, provided that:
*
* 1. The code and documentation are only used to implement a
* TekColor Editor in an X Window System environment; and
* 2. This copyright and permission notice is reproduced in all copies
* of the code and in supporting documentation.
*
* Permission is granted to modify this code as required to allow it to
* be compiled on any host computer, provided that the functionality of
* the TekColor Editor is not modified in any way. A description of any
* modifications must be sent to Tektronix, Inc. Contact
* Tektronix Inc., P.O. Box 1000, Mail Station 60-850,
* Network Displays Division Engineering, Wilsonville, OR 97070.
*
* Tektronix makes no representation about the suitability of this software
* for any purpose. It is provided "as is" and with all faults.
*
* TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
* INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX 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 THE PERFORMANCE OF THIS SOFTWARE.
*
* NAME
* resources - manage objects manipulated by the interface
*
* DESCRIPTION
* This is the lowest level of the interface, actually modifying
* objects. Some of these objects are located on the server,
* some located in this file.
* In addition, some X objects used by the interface are
* created here, even though they are not strictly manipulated
* by the interface. Some objects and the routines to control
* them have been partitioned into other files because of this
* file size - for example, selection.c and package.c
*/
#ifndef LINT
static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
#ifdef RCS_ID
static char *rcsid= "$Header: resources.c,v 1.3 91/08/28 10:03:20 adamsc Exp $";
#endif /* RCS_ID */
#endif /* LINT */
/*
* EXTERNAL INCLUDES
*/
/*
* INTERNAL INCLUDES
*/
#include <stdio.h>
#include "xtici.h"
#include <X11/cursorfont.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include "cursors.h"
#include "icon.h"
/*
* EXTERNS
*/
extern Bool restoreFill;
extern Status XcmsTekHVCClipC();
extern Status XcmsTekHVCClipV();
extern Status XcmsTekHVCClipVC();
/*
* GLOBALS
*/
#ifdef DEC
# define GLOBAL global
#else
# define GLOBAL
#endif
GLOBAL Display *dpy;
GLOBAL XcmsCCC pDefaultCCC;
GLOBAL XVisualInfo visInfo;
GLOBAL Colormap cmap;
/*
* This is the value of the current color;
* Could be a pointer into the currentMap.
*/
GLOBAL XcmsColor currentHvc;
/*
* This is the value of the current color in RGB,
* however, it is only updated when needed - not always current.
*/
GLOBAL XColor currentRgb = {0, 0, 0, 0, DoRed | DoGreen | DoBlue};
/*
* This is the value of the current color in u'v'Y,
* however, it is only updated when needed - not always current.
*/
GLOBAL XcmsCIEuvY currentUvy = {0.0, 0.0, 0.0};
/*
* This structure mimics the colormap stored in the server.
* We need this because some colors are not reachable by the server,
* so they cannot be stored there.
* This could be an array of hvc's, but using XcmsColors allows changes
* to be made more quickly. The drawback is the increased size, of course.
*/
GLOBAL XcmsColor *currentMap = (XcmsColor *)NULL;
/*
* This is used to cache checkpointed values.
*/
GLOBAL XcmsColor *cpmap = (XcmsColor *)NULL;
GLOBAL Cursor normalCursor, hvcCursor, waitCursor, grabCursor;
GLOBAL int *edited = NULL;
GLOBAL int GamutComp = GamutCompChroma;
/*
* This variable is used to control which interface fill options are available.
* It is first set by the available size of the colormap; filling is not
* allowed if it uses more than 2/3 of the map.
* It is further restricted if any interface color falls in the block
* of cells reserved for filling the object.
*/
GLOBAL int allowFill = FillAny;
/*
* LOCAL DEFINES
*/
#define MaxIfColors 12
/*
* Steal the top part of the colormap for the huebar.
*/
#define HuebarColors 72
/*
* Steal the next part of the map to fill the leaf.
*/
#define LeafColors 56
/*
* LOCAL TYPEDEFS
*/
/*
* LOCALS VARIABLES
*/
#ifdef DEBUG
# define STATIC
#else
# define STATIC static
#endif /* DEBUG */
/*
* This array is used to check if XcmsStoreColors clamped a chroma.
* The number of colors stored at one time depends on colormap size,
* so it must be dynamically allocated.
*/
STATIC unsigned char *clampCheck;
/*
* This could be dynamically sized, but it isn't worth it.
* If the interface needs more than this many colors,
* we are probably in trouble anyway.
*/
STATIC Pixel ifColors[MaxIfColors];
STATIC int ifColorCt = 0;
/* TODO: Does the local client need this ??? */
STATIC Colormap tmpMap;
STATIC Pixel huebarBase = 0;
/*
* Use HVC because that is the natural computational system
* Cache precomputed MaxChromaValues for the constant hues.
* Compute this on the fly for the local client
*/
STATIC XcmsColor constantHuebar[HuebarColors];
/* This is the base to use when empty - it is the widget background */
STATIC Pixel huebarBackground = ~(Pixel)0;
/* Values are always computed in the leaf widget. */
STATIC Pixel leafBase = 0;
/*
* LOCAL FUNCTION DECLARATIONS
*/
STATIC int IfColorChanged();
#ifdef XDEBUG
STATIC char *routine_name;
STATIC char *CONSTRAIN_COLOR = "ConstrainColor";
STATIC char *COPY_ARRAY = "CopyArray";
STATIC char *COPY_COLORMAP = "CopyColormap";
STATIC char *EDIT_UVY_CELLS = "EditUvyCells";
STATIC char *GET_COLORS = "GetColors";
STATIC char *UNCACHE_CELL = "UncacheCell";
#endif
/*
* Store the given cell in the backup map. If the index is -1,
* store the entire map.
*/
void CacheCell(index)
int index;
{
if (index < 0)
bcopy(currentMap, cpmap, mapSize * sizeof(XcmsColor));
else
bcopy(¤tMap[index], &cpmap[index], sizeof(XcmsColor));
}
/*
* Force a change in the colormap.
* Apply constraints as proper.
*/
/* ARGSUSED */
void ChangeHvcCells(hvcs, len, method)
XcmsColor *hvcs;
int len;
unsigned char method;
{
int i;
for (i = 0; i < len; i++) {
bcopy((char *)&hvcs[i],(char *)¤tMap[hvcs[i].pixel],sizeof(XcmsColor));
ConstrainColor(hvcs[i].pixel);
bcopy((char *)¤tMap[hvcs[i].pixel], (char *)&hvcs[i], sizeof(XcmsColor));
}
}
/*
* Clear all of the edited index marks
*/
void ClearMapEdited(limit)
int limit;
{
int i;
int easy = limit / 32;
int rest = limit % 32;
int mask;
for (i = 0; i < easy; i++)
edited[i] = 0;
if (rest) {
mask = (1 << (rest+1)) - 1;
edited[easy] &= ~mask;
}
}
/*****************************************************************************
*
* This gets the default CCC of the display.
* This checks for a PseudoColor visual for that display.
*
* If all this is ok then pick the largest colormap possible.
* Set up resources based on visuals and the map size of visual in use.
*
*****************************************************************************/
void ValidateDisplay()
{
long mask;
XVisualInfo *list, *visList;
XVisualInfo template;
int i, ct;
int visCt;
int maxMapSize = 0;
extern void ClearMapEdited();
/* determine if the display supports the extension */
if ((pDefaultCCC = XcmsDefaultCCC(dpy, DefaultScreen(dpy))) == NULL) {
Error("Failed to find the Default XcmsCCC.\n\
Check to make sure the extension property is loaded on the root window.");
}
switch(GamutComp) {
case GamutCompValue:
XcmsSetCompressionProc(pDefaultCCC, XcmsTekHVCClipV, NULL);
break;
case GamutCompClosest:
XcmsSetCompressionProc(pDefaultCCC, XcmsTekHVCClipVC, NULL);
break;
case GamutCompChroma:
default:
XcmsSetCompressionProc(pDefaultCCC, XcmsTekHVCClipC, NULL);
break;
}
/* find the interesting visuals */
/* only use PseudoColor visuals */
template.class = reqVisual;
mask = VisualClassMask;
list = XGetVisualInfo(dpy, mask, &template, &ct);
visList = (XVisualInfo *)XtCalloc(ct, sizeof(XVisualInfo));
visCt = 0;
for (i = 0; i < ct; i++) {
/* just in case */
if (list[i].class != reqVisual)
continue;
/* use the largest possible visual */
if (1 << list[i].depth > maxMapSize) {
maxMapSize = 1 << list[i].depth;
visInfo = list[i];
}
visList[visCt++] = list[i];
}
/* Error will exit, so don't bother to free list */
if (visCt == 0) {
Error("No PseudoColor visual on this screen");
}
mapSize = maxMapSize;
edited = (int *)XtCalloc((maxMapSize + 31)/32, sizeof(int));
clampCheck = (unsigned char *)XtCalloc(maxMapSize, sizeof(unsigned char));
ClearMapEdited(maxMapSize);
huebarBase = maxMapSize - HuebarColors;
leafBase = huebarBase - LeafColors;
/* don't allow this option if filling leaves less than 1/3 of map */
if (leafBase < maxMapSize / 3)
allowFill = FillHuebar;
if (huebarBase < maxMapSize / 3)
allowFill = FillNone;
XFree((char *)list);
}
/*
* Apply the current clamping constraint(s) to the passed cells
* in the cached colormap (currentMap). The backup map is not modified.
* If the backup (cpmap) is restored, constraints are applied at that time.
*/
void ConstrainColor(index)
Pixel index;
{
XcmsColor tmp;
bcopy((char *)¤tMap[index], (char *)&tmp, sizeof(XcmsColor));
#ifdef XDEBUG
routine_name = CONSTRAIN_COLOR;
#endif
StoreAllocColors(dpy, cmap, &tmp, 1, XcmsTekHVCFormat);
if (clampState & ClampMonitor) {
/* which should be applied only if clamping to monitor */
switch (GamutComp) {
case GamutCompValue:
currentMap[index].spec.TekHVC.V = tmp.spec.TekHVC.V;
break;
case GamutCompClosest:
currentMap[index].spec.TekHVC.V = tmp.spec.TekHVC.V;
case GamutCompChroma:
default:
currentMap[index].spec.TekHVC.C = tmp.spec.TekHVC.C;
}
}
}
/*
* Adjust the passed value to fall in the legal range determined by
* the current colormap size.
*/
Pixel ConstrainIndex(index)
Pixel index;
{
/* Pixel is unsigned, so index cannot be negative */
if (index >= mapSize)
return((Pixel)(mapSize - 1));
else
return(index);
}
/*
* Copy the target XcmsColor array into our editable map.
* If protect is set, allow user to restore interface colors.
*/
STATIC char *protectIfHelp = "\
The new colormap has different values in at least one cell that the editor\n\
is using. If you continue, any image will be displayed correctly, but the\n\
editor may not be usable. If you cancel, editor interface colors will remain\n\
unchanged, but the image may not be displayed correctly.\n\
\n\
In either case, colors not used by the interface will be changed to reflect\n\
the colors in the new colormap.";
/* for now, is not used by the local client; used to load a colormap */
/* void CopyArray(old, size, protect)
* XcmsColor *old;
* int size;
* Boolean protect;
* {
* int i;
* int limit;
* Boolean restore = False;
* XcmsColor ifCols[MaxIfColors];
* int ifColsCt = ifColorCt;
*
* /* if we need to protect interface colors, cache them first */
/* if (protect) {
* for (i = 0; i < ifColsCt; i++)
* bcopy((char *)¤tMap[ifColors[i]], (char *)&ifCols[i], sizeof(XcmsColor));
* }
*
* /* often we are copying from existing arrays; avoid that */
/* if (old != cpmap)
* bcopy(old, cpmap, size * sizeof(XcmsColor));
* /* set properly to do stores; reset later to avoid adjustments */
/* if (old != currentMap)
* bcopy(old, currentMap, size * sizeof(XcmsColor));
*
* /* if huebar is filled, don't modify those cells */
/* if ( (leafState & LeafFilled) && (size >= leafBase) )
* limit = leafBase;
* else if ( (huebarState != HuebarEmpty) && (size >= huebarBase) )
* limit = huebarBase;
* else
* limit = size;
* #ifdef XDEBUG
* routine_name = COPY_ARRAY;
* #endif
* StoreAllocColors(dpy, cmap, currentMap, limit, XcmsTekHVCFormat);
*
* if ( (leafState & LeafFilled) && (huebarState == HuebarEmpty)
* && (size >= huebarBase) ) {
* #ifdef XDEBUG
* routine_name = COPY_ARRAY;
* #endif
* (void) StoreAllocColors(dpy, cmap, currentMap+huebarBase, size - huebarBase, XcmsTekHVCFormat);
* }
*
* /* If needed, restore the interface colors */
/* if (protect) {
* if (IfColorChanged(cpmap, ifCols, ifColsCt))
* restore = (Warning("Modify interface color cell?", protectIfHelp)
* != MessageContinue);
* }
* if (restore) {
* for (i = 0; i < ifColsCt; i++)
* cpmap[ifCols[i].pixel] = ifCols[i];
* #ifdef XDEBUG
* routine_name = COPY_ARRAY;
* #endif
* (void) StoreAllocColors(dpy, cmap, ifCols, ifColsCt, XcmsTekHVCFormat);
* }
*
* bcopy(cpmap, currentMap, size * sizeof(XcmsColor));
* }
*/
/*
* Copy the target map into our editable map.
* If protect is set, allow user to restore interface colors.
*/
void CopyColormap(old, from, to, protect)
Colormap old;
Pixel from, to;
Boolean protect;
{
int i;
Pixel limit, size = to - from + 1;
Boolean restore = False;
XcmsColor ifCols[MaxIfColors];
/* ifColorCt may change, so save value that matches remembered array */
int ifColsCt = ifColorCt;
/* if we need to protect interface colors, cache them first */
if (protect) {
for (i = 0; i < ifColsCt; i++)
bcopy((char *)¤tMap[ifColors[i]], (char *)&ifCols[i], sizeof(XcmsColor));
}
if (XcmsQueryColors(dpy, old, cpmap+from, size, XcmsTekHVCFormat)
== XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed in CopyColormap\n");
#endif
}
/* set the current map properly to store colors; */
/* reset later to avoid unwanted coordinate adjustments */
bcopy(cpmap+from, currentMap+from, size * sizeof(XcmsColor));
/* if huebar filled, don't modify those cells */
if ( (leafState & LeafFilled) && (size >= leafBase) )
limit = leafBase - from;
else if ( (huebarState != HuebarEmpty) && (size >= huebarBase) )
limit = huebarBase - from;
else
limit = size;
#ifdef XDEBUG
routine_name = COPY_COLORMAP;
#endif
(void) StoreAllocColors(dpy, cmap, currentMap+from, (int)limit,
XcmsTekHVCFormat);
/* if necessary, do piece beyond leaf hues */
if ( (leafState & LeafFilled) && (huebarState == HuebarEmpty)
&& (to >= huebarBase) ) {
#ifdef XDEBUG
routine_name = COPY_COLORMAP;
#endif
StoreAllocColors(dpy, cmap, currentMap+huebarBase,
(int)(to - huebarBase + 1), XcmsTekHVCFormat);
}
/* If needed, restore the interface colors */
if (protect) {
if (IfColorChanged(cpmap, ifCols, ifColsCt))
restore = (Warning("Modify interface color cell?", protectIfHelp)
!= MessageContinue);
}
if (restore) {
for (i = 0; i < ifColsCt; i++)
cpmap[ifCols[i].pixel] = ifCols[i];
#ifdef XDEBUG
routine_name = COPY_COLORMAP;
#endif
StoreAllocColors(dpy, cmap, ifCols, ifColsCt, XcmsTekHVCFormat);
}
bcopy(cpmap, currentMap, size * sizeof(XcmsColor));
}
/*
* Create a colormap to use for editing from the interface visual.
* Allocate all colors in the map. Copy the colors of the default
* colormap into it for starters.
*/
void CreateColormap()
{
Pixel i, cmap_size;
XcmsColor tmpColor;
/* The window identifies the screen, not visual or depth */
cmap = XCreateColormap(dpy, RootWindow(dpy, visInfo.screen),
visInfo.visual, AllocAll);
XcmsSetCompressionProc(XcmsCCCOfColormap(dpy, cmap),
pDefaultCCC->gamutCompProc, NULL);
tmpMap = XCreateColormap(dpy, RootWindow(dpy, visInfo.screen),
visInfo.visual, AllocAll);
XcmsSetCompressionProc(XcmsCCCOfColormap(dpy, tmpMap),
pDefaultCCC->gamutCompProc, NULL);
cmap_size = 1 << visInfo.depth;
currentMap = (XcmsColor *)XtCalloc(cmap_size, sizeof(XcmsColor));
cpmap = (XcmsColor *)XtCalloc(cmap_size, sizeof(XcmsColor));
tmpColor.format = XcmsTekHVCFormat;
tmpColor.spec.TekHVC.H=tmpColor.spec.TekHVC.V=tmpColor.spec.TekHVC.C=0.0;
for (i = 0; i < cmap_size; i++) {
tmpColor.pixel = i;
bcopy((char *)&tmpColor, (char *)&cpmap[i], sizeof(XcmsColor));
bcopy((char *)&tmpColor, (char *)¤tMap[i], sizeof(XcmsColor));
}
/* copy colormap entries */
CopyColormap(DefaultColormap(dpy, visInfo.screen), (Pixel)0,
(Pixel)(cmap_size - 1), (Boolean) False);
/* Get the current HVC value for the first time */
/* arbitrarily use the WhitePixel to start */
currentHvc.format = XcmsTekHVCFormat;
currentHvc.pixel = WhitePixel(dpy, visInfo.screen);
if (XcmsQueryColor(dpy, DefaultColormap(dpy, visInfo.screen), ¤tHvc,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColor failed in CreateColormap\n");
#endif
}
}
/*
* Force a change in the colormap, with all of its side effects.
* Side effects include marking the cell as edited,
* and trying to assume selection ownership (if not already owned).
* Apply constraints as proper.
*
* Return NO_ADJUST iff the entire range was ok.
*/
void EditHvcCells(pHVCs, len, method, mark)
XcmsColor *pHVCs;
int len;
unsigned char method;
Boolean mark;
{
int i;
for (i = 0; i < len; i++) {
if (mark)
MarkIndexEdited(pHVCs[i].pixel);
ChangeHvcCells(pHVCs+i, 1, method);
}
/*
* It takes 2-3 times as long to modify the map one cell at a time,
* but StoreColors has a bug in that it does not modify the passed value.
* In addition, the update can take a long time, particularly on the
* 20 and 30 servers. Even though it takes a while, at least the user
* can see something happening.
*
* Definitely want to consider changing calling sequences to
* improve performance.
*
* if (!selectionMine)
* TakeSelection();
*/
for (i = 0; i < len; i++) {
if (clampCheck[i] != NO_ADJUST)
return;
}
}
/*
* This routine combines EditHvcCells and ChangeHvcCells for a change
* in RGB. This is because we never want to change a RGB color except
* when editing. If this ever changes, extract it.
*
* May want to modify this algorithm to be more efficient.
*/
void EditRgbCells(rgbs, len)
XColor *rgbs;
int len;
{
int i;
Pixel start = mapSize, stop = 0;
XStoreColors(dpy, cmap, rgbs, len);
for (i = 0; i < len; i++) {
MarkIndexEdited(rgbs[i].pixel);
if (rgbs[i].pixel < start)
start = rgbs[i].pixel;
if (rgbs[i].pixel > stop)
stop = rgbs[i].pixel;
}
/* update the internal copy */
/* but only need to if XStoreColors was used */
/* could query the entire map, but I think this is more efficient */
if (XcmsQueryColors(dpy, cmap, currentMap+start, stop - start + 1,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed in EditRGB Cells\n");
#endif
}
for (i = 0; i < len; i++)
ConstrainColor(rgbs[i].pixel);
/* if (!selectionMine)
* TakeSelection();
*/
}
/*
* This routine is identical to EditRgbCells, except it deals with
* coordinates specified in u'v'Y space.
* Since the local client does not support this space,
* only defined for the host based client.
*/
void EditUvyCells(uvys, len)
XcmsColor *uvys;
int len;
{
int i;
Pixel start = mapSize, stop = 0;
#ifdef XDEBUG
routine_name = EDIT_UVY_CELLS;
#endif
StoreAllocColors(dpy, cmap, uvys, len, XcmsCIEuvYFormat);
for (i = 0; i < len; i++) {
MarkIndexEdited(uvys[i].pixel);
if (uvys[i].pixel < start)
start = uvys[i].pixel;
if (uvys[i].pixel > stop)
stop = uvys[i].pixel;
}
/* update the internal copy */
/* could query the entire map, but I think this is more efficient */
if (XcmsQueryColors(dpy, cmap, currentMap+start, stop - start + 1,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed in EdituvYCells\n");
#endif
}
for (i = 0; i < len; i++)
ConstrainColor(uvys[i].pixel);
/* if (!selectionMine)
* TakeSelection();
*/
}
STATIC Cursor MakeCursor();
void CreateCursors()
{
unsigned int bestWidth, bestHeight;
/* normal cursor is always boring upper left arrow */
normalCursor = XCreateFontCursor(dpy, XC_left_ptr);
XQueryBestSize(dpy, CursorShape, RootWindow(dpy, visInfo.screen),
(unsigned int)hvc_cursor_width, (unsigned int)hvc_cursor_height,
&bestWidth, &bestHeight);
/* If best size is less than what we asked for, use font cursors */
if ( (bestWidth < hvc_cursor_width) || (bestHeight < hvc_cursor_height) ) {
hvcCursor = normalCursor;
waitCursor = XCreateFontCursor(dpy, XC_watch);
grabCursor = XCreateFontCursor(dpy, XC_crosshair);
/* otherwise use our larger cursors */
} else {
hvcCursor = MakeCursor(hvc_cursor_bits, hvc_mask_cursor_bits,
hvc_mask_cursor_width, hvc_mask_cursor_height,
hvc_cursor_x_hot, hvc_cursor_y_hot);
waitCursor = MakeCursor(wait_cursor_bits, wait_mask_cursor_bits,
wait_mask_cursor_width, wait_mask_cursor_height,
wait_cursor_x_hot, wait_cursor_y_hot);
grabCursor = MakeCursor(pick_cursor_bits, pick_mask_cursor_bits,
pick_mask_cursor_width, pick_mask_cursor_height,
pick_cursor_x_hot, pick_cursor_y_hot);
}
}
/*
* Return non-zero if any cell in the map has been edited
*/
int EditedMap(limit)
int limit;
{
int i;
int easy = limit / 32;
int rest = limit % 32;
int mask;
for (i = 0; i < easy; i++) {
if (edited[i])
return(1);
}
if (rest) {
mask = (1 << (rest+1)) - 1;
return(mask & edited[easy]);
} else
return(0);
}
/*
* Return up to size colors from the current map, beginning at start.
* Return the colors in the format requested HVC.
* The effective top limit is mapSize.
*/
/* int GetColors(colors, start, size)
* XtPointer *colors;
* int start, size;
* {
* XcmsColor *pHVCs = (XcmsColor *)colors;
* int chunk;
*
* /* only copy to the limit of current mapSize */
/* if (start >= mapSize)
* return(0);
*
* chunk = mapSize - start;
* if (chunk > size)
* chunk = size;
*
* /* if (format == FileHVC) */
/* bcopy(currentMap, pHVCs, chunk * sizeof(XcmsColor));
*
* return(chunk);
* }
*/
/*
* If any of the displayed pixel values are stolen by the hue bar,
* tell the user to back off of a cell available for editing.
* TODO: either prevent this from happening, or provide a way to continue.
*/
/* TODO: this is lousy help; how do you free? what is the high end? */
STATIC char *huebarCellInUse = "\
This option `steals' a number of color cells from the top end of the colormap.\n\
At least one of these cells has already been chosen to be edited. Since \n\
the cell cannot be used for both purposes, the option cannot be implemented.\n\
\n\
To enable the option, free the cells in the high end of the colormap from\n\
editing.";
int HuebarRangeBusy()
{
Pixel *colors;
int ct;
int i;
colors = EditingIndexes(&ct);
for (i = 0; i < ct; i++) {
if (colors[i] >= huebarBase) {
InformMsg("Color cell in use. Change cell to enable option.",
huebarCellInUse);
return(1);
}
}
return(0);
}
/*
* Load a pre-computed range of max ValueChromas for different hues
* into the back end of the colormap. Then tell the huebar widget to use
* them.
*/
void HuebarRangeLoad(base, len)
Pixel *base;
int *len;
{
int i;
XcmsFloat HRL_step;
XcmsFloat HRL_hue;
/* set up the range the first time we are called and cache it */
if (constantHuebar[1].pixel != huebarBase + 1) {
HRL_step = 360.0 / (XcmsFloat)HuebarColors;
HRL_hue = HRL_step / 2.0;
for (i = 0; i < HuebarColors; i++, HRL_hue += HRL_step) {
constantHuebar[i].pixel = huebarBase + i;
constantHuebar[i].format = XcmsTekHVCFormat;
constantHuebar[i].spec.TekHVC.H = HRL_hue;
if (!XcmsTekHVCQueryMaxVC(pDefaultCCC, HRL_hue, &constantHuebar[i])) {
return;
}
constantHuebar[i].pixel = huebarBase + i;
if (constantHuebar[i].format != XcmsTekHVCFormat) {
if ((XcmsConvertColors (pDefaultCCC, &constantHuebar[i], 1,
XcmsTekHVCFormat, NULL) == XcmsFailure)&&
constantHuebar[i].format != XcmsTekHVCFormat) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsConvertColors failed in HuebarRangeLoad\n");
#endif
}
constantHuebar[i].pixel = huebarBase + i;
}
}
}
if (XcmsStoreColors(dpy, cmap, constantHuebar,
HuebarColors, NULL) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsStoreColors failed HuebarRangeLoad \n");
#endif
}
if (XcmsQueryColors(dpy, cmap, constantHuebar, HuebarColors,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed HuebarRangeLoad\n");
#endif
}
*base = huebarBase;
*len = HuebarColors;
}
/*
* Restore real colormap values, previously saved with HuebarRangeSave.
* Set the huebar widget to use only the single background color.
*/
void HuebarRangeRestore(base, len)
Pixel *base;
int *len;
{
if (XcmsStoreColors(dpy, cmap, currentMap+huebarBase,
HuebarColors, NULL) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsStoreColors failed HuebarRangeRestore\n");
#endif
}
if (XcmsQueryColors(dpy, cmap, currentMap+huebarBase,
HuebarColors, XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed HuebarRangeRestore\n");
#endif
}
*base = huebarBackground;
*len = 1;
}
/*
* Save the real colormap values of those cells stolen for the hue bar
* This routine is no longer needs to save cells since they are in the
* currentColormap, but it does set huebarBackground.
*/
void HuebarRangeSave()
{
Arg arg;
/* This needs only to be set once, since background doesn't change */
if ((int)huebarBackground >= 0)
return;
XtSetArg(arg, XtNbackground, &huebarBackground);
/*
* this routine can be called by routine creating hue,
* so use interface parent widget instead.
*/
XtGetValues(primary, &arg, 1);
}
/*
* Load a range of colors at different hues with current value and chroma
* into the back end of the colormap.
*/
void HuebarRangeUpdate(base, len)
Pixel *base;
int *len;
{
int i;
XcmsFloat HRU_step = 360.0 / (XcmsFloat)HuebarColors;
XcmsColor range[HuebarColors];
XcmsColor target;
/* set up the range */
target.spec.TekHVC.H = HRU_step / 2.0;
target.spec.TekHVC.V = currentHvc.spec.TekHVC.V;
target.spec.TekHVC.C = currentHvc.spec.TekHVC.C;
for (i = 0; i < HuebarColors; i++) {
range[i].pixel = huebarBase + i;
range[i].format = XcmsTekHVCFormat;
range[i].spec.TekHVC.H = target.spec.TekHVC.H;
range[i].spec.TekHVC.V = target.spec.TekHVC.V;
range[i].spec.TekHVC.C = target.spec.TekHVC.C;
target.spec.TekHVC.H += HRU_step;
}
if (XcmsStoreColors(dpy, cmap, range,
HuebarColors, NULL) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsStoreColors failed HuebarRangeUpdate\n");
#endif
}
if (XcmsQueryColors(dpy, cmap, range, HuebarColors,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColor failed HuebarRangeUpdate\n");
#endif
}
*base = huebarBase;
*len = HuebarColors;
}
/*
* Return non-zero iff the pixel of the passed color struct is in use in the
* interface and its color differs from the current colors.
* This routine assumes that the array of current colors contains a color
* structure for each pixel in the ifColors array.
*/
STATIC int IfColorChanged(col, ifCols, ifColsCt)
XcmsColor *col, *ifCols;
int ifColsCt;
{
int i;
Pixel index;
for (i = 0; i < ifColsCt; i++) {
index = ifCols[i].pixel;
/* TODO: need epsilon check instead of strict equality ?? */
if (col[index].spec.TekHVC.H != ifCols[i].spec.TekHVC.H)
return(1);
if (col[index].spec.TekHVC.V != ifCols[i].spec.TekHVC.V)
return(1);
if (col[index].spec.TekHVC.C != ifCols[i].spec.TekHVC.C)
return(1);
}
return(0);
}
/* a convenience macro used by Is*Range functions */
#define PixInRange(p,l,h) (( (p) >= (l) ) && ( (p) <= (h) ))
/*
* Return true if black or white pixel are in the passed range
*/
/* Boolean IsBWRange(lo, hi)
* Pixel lo, hi;
* {
* return (PixInRange(WhitePixel(dpy,visInfo.screen), lo, hi)
* || PixInRange(BlackPixel(dpy,visInfo.screen), lo, hi) );
* }
*/
/*
* Return true if the passed pixel is used in the hue bar.
*/
Boolean IsHuebarIndex(pix)
Pixel pix;
{
return(huebarState != HuebarEmpty && pix >= huebarBase);
}
/*
* Return true if the passed pixel is used in the interface
*/
Boolean IsIfIndex(pix)
Pixel pix;
{
int i;
for (i = 0; i < ifColorCt; i++) {
if (ifColors[i] == pix)
return(True);
}
return(False);
}
/*
* Return true if the an interface pixel is in the passed range
*/
/* Boolean IsIfRange(lo, hi)
* Pixel lo, hi;
* {
* int i;
* for (i = 0; i < ifColorCt; i++) {
* if (PixInRange(ifColors[i], lo, hi))
* return(True);
* }
*
* return(False);
* }
*/
/*
* Return true if the passed pixel is used to fill the leaf.
*/
Boolean IsLeafIndex(pix)
Pixel pix;
{
return((leafState & LeafFilled) && (pix >= leafBase) && (pix < huebarBase));
}
/*
* If any of the displayed pixel values are stolen by the leaf,
* tell the user to back off of a cell available for editing.
* TODO: either prevent this from happening, or provide a way to continue.
*/
/* TODO: this is lousy help; how do you free? what is the high end? */
STATIC char *leafCellInUse = "\
This option `steals' a number of color cells from the colormap.\n\
At least one of these cells has already been chosen to be edited. Since \n\
the cell cannot be used for both purposes, the option cannot be implemented.\n\
\n\
To enable the option, free the cells in the middle of the colormap from\n\
editing.";
int LeafRangeBusy()
{
Pixel *colors;
int ct;
int i;
colors = EditingIndexes(&ct);
for (i = 0; i < ct; i++) {
if ( (colors[i] >= leafBase) && (colors[i] - leafBase < LeafColors) ) {
InformMsg("Color cell in use. Change cell to enable option.",
leafCellInUse);
return(1);
}
}
return(0);
}
/*
* Restore real colormap values, previously saved with LeafRangeSave.
* Set the leaf widget to not fill (-1)
*/
void LeafRangeRestore(base)
Pixel *base;
{
if (XcmsStoreColors(dpy, cmap, currentMap+leafBase,
LeafColors, NULL) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsStoreColors failed LeafRangeRestore\n");
#endif
}
if (XcmsQueryColors(dpy, cmap, currentMap+leafBase, LeafColors,
XcmsTekHVCFormat) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed LeafRangeRestore\n");
#endif
}
*base = (Pixel)-1;
}
/*
* Save the real colormap values of those cells stolen for leaf.
* Return the base of the colors saved (widget can then use those colors).
* This routine is no longer needed since cells are already stored
* in currentColormap.
*/
void LeafRangeSave(base)
Pixel *base;
{
*base = leafBase;
}
STATIC Cursor MakeCursor(image, mask, wt, ht, x, y)
unsigned char *image, *mask;
unsigned int wt, ht;
int x, y;
{
Cursor crsr;
Pixmap img, msk;
XColor white, black;
/* set the colors */
white.flags = black.flags = DoRed | DoGreen | DoBlue;
white.pixel = WhitePixel(dpy, visInfo.screen);
black.pixel = BlackPixel(dpy, visInfo.screen);
XQueryColor(dpy, DefaultColormap(dpy, visInfo.screen), &white);
XQueryColor(dpy, DefaultColormap(dpy, visInfo.screen), &black);
/* build images from data */
img = XCreateBitmapFromData(dpy, RootWindow(dpy, visInfo.screen),
(char *)image, wt, ht);
msk = XCreateBitmapFromData(dpy, RootWindow(dpy, visInfo.screen),
(char *)mask, wt, ht);
/* make cursor from images */
crsr = XCreatePixmapCursor(dpy, img, msk, &white, &black, x, y);
/* free the images */
XFreePixmap(dpy, img);
XFreePixmap(dpy, msk);
return(crsr);
}
/*
* If the passed shell widget does not have an icon bitmap set,
* create one and set it.
*/
Pixmap MakeIcon()
{
/*
* Could get icon sizes, build a pixmap and render into it.
* However, 32x32 seems to be a likely candidate (if the wm
* supports this at all). And this is easier.
*/
return(XCreateBitmapFromData(dpy, RootWindow(dpy, visInfo.screen),
(char *)icon_bits, icon_width, icon_height));
}
/*
* Place the given colors into an array of XcmsColors.
* Exactly which array is not specified -
* but we use cpmap.
* Return the colormap the colors are going into.
*
* The idea is that after this map is completely loaded,
* it will copied into the primary editing map.
*/
/* XcmsColor *PutHvcColors(colors, size)
* XcmsColor *colors;
* int size;
* {
* bcopy(colors, cpmap+colors->pixel, size * sizeof(XcmsColor));
*
* return(cpmap);
* }
*/
/*
* Place the given colors into a colormap. Exactly which colormap
* is not specified, but we put it into a temporary.
* Return the colormap the colors are going into.
*
* The idea is that after this map is completely loaded,
* it will copied into the primary editing map.
*/
/* Colormap PutRgbColors(colors, size)
* XColor *colors;
* int size;
* {
* XStoreColors(dpy, tmpMap, colors, size);
*
* return(tmpMap);
* }
*/
/*
* Remember pixels allocated by widgets to avoid later conflicts
*/
void RegisterIfPixel(pix)
Pixel pix;
{
int i;
/* allow only unique entries */
for (i = 0; i < ifColorCt; i++) {
if (ifColors[i] == pix)
return;
}
/* disable filling mode if pixel is in "stolen" range */
if ( (pix >= huebarBase) && (allowFill <= FillHuebar) ) {
allowFill = FillHuebar + 1;
huebarState = HuebarEmpty;
}
if ( (pix >= leafBase) && (allowFill <= FillLeaf) ) {
allowFill = FillLeaf + 1;
leafState &= ~LeafFilled;
}
ifColors[ifColorCt++] = pix;
if (ifColorCt >= MaxIfColors)
Error("Too many colors allocated for the interface");
}
/*
* If the passed shell widget does not have an icon bitmap set,
* create one and set it.
*/
/* void SetIcon(w)
* Widget w;
* {
* #if defined(HOST_BASED) || defined(MIT)
* Arg arg;
* Pixmap existing;
* STATIC Pixmap icon = NULL;
*
* XtSetArg(arg, XtNiconPixmap, &existing);
* XtGetValues(w, &arg, 1);
*
* if (existing != NULL)
* return;
*
* /*
* * Could get icon sizes, build a pixmap and render into it.
* * However, 32x32 seems to be a likely candidate (if the wm
* * supports this at all). And this is easier.
* *//*
* if (!icon)
* icon = XCreateBitmapFromData(dpy, RootWindow(dpy, visInfo.screen),
* icon_bits, icon_width, icon_height);
* arg.value = (XtArgVal)icon;
* XtSetValues(w, &arg, 1);
* }
*/
void SetCursor(crsr)
Cursor crsr;
{
/* TODO: need to know how to get windows to update */
XDefineCursor(dpy, XtWindow(primary), crsr);
/* use XSync instead ?? */
XFlush(dpy);
}
/*
* Load the given cell from the backup map into the visible map.
* If the index is -1, load the entire map.
*/
/* void UncacheCell(index)
* int index;
* {
* if (index < 0) {
* bcopy(cpmap, currentMap, mapSize * sizeof(XcmsColor));
* #ifdef XDEBUG
* routine_name = UNCACHE_CELL;
* #endif
* StoreAllocColors(dpy, cmap, cpmap, mapSize, XcmsTekHVCFormat);
* } else {
* bcopy((char *)&cpmap[index], (char *)¤tMap[index], sizeof(XcmsColor));
* #ifdef XDEBUG
* routine_name = UNCACHE_CELL;
* #endif
* StoreAllocColors(dpy, cmap, cpmap+index, 1, XcmsTekHVCFormat);
* }
* }
*/
/****************************************************************************
*
* NAME
* StoreAllocColors - Either Store or Allocate Colors
*
* DESCRIPTION
* Do XcmsStoreColors/XcmsQueryColors if the visual is dynamic.
* Do XcmsAllocColor if visual is static.
*
* Returns
* 0 = Failure
* 1 = Success
*
*****************************************************************************/
void StoreAllocColors (dsply, colormap, color, count, f1)
Display *dsply;
Colormap colormap;
XcmsColor *color;
int count;
XcmsColorFormat f1;
{
if (XcmsStoreColors(dsply, colormap, color, count, NULL) == XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsStoreColors failed in %s\n", routine_name);
#endif
}
if (XcmsQueryColors(dsply, colormap, color, count, f1)==XcmsFailure) {
#ifdef XDEBUG
fprintf (stderr, "Warning: XcmsQueryColors failed in %s\n", routine_name);
#endif
}
}
/*
* Set the value of the current index.
* Must be called after all widgets are created to avoid conflicts.
*/
void SetFirstIndex()
{
Pixel i;
int new = -1;
for (i = 0; new < 0; i++) {
if (IsIfIndex(i))
continue;
if (IsBWIndex(i))
continue;
new = (int)i;
}
NewIndex(new, NoWidget);
}