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
/
selection.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-28
|
16KB
|
580 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
* selection.c - routines and resources dealing with selection
*
* DESCRIPTION
* This file contains routines and globals which implement
* the XcmsColor selection convention. This includes routines to
* take control of, release, and convert the selection.
* It also contains routines to respond to user messages directing
* a color change to be implemented.
*
*/
#ifndef LINT
static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
#ifdef RCS_ID
static char *rcsid= "$Header: selection.c,v 1.2 91/08/22 11:34:26 adamsc Exp $";
#endif /* RCS_ID */
#endif /* LINT */
/*
* EXTERNAL INCLUDES
*/
/*
* INTERNAL INCLUDES
*/
#include "xtici.h"
#include <X11/Xatom.h>
#include "CMSColor.h"
/*
* EXTERNS
*/
extern Time lastTime;
/*
* GLOBALS
*/
#ifdef DEC
# define GLOBAL global
#else
# define GLOBAL
#endif
/* Has the selection been gained but not yet lost */
Boolean selectionMine = False;
/*
* Use this atom to attempt to export to a cooperating client.
*/
Atom changeMessage;
/* This atom marks editor as understanding CMS_COLOR protocol. */
Atom markerProp;
/*
* LOCAL DEFINES
*/
/*
* LOCAL TYPEDEFS
*/
/*
* LOCAL VARIABLES
*/
#ifdef DEBUG
# define STATIC
#else
# define STATIC static
#endif
/*
* variables controlling the colormap selection
*/
STATIC Atom mapSelection;
STATIC Window selectionWindow = 0;
STATIC Widget selectionWidget = 0;
STATIC Time selectionTime;
/* supported target types */
STATIC Atom colormapTarget, targetsTarget, multipleTarget, timestampTarget;
STATIC char *badtargetHelp = "\
The selected window does not have a cooperating client. In order to\n\
use the Export mechanism the client controlling the selected window\n\
must set the property named \042_CMS_COLOR\042 on one of its windows.\n\
Documentation on this Color and Colormap Exchange Convention is available\n\
for the asking.";
/*
* variables controlling the primary selection
*/
STATIC Atom primarySelection;
STATIC Atom primaryTarget;
STATIC Time selectionPrimaryTime;
Boolean selectionPrimaryMine = False;
/*
* Storage for when someone is sending a change to us.
*/
STATIC CmsChange changeRange;
/************************************************************************
* *
* PRIVATE ROUTINES *
* *
************************************************************************/
/************************************************************************
* *
* PUBLIC ROUTINES *
* *
************************************************************************/
/*
* Callback exercised when the editor requests color change selection.
*/
/* ARGSUSED */
void ChangeColors(w, prange, sel, type, pval, len, format)
Widget w;
XtPointer prange;
Atom *sel, *type;
XtPointer pval;
unsigned long *len;
int *format;
{
Colormap *val = (Colormap *)pval;
CmsChange *range = (CmsChange *)prange;
Colormap from;
/* check if conversion failed */
if ( (*sel != mapSelection) || (*type != colormapTarget) )
return;
/* Should value be freed even if conversion fails ?? */
if (val) {
from = *val;
XFree((char *)val);
} else
return;
/* This change is not driven by user actions in the interface, */
/* so do not adjust the undo state */
NewCellRange(from, (Pixel)range->min, (Pixel)range->max);
}
/*
* Examine the passed selection clear event. If it is valid,
* reset the boolean that indicates ownership.
*/
void ClearSelection(w, sel)
Widget w;
Atom *sel;
{
/* should not happen */
if ( (w != selectionWidget) || (*sel != mapSelection) )
return;
selectionMine = False;
}
/*
* Examine the passed selection request event. If it is valid,
* respond to it.
* Returns false if the conversion cannot be performed.
*/
/* ARGSUSED */
Boolean ConvertSelection(w, sel, tgt, type, pval, len, format)
Widget w;
Atom *sel, *tgt, *type;
XtPointer *pval;
unsigned long *len;
int *format;
{
long *data;
/* just in case */
if (*sel != mapSelection)
return(False);
if (*tgt == colormapTarget) {
data = (long *)malloc(sizeof(Colormap));
*len = 1;
*format = 8 * sizeof(Colormap);
data[0] = cmap;
} else if (*tgt == timestampTarget) {
data = (long *)malloc(sizeof(Time));
*len = 1;
*format = 8 * sizeof(Time);
data[0] = selectionTime;
} else if (*tgt = targetsTarget) {
data = (long *)malloc(3 * sizeof(Atom));
*len = 3;
*format = 8 * sizeof(Atom);
data[0] = colormapTarget;
data[1] = timestampTarget;
data[2] = targetsTarget;
} else {
return(False);
}
*type = *tgt;
*pval = (XtPointer)data;
return(True);
}
/*
* Get the atom for the map selection and export notification.
*/
void CreateAtoms()
{
mapSelection = XInternAtom(dpy, CMS_SelectionName, False);
changeMessage = XInternAtom(dpy, CMS_MessageName, False);
markerProp = XInternAtom(dpy, CMS_Status, False);
colormapTarget = XInternAtom(dpy, CMS_Colormap, False);
targetsTarget = XInternAtom(dpy, "TARGETS", False);
multipleTarget = XInternAtom(dpy, "MULTIPLE", False);
timestampTarget = XInternAtom(dpy, "TIMESTAMP", False);
primarySelection = XA_PRIMARY;
primaryTarget = XA_STRING;
}
/*
* The only user messages of interest are those that are CMS color change.
* For these, record the message and then request a selection conversion.
*/
void HandleUserMessage(me)
XClientMessageEvent *me;
{
void ChangeColors();
if (me->message_type != changeMessage)
return;
changeRange.when = me->data.l[0];
changeRange.min = me->data.l[1];
changeRange.max = me->data.l[2];
changeRange.x_root = me->data.l[3];
changeRange.y_root = me->data.l[4];
XtGetSelectionValue(selectionWidget, mapSelection, colormapTarget,
ChangeColors, (XtPointer)&changeRange,
changeRange.when);
}
/*
* Prepare to manage the selection mechanism.
* This involves using the passed window as an owner,
* setting up a fake property that we can use to get a decent timestamp,
* and insure property change events are received to get that timestamp.
*/
/* ARGSUSED */
void NullProc(w, client, e, cont_to_dispatch)
Widget w;
XtPointer client;
XEvent *e;
Boolean *cont_to_dispatch;
{
lastTime = ((XPropertyEvent *)e)->time;
}
void InitSelection(owner)
Widget owner;
{
selectionWidget = owner;
selectionWindow = XtWindow(owner);
/*
* Need to get toolkit to select on PropertyChange events.
* So register an event handler, which turns out does nothing.
*/
XtAddEventHandler(owner, PropertyChangeMask, False, NullProc, NULL);
/*
* Could set event handler to look for CMS_COLOR change user messages,
* but user messages don't have a mask. It is simpler just to look for
* them in my event loop.
*/
XChangeProperty(dpy, selectionWindow, markerProp, XA_STRING, 8,
PropModeReplace, (unsigned char *)versionString,
strlen(versionString)+1);
}
/*
* Send notifcation to another client that the user wants it to change
* color(s). The expected result is that the client will then request
* the selection, although there is no way to insure this.
* The protocol we publish uses the markerProp property to indicate
* if the client is interested, so do that at least.
*/
void NotifyTarget(target, be, index)
Window target;
XButtonEvent *be;
int index; /* -1 means all indexes */
{
Atom type;
int format;
unsigned long nitems, after;
unsigned char *data;
XEvent e;
XClientMessageEvent *cm = (XClientMessageEvent *)&e;
/* check if this window has the magic property */
XGetWindowProperty(dpy, target, markerProp, 0L, 0L, False,
AnyPropertyType, &type, &format,
&nitems, &after, &data);
/* send a message telling the client to ask for the selection*/
if (type != None) {
cm->type = ClientMessage;
/* does the server set some of these fields automatically? */
cm->send_event = True;
cm->display = dpy;
cm->window = target;
cm->message_type = changeMessage;
cm->format = 32;
cm->data.l[0] = (long)be->time;
if (index < 0) {
cm->data.l[1] = 0;
cm->data.l[2] = mapSize - 1;
} else {
cm->data.l[1] = (long)index;
cm->data.l[2] = (long)index;
}
cm->data.l[3] = (long) be->x_root;
cm->data.l[4] = (long) be->y_root;
XSendEvent(dpy, target, True, NoEventMask, (XEvent *)cm);
/* or just tell the user we can't do anything with that window */
} else {
InformMsg("Cannot export to that window", badtargetHelp);
XBell(dpy, 0);
}
}
/*
* Attempt to establish ownership of the selection.
*/
void TakeSelection()
{
/*
* If this routine is called before selectionWindow is set,
* it could not have been the result of the user editing,
* so it is premature. Just ignore.
*/
if (!selectionWindow)
return;
selectionMine = XtOwnSelection(selectionWidget, mapSelection,
lastTime, ConvertSelection,
ClearSelection, NULL);
if (selectionMine)
selectionTime = lastTime;
}
/*****************************************************************************
* The following routines implement the Copy and Paste functions in menu.c
*****************************************************************************/
/*
* Examine the passed selection clear event. If it is valid,
* reset the boolean that indicates ownership.
*/
/* ARGSUSED */
void ClearPrimarySelection(w, sel)
Widget w;
Atom *sel;
{
/* should not happen */
if (*sel != primarySelection)
return;
selectionPrimaryMine = False;
}
#define STRLEN 50
/*
* Examine the passed selection request event. If it is valid,
* respond to it.
* Returns false if the conversion cannot be performed.
*/
/* ARGSUSED */
Boolean ConvertPrimarySelection(w, sel, tgt, type, pval, len, format)
Widget w;
Atom *sel, *tgt, *type;
XtPointer *pval;
unsigned long *len;
int *format;
{
XtPointer data;
/* just in case */
if (*sel != primarySelection)
return(False);
if (*tgt == primaryTarget) {
data = (XtPointer)malloc(STRLEN);
/* convert the clipColor to the string */
switch (clipColor.format) {
case XcmsRGBFormat:
sprintf (data, "\043%4.4x%4.4x%4.4x\000",
(unsigned)(clipColor.spec.RGB.red),
(unsigned)(clipColor.spec.RGB.green),
(unsigned)(clipColor.spec.RGB.blue));
break;
case XcmsRGBiFormat:
sprintf (data, "RGB:%7.5f/%7.5f/%7.5f\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsUndefinedFormat:
return(False);
case XcmsCIEXYZFormat:
sprintf (data, "CIEXYZ:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsCIEuvYFormat:
sprintf (data, "CIEuvY:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsCIExyYFormat:
sprintf (data, "CIExyY:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsCIELabFormat:
sprintf (data, "CIELab:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsCIELuvFormat:
sprintf (data, "CIELuv:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y,
clipColor.spec.CIEXYZ.Z);
break;
case XcmsTekHVCFormat:
sprintf (data, "TekHVC:%7.5lf/%7.5lf/%7.5lf\000",
clipColor.spec.TekHVC.H,clipColor.spec.TekHVC.V,
clipColor.spec.TekHVC.C);
break;
default:
return (False);
}
*len = strlen ((char *)data);
*format = 8;
} else if (*tgt = targetsTarget) {
data = (XtPointer)malloc(2 * sizeof(Atom));
*len = 2;
*format = 8 * sizeof(Atom);
((Atom *)data)[0] = primaryTarget;
((Atom *)data)[2] = targetsTarget;
} else {
return(False);
}
*type = *tgt;
*pval = data;
/* printf ("ConvertPrimarySelection: \042%s\042\n", data); */
return(True);
}
/*
* This code is establishing the copy color mechanism via an
* attempt to establish ownership of the primary selection.
*/
/* ARGSUSED */
void HandleColorCopy()
{
selectionPrimaryMine = XtOwnSelection(selectionWidget, primarySelection,
lastTime, ConvertPrimarySelection,
ClearPrimarySelection, NULL);
if (selectionPrimaryMine)
selectionPrimaryTime = lastTime;
}
/*
* Callback exercised when the editor requests color change selection.
*/
/* ARGSUSED */
void ChangeColorStringCallback(w, ppColor, sel, type, pval, len, format)
Widget w;
XtPointer ppColor;
Atom *sel, *type;
XtPointer pval;
unsigned long *len;
int *format;
{
XcmsColor *pColor = (XcmsColor *)ppColor;
char *val = (char *)pval;
char *pColorString;
XcmsColor newColor, scrnColor;
/* check if conversion failed */
if ((*sel == 0) || (*len == 0)) {
pColor->format = XcmsUndefinedFormat;
return;
}
if ((*sel != primarySelection) || (*type != primaryTarget)) {
pColor->format = XcmsUndefinedFormat;
return;
}
/* Should value be freed even if conversion fails ?? */
if (val) {
/**********************************************************
/* Convert from the color string in val to a XcmsColor
/* The format for color string is "color_string"
/* Start by skipping over any white space in string.
/**********************************************************/
/* printf ("Paste: \042%s\042\n", val); */
pColorString = val;
while (*pColorString == ' ' || *pColorString == '\t') {
pColorString++;
}
newColor.format = XcmsTekHVCFormat;
if ((!*pColorString) ||
(XcmsLookupColor (dpy, cmap, pColorString, &newColor,
&scrnColor, XcmsTekHVCFormat) == XcmsFailure)) {
/* Could put up warning here. */
XFree((char *)val);
pColor->format = XcmsUndefinedFormat;
return;
}
/* use the pixel value passed in to set new color */
newColor.pixel = pColor->pixel;
NewHvc (&newColor, MenuWidget, UnknownChange);
XFree((char *)val);
} else {
pColor->format = XcmsUndefinedFormat;
return;
}
}
int HandleColorPaste (pColor)
XcmsColor *pColor;
{
XtGetSelectionValue(selectionWidget, primarySelection, primaryTarget,
ChangeColorStringCallback, pColor, lastTime);
}