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 >
C/C++ Source or Header  |  1991-08-28  |  16KB  |  580 lines

  1. /*
  2.  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
  3.  *     All Rights Reserved
  4.  * 
  5.  * This file is a component of an X Window System client which uses the Xcms 
  6.  * Color Management System.  TekColor is a trademark of Tektronix, Inc.  The
  7.  * TekColor Editor is the subject of U.S. and foreign patents pending.  The
  8.  * term "TekHVC" designates a particular color space that is the subject of
  9.  * U.S. Patent No. 4,985,853 (equivalent foreign patents pending).
  10.  * Permission is hereby granted to use, copy, modify, sell, and otherwise
  11.  * distribute this software and its documentation for the X Window System
  12.  * environment, for any purpose and without fee, provided that:
  13.  * 
  14.  * 1.    The code and documentation are only used to implement a 
  15.  *      TekColor Editor in an X Window System environment; and
  16.  * 2.    This copyright and permission notice is reproduced in all copies
  17.  *     of the code and in supporting documentation.
  18.  * 
  19.  * Permission is granted to modify this code as required to allow it to
  20.  * be compiled on any host computer, provided that the functionality of
  21.  * the TekColor Editor is not modified in any way.  A description of any 
  22.  * modifications must be sent to Tektronix, Inc.  Contact 
  23.  * Tektronix Inc., P.O. Box 1000, Mail Station 60-850, 
  24.  * Network Displays Division Engineering, Wilsonville, OR 97070.
  25.  *
  26.  * Tektronix makes no representation about the suitability of this software
  27.  * for any purpose.  It is provided "as is" and with all faults.
  28.  * 
  29.  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
  30.  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  31.  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
  32.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  33.  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
  34.  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  35.  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
  36.  * 
  37.  *    NAME
  38.  *        selection.c - routines and resources dealing with selection
  39.  *
  40.  *    DESCRIPTION
  41.  *        This file contains routines and globals which implement
  42.  *        the XcmsColor selection convention.  This includes routines to
  43.  *        take control of, release, and convert the selection.
  44.  *        It also contains routines to respond to user messages directing
  45.  *        a color change to be implemented.
  46.  *
  47.  */
  48. #ifndef LINT
  49. static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
  50. #ifdef RCS_ID
  51. static char *rcsid=  "$Header: selection.c,v 1.2 91/08/22 11:34:26 adamsc Exp $";
  52. #endif /* RCS_ID */
  53. #endif /* LINT */
  54.  
  55. /*
  56.  *      EXTERNAL INCLUDES
  57.  */
  58.  
  59.  
  60. /*
  61.  *      INTERNAL INCLUDES
  62.  */
  63.  
  64. #include "xtici.h"
  65. #include <X11/Xatom.h>
  66. #include "CMSColor.h"
  67.  
  68. /*
  69.  *      EXTERNS
  70.  */
  71. extern Time lastTime;
  72.  
  73. /*
  74.  *      GLOBALS
  75.  */
  76. #ifdef DEC
  77. #  define GLOBAL    global
  78. #else
  79. #  define GLOBAL
  80. #endif
  81.  
  82. /* Has the selection been gained but not yet lost */
  83. Boolean selectionMine = False;
  84.  
  85. /*
  86.  * Use this atom to attempt to export to a cooperating client.
  87.  */
  88. Atom changeMessage;
  89. /* This atom marks editor as understanding CMS_COLOR protocol. */
  90. Atom markerProp;
  91.  
  92.  
  93. /*
  94.  *      LOCAL DEFINES
  95.  */
  96.  
  97. /*
  98.  *      LOCAL TYPEDEFS
  99.  */
  100.  
  101. /*
  102.  *      LOCAL VARIABLES
  103.  */
  104. #ifdef DEBUG
  105. #  define STATIC
  106. #else
  107. #  define STATIC        static
  108. #endif
  109.  
  110. /*
  111.  * variables controlling the colormap selection
  112.  */
  113. STATIC Atom   mapSelection;
  114. STATIC Window selectionWindow = 0;
  115. STATIC Widget selectionWidget = 0;
  116. STATIC Time   selectionTime;
  117.  
  118. /* supported target types */
  119. STATIC Atom colormapTarget, targetsTarget, multipleTarget, timestampTarget;
  120.  
  121. STATIC char *badtargetHelp = "\
  122. The selected window does not have a cooperating client.  In order to\n\
  123. use the Export mechanism the client controlling the selected window\n\
  124. must set the property named \042_CMS_COLOR\042 on one of its windows.\n\
  125. Documentation on this Color and Colormap Exchange Convention is available\n\
  126. for the asking.";
  127.  
  128. /*
  129.  * variables controlling the primary selection
  130.  */
  131. STATIC Atom primarySelection;
  132. STATIC Atom primaryTarget;
  133. STATIC Time selectionPrimaryTime;
  134. Boolean     selectionPrimaryMine = False;
  135.  
  136. /*
  137.  * Storage for when someone is sending a change to us.
  138.  */
  139. STATIC CmsChange changeRange;
  140.  
  141.  
  142. /************************************************************************
  143.  *                                    *
  144.  *            PRIVATE ROUTINES                *
  145.  *                                    *
  146.  ************************************************************************/
  147.  
  148.  
  149. /************************************************************************
  150.  *                                    *
  151.  *            PUBLIC ROUTINES                    *
  152.  *                                    *
  153.  ************************************************************************/
  154. /*
  155.  * Callback exercised when the editor requests color change selection.
  156.  */
  157. /* ARGSUSED */
  158. void ChangeColors(w, prange, sel, type, pval, len, format)
  159. Widget w;
  160. XtPointer prange;
  161. Atom *sel, *type;
  162. XtPointer pval;
  163. unsigned long *len;
  164. int *format;
  165. {
  166.     Colormap *val = (Colormap *)pval;
  167.     CmsChange *range = (CmsChange *)prange;
  168.     Colormap from;
  169.  
  170.     /* check if conversion failed */
  171.     if ( (*sel != mapSelection) || (*type != colormapTarget) )
  172.     return;
  173.  
  174.     /* Should value be freed even if conversion fails ?? */
  175.     if (val) {
  176.     from = *val;
  177.     XFree((char *)val);
  178.     } else
  179.     return;
  180.  
  181.     /* This change is not driven by user actions in the interface, */
  182.     /* so do not adjust the undo state */
  183.  
  184.     NewCellRange(from, (Pixel)range->min, (Pixel)range->max);
  185. }
  186.  
  187. /*
  188.  * Examine the passed selection clear event.  If it is valid,
  189.  * reset the boolean that indicates ownership.
  190.  */
  191. void ClearSelection(w, sel)
  192. Widget w;
  193. Atom *sel;
  194. {
  195.     /* should not happen */
  196.     if ( (w != selectionWidget) || (*sel != mapSelection) )
  197.     return;
  198.     selectionMine = False;
  199. }
  200.  
  201. /*
  202.  * Examine the passed selection request event.  If it is valid,
  203.  * respond to it.
  204.  * Returns false if the conversion cannot be performed.
  205.  */
  206. /* ARGSUSED */
  207. Boolean ConvertSelection(w, sel, tgt, type, pval, len, format)
  208.     Widget w;
  209.     Atom *sel, *tgt, *type;
  210.     XtPointer *pval;
  211.     unsigned long *len;
  212.     int *format;
  213. {
  214.     long *data;
  215.  
  216.     /* just in case */
  217.     if (*sel != mapSelection)
  218.     return(False);
  219.  
  220.     if (*tgt == colormapTarget) {
  221.     data = (long *)malloc(sizeof(Colormap));
  222.     *len = 1;
  223.     *format = 8 * sizeof(Colormap);
  224.     data[0] = cmap;
  225.     } else if (*tgt == timestampTarget) {
  226.     data = (long *)malloc(sizeof(Time));
  227.     *len = 1;
  228.     *format = 8 * sizeof(Time);
  229.     data[0] = selectionTime;
  230.     } else if (*tgt = targetsTarget) {
  231.     data = (long *)malloc(3 * sizeof(Atom));
  232.     *len = 3;
  233.     *format = 8 * sizeof(Atom);
  234.     data[0] = colormapTarget;
  235.     data[1] = timestampTarget;
  236.     data[2] = targetsTarget;
  237.     } else {
  238.     return(False);
  239.     }
  240.  
  241.     *type = *tgt;
  242.     *pval = (XtPointer)data;
  243.     return(True);
  244. }
  245.  
  246. /*
  247.  * Get the atom for the map selection and export notification.
  248.  */
  249. void CreateAtoms()
  250. {
  251.     mapSelection = XInternAtom(dpy, CMS_SelectionName, False);
  252.     changeMessage = XInternAtom(dpy, CMS_MessageName, False);
  253.     markerProp = XInternAtom(dpy, CMS_Status, False);
  254.     colormapTarget = XInternAtom(dpy, CMS_Colormap, False);
  255.     targetsTarget = XInternAtom(dpy, "TARGETS", False);
  256.     multipleTarget = XInternAtom(dpy, "MULTIPLE", False);
  257.     timestampTarget = XInternAtom(dpy, "TIMESTAMP", False);
  258.  
  259.     primarySelection = XA_PRIMARY;
  260.     primaryTarget = XA_STRING;
  261. }
  262.  
  263. /*
  264.  * The only user messages of interest are those that are CMS color change.
  265.  * For these, record the message and then request a selection conversion.
  266.  */
  267. void HandleUserMessage(me)
  268. XClientMessageEvent *me;
  269. {
  270.     void ChangeColors();
  271.  
  272.     if (me->message_type != changeMessage)
  273.     return;
  274.  
  275.     changeRange.when = me->data.l[0];
  276.     changeRange.min = me->data.l[1];
  277.     changeRange.max = me->data.l[2];
  278.     changeRange.x_root = me->data.l[3];
  279.     changeRange.y_root = me->data.l[4];
  280.  
  281.     XtGetSelectionValue(selectionWidget, mapSelection, colormapTarget,
  282.             ChangeColors, (XtPointer)&changeRange,
  283.             changeRange.when);
  284. }
  285.  
  286. /*
  287.  * Prepare to manage the selection mechanism.
  288.  * This involves using the passed window as an owner,
  289.  * setting up a fake property that we can use to get a decent timestamp,
  290.  * and insure property change events are received to get that timestamp.
  291.  */
  292. /* ARGSUSED */
  293. void NullProc(w, client, e, cont_to_dispatch)
  294. Widget w;
  295. XtPointer client;
  296. XEvent *e;
  297. Boolean *cont_to_dispatch;
  298. {
  299.     lastTime = ((XPropertyEvent *)e)->time;
  300. }
  301.  
  302. void InitSelection(owner)
  303. Widget owner;
  304. {
  305.     selectionWidget = owner;
  306.     selectionWindow = XtWindow(owner);
  307.  
  308.     /* 
  309.      * Need to get toolkit to select on PropertyChange events.
  310.      * So register an event handler, which turns out does nothing.
  311.      */
  312.     XtAddEventHandler(owner, PropertyChangeMask, False, NullProc, NULL);
  313.     /*
  314.      * Could set event handler to look for CMS_COLOR change user messages,
  315.      * but user messages don't have a mask.  It is simpler just to look for
  316.      * them in my event loop.
  317.      */
  318.     XChangeProperty(dpy, selectionWindow, markerProp, XA_STRING, 8, 
  319.             PropModeReplace, (unsigned char *)versionString, 
  320.             strlen(versionString)+1);
  321. }
  322.  
  323. /*
  324.  * Send notifcation to another client that the user wants it to change
  325.  * color(s).  The expected result is that the client will then request
  326.  * the selection, although there is no way to insure this.
  327.  * The protocol we publish uses the markerProp property to indicate
  328.  * if the client is interested, so do that at least.
  329.  */
  330. void NotifyTarget(target, be, index)
  331. Window target;
  332. XButtonEvent *be;
  333. int index;    /* -1 means all indexes */
  334. {
  335.     Atom type;
  336.     int format;
  337.     unsigned long nitems, after;
  338.     unsigned char *data;
  339.     XEvent e;
  340.     XClientMessageEvent *cm = (XClientMessageEvent *)&e;
  341.  
  342.     /* check if this window has the magic property */
  343.     XGetWindowProperty(dpy, target, markerProp, 0L, 0L, False, 
  344.             AnyPropertyType, &type, &format, 
  345.             &nitems, &after, &data);
  346.  
  347.     /* send a message telling the client to ask for the selection*/
  348.     if (type != None) {
  349.     cm->type = ClientMessage;
  350.     /* does the server set some of these fields automatically? */
  351.     cm->send_event = True;
  352.     cm->display = dpy;
  353.     cm->window = target;
  354.     cm->message_type = changeMessage;
  355.     cm->format = 32;
  356.     cm->data.l[0] = (long)be->time;
  357.         if (index < 0) {
  358.             cm->data.l[1] = 0;
  359.             cm->data.l[2] = mapSize - 1;
  360.     } else {
  361.         cm->data.l[1] = (long)index;
  362.         cm->data.l[2] = (long)index;
  363.     }
  364.     cm->data.l[3] = (long) be->x_root;
  365.     cm->data.l[4] = (long) be->y_root;
  366.     XSendEvent(dpy, target, True, NoEventMask, (XEvent *)cm);
  367.     /* or just tell the user we can't do anything with that window */
  368.     } else {
  369.     InformMsg("Cannot export to that window", badtargetHelp);
  370.     XBell(dpy, 0);
  371.     }
  372. }
  373.  
  374. /*
  375.  * Attempt to establish ownership of the selection.
  376.  */
  377. void TakeSelection()
  378. {
  379.     /*
  380.      * If this routine is called before selectionWindow is set, 
  381.      * it could not have been the result of the user editing,
  382.      * so it is premature.  Just ignore.
  383.      */
  384.     if (!selectionWindow)
  385.     return;
  386.  
  387.     selectionMine = XtOwnSelection(selectionWidget, mapSelection, 
  388.                    lastTime, ConvertSelection, 
  389.                    ClearSelection, NULL);
  390.     if (selectionMine)
  391.     selectionTime = lastTime;
  392. }
  393.  
  394. /*****************************************************************************
  395.  *  The following routines implement the Copy and Paste functions in menu.c
  396.  *****************************************************************************/
  397.  
  398. /*
  399.  * Examine the passed selection clear event.  If it is valid,
  400.  * reset the boolean that indicates ownership.
  401.  */
  402. /* ARGSUSED */
  403. void ClearPrimarySelection(w, sel)
  404. Widget w;
  405. Atom *sel;
  406. {
  407.     /* should not happen */
  408.     if (*sel != primarySelection)
  409.     return;
  410.     selectionPrimaryMine = False;
  411. }
  412.  
  413. #define STRLEN 50
  414.  
  415. /*
  416.  * Examine the passed selection request event.  If it is valid,
  417.  * respond to it.
  418.  * Returns false if the conversion cannot be performed.
  419.  */
  420. /* ARGSUSED */
  421. Boolean ConvertPrimarySelection(w, sel, tgt, type, pval, len, format)
  422. Widget w;
  423. Atom *sel, *tgt, *type;
  424. XtPointer *pval;
  425. unsigned long *len;
  426. int *format;
  427. {
  428.     XtPointer data;
  429.  
  430.     /* just in case */
  431.     if (*sel != primarySelection)
  432.     return(False);
  433.  
  434.     if (*tgt == primaryTarget) {
  435.     data = (XtPointer)malloc(STRLEN);
  436.     /* convert the clipColor to the string */
  437.     switch (clipColor.format) {
  438.         case XcmsRGBFormat:
  439.         sprintf (data, "\043%4.4x%4.4x%4.4x\000", 
  440.                  (unsigned)(clipColor.spec.RGB.red), 
  441.              (unsigned)(clipColor.spec.RGB.green), 
  442.              (unsigned)(clipColor.spec.RGB.blue));
  443.         break;
  444.         case XcmsRGBiFormat:
  445.         sprintf (data, "RGB:%7.5f/%7.5f/%7.5f\000", 
  446.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  447.                clipColor.spec.CIEXYZ.Z);
  448.         break;
  449.         case XcmsUndefinedFormat:
  450.         return(False);
  451.         case XcmsCIEXYZFormat:
  452.         sprintf (data, "CIEXYZ:%7.5lf/%7.5lf/%7.5lf\000", 
  453.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  454.                clipColor.spec.CIEXYZ.Z);
  455.         break;
  456.         case XcmsCIEuvYFormat:
  457.         sprintf (data, "CIEuvY:%7.5lf/%7.5lf/%7.5lf\000", 
  458.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  459.                clipColor.spec.CIEXYZ.Z);
  460.         break;
  461.         case XcmsCIExyYFormat:
  462.         sprintf (data, "CIExyY:%7.5lf/%7.5lf/%7.5lf\000", 
  463.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  464.                clipColor.spec.CIEXYZ.Z);
  465.         break;
  466.         case XcmsCIELabFormat:
  467.         sprintf (data, "CIELab:%7.5lf/%7.5lf/%7.5lf\000", 
  468.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  469.                clipColor.spec.CIEXYZ.Z);
  470.         break;
  471.         case XcmsCIELuvFormat:
  472.         sprintf (data, "CIELuv:%7.5lf/%7.5lf/%7.5lf\000", 
  473.                clipColor.spec.CIEXYZ.X, clipColor.spec.CIEXYZ.Y, 
  474.                clipColor.spec.CIEXYZ.Z);
  475.         break;
  476.         case XcmsTekHVCFormat:
  477.         sprintf (data, "TekHVC:%7.5lf/%7.5lf/%7.5lf\000", 
  478.                clipColor.spec.TekHVC.H,clipColor.spec.TekHVC.V, 
  479.                clipColor.spec.TekHVC.C);
  480.         break;
  481.         default:
  482.         return (False);
  483.     }
  484.     *len = strlen ((char *)data);
  485.     *format = 8;
  486.     } else if (*tgt = targetsTarget) {
  487.     data = (XtPointer)malloc(2 * sizeof(Atom));
  488.     *len = 2;
  489.     *format = 8 * sizeof(Atom);
  490.     ((Atom *)data)[0] = primaryTarget;
  491.     ((Atom *)data)[2] = targetsTarget;
  492.     } else {
  493.     return(False);
  494.     }
  495.  
  496.     *type = *tgt;
  497.     *pval = data;
  498.     /* printf ("ConvertPrimarySelection: \042%s\042\n", data); */
  499.     return(True);
  500. }
  501.  
  502. /*
  503.  * This code is establishing the copy color mechanism via an
  504.  * attempt to establish ownership of the primary selection.
  505.  */
  506. /* ARGSUSED */
  507. void HandleColorCopy()
  508. {
  509.     selectionPrimaryMine = XtOwnSelection(selectionWidget, primarySelection, 
  510.                               lastTime, ConvertPrimarySelection,
  511.                           ClearPrimarySelection, NULL);
  512.     if (selectionPrimaryMine)
  513.     selectionPrimaryTime = lastTime;
  514. }
  515.  
  516. /*
  517.  * Callback exercised when the editor requests color change selection.
  518.  */
  519. /* ARGSUSED */
  520. void ChangeColorStringCallback(w, ppColor, sel, type, pval, len, format)
  521. Widget w;
  522. XtPointer ppColor;
  523. Atom      *sel, *type;
  524. XtPointer pval;
  525. unsigned long *len;
  526. int *format;
  527. {
  528.     XcmsColor *pColor = (XcmsColor *)ppColor;
  529.     char *val = (char *)pval;
  530.     char *pColorString;
  531.     XcmsColor newColor, scrnColor;
  532.  
  533.     /* check if conversion failed */
  534.     if ((*sel == 0) || (*len == 0)) {
  535.     pColor->format = XcmsUndefinedFormat;
  536.     return;
  537.     }
  538.     if ((*sel != primarySelection) || (*type != primaryTarget)) {
  539.     pColor->format = XcmsUndefinedFormat;
  540.     return;
  541.     }
  542.  
  543.     /* Should value be freed even if conversion fails ?? */
  544.     if (val) {
  545.     /**********************************************************
  546.     /* Convert from the color string in val to a XcmsColor 
  547.     /* The format for color string is "color_string" 
  548.     /* Start by skipping over any white space in string.
  549.     /**********************************************************/
  550.     /* printf ("Paste: \042%s\042\n", val); */
  551.     pColorString = val;
  552.     while (*pColorString == ' ' || *pColorString == '\t') {
  553.         pColorString++;
  554.     }
  555.     newColor.format = XcmsTekHVCFormat;
  556.     if ((!*pColorString) || 
  557.         (XcmsLookupColor (dpy, cmap, pColorString, &newColor, 
  558.                &scrnColor, XcmsTekHVCFormat) == XcmsFailure)) {
  559.         /* Could put up warning here. */
  560.         XFree((char *)val);
  561.         pColor->format = XcmsUndefinedFormat;
  562.         return;
  563.     }
  564.     /* use the pixel value passed in to set new color */
  565.     newColor.pixel = pColor->pixel;
  566.     NewHvc (&newColor, MenuWidget, UnknownChange);
  567.     XFree((char *)val);
  568.     } else {
  569.     pColor->format = XcmsUndefinedFormat;
  570.     return;    
  571.     }
  572. }
  573.  
  574. int HandleColorPaste (pColor)
  575.     XcmsColor *pColor;
  576. {
  577.     XtGetSelectionValue(selectionWidget, primarySelection, primaryTarget,
  578.             ChangeColorStringCallback, pColor, lastTime);
  579. }
  580.