/*
* tkUnixSelect.c --
*
* This file contains X specific routines for manipulating
* selections.
*
* Copyright (c) 1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkUnixSelect.c 1.5 96/03/29 14:14:31
*/
#include "tkInt.h"
#include "tkSelect.h"
/*
* When handling INCR-style selection retrievals, the selection owner
* uses the following data structure to communicate between the
* ConvertSelection procedure and TkSelPropProc.
*/
typedef struct IncrInfo {
* perform: one or more pairs of
* (target, property). This either
* points to a retrieved property (for
* MULTIPLE retrievals) or to a static
* array. */
unsigned long numConversions;
/* Number of entries in offsets (same as
* # of pairs in multAtoms). */
* multAtoms; -1 means all data has
* been transferred for this
* conversion. -2 means only the
* final zero-length transfer still
* has to be done. Otherwise it is the
* offset of the next chunk of data
* to transfer. This array is malloc-ed. */
* aren't -1 (i.e. # of INCR-mode transfers
* not yet completed). */
* anything from the selection
* requestor. */
* selection at beginning of request;
* used to abort transfer if selection
* changes. */
* retrievals currently pending. */
} IncrInfo;
/* List of all incr structures
* currently active. */
/*
* Largest property that we'll accept when sending or receiving the
* selection:
*/
/* List of all retrievals currently
* being waited for. */
/*
* Forward declarations for procedures defined in this file:
*/
/*
*----------------------------------------------------------------------
*
* TkSelGetSelection --
*
* Retrieve the specified selection from another process.
*
* Results:
* The return value is a standard Tcl return value.
* If an error occurs (such as no selection exists)
* then an error message is left in interp->result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
* errors. */
* the selection (determines display
* from which to retrieve). */
* is to be returned. */
* selection, once it has been retrieved. */
{
/*
* The selection is owned by some other process. To
* retrieve it, first record information about the retrieval
* in progress. Use an internal window as the requestor.
*/
int result;
return result;
}
}
/*
* Initiate the request for the selection. Note: can't use
* TkCurrentTime for the time. If we do, and this application hasn't
* received any X events in a long time, the current time will be way
* in the past and could even predate the time when the selection was
* made; if this happens, the request will be rejected.
*/
/*
* Enter a loop processing X events until the selection
* has been retrieved and processed. If no response is
* received within a few seconds, then timeout.
*/
(ClientData) &retr);
Tcl_DoOneEvent(0);
}
/*
* Unregister the information about the selection retrieval
* in progress.
*/
if (pendingRetrievals == &retr) {
} else {
break;
}
}
}
}
/*
*----------------------------------------------------------------------
*
* TkSelPropProc --
*
* This procedure is invoked when property-change events
* occur on windows not known to the toolkit. Its function
* is to implement the sending side of the INCR selection
* retrieval protocol when the selection requestor deletes
* the property containing a part of the selection.
*
* Results:
* None.
*
* Side effects:
* If the property that is receiving the selection was just
* deleted, then a new piece of the selection is fetched and
* placed in the property, until eventually there's no more
* selection to fetch.
*
*----------------------------------------------------------------------
*/
void
{
int i, format;
int numItems;
char *propPtr;
/*
* See if this event announces the deletion of a property being
* used for an INCR transfer. If so, then add the next chunk of
* data to the property.
*/
return;
}
continue;
}
for (i = 0; i < incrPtr->numConversions; i++) {
continue;
}
return;
}
numItems = 0;
((char *) buffer)[0] = 0;
} else {
pendingPtr = &ip;
/*
* The selection handler deleted itself.
*/
return;
}
if (numItems > TK_SEL_BYTES_AT_ONCE) {
panic("selection handler returned too many bytes");
} else {
if (numItems < 0) {
numItems = 0;
}
}
}
if (numItems < TK_SEL_BYTES_AT_ONCE) {
if (numItems <= 0) {
} else {
}
} else {
}
if (formatType == XA_STRING) {
format = 8;
} else {
&numItems);
format = 32;
}
}
return;
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* TkSelEventProc --
*
* This procedure is invoked whenever a selection-related
* event occurs. It does the lion's share of the work
* in implementing the selection protocol.
*
* Results:
* None.
*
* Side effects:
* Lots: depends on the type of event.
*
*--------------------------------------------------------------
*/
void
* targeted. */
* SelectionRequest, or
* SelectionNotify. */
{
/*
* Case #1: SelectionClear events.
*/
}
/*
* Case #2: SelectionNotify events. Call the relevant procedure
* to handle the incoming selection.
*/
char *propInfo;
return;
}
break;
}
" selection doesn't exist or form \"",
"\" not defined", (char *) NULL);
return;
}
}
}
(unsigned char **) &propInfo);
return;
}
if (bytesAfter != 0) {
return;
}
if (format != 8) {
"bad format for string selection: wanted \"8\", got \"%d\"",
format);
return;
}
/*
* It's a !?#@!?!! INCR-style reception. Arrange to receive
* the selection in pieces, using the ICCCM protocol, then
* hang around until either the selection is all here or a
* timeout occurs.
*/
(ClientData) retrPtr);
Tcl_DoOneEvent(0);
}
(ClientData) retrPtr);
} else {
char *string;
if (format != 32) {
"bad format for selection: wanted \"32\", got \"%d\"",
format);
return;
}
}
return;
}
/*
* Case #3: SelectionRequest events. Call ConvertSelection to
* do the dirty work.
*/
return;
}
}
/*
*----------------------------------------------------------------------
*
* SelTimeoutProc --
*
* This procedure is invoked once every second while waiting for
* the selection to be returned. After a while it gives up and
* aborts the selection retrieval.
*
* Results:
* None.
*
* Side effects:
* A new timer callback is created to call us again in another
* second, unless time has expired, in which case an error is
* recorded for the retrieval.
*
*----------------------------------------------------------------------
*/
static void
* in progress. */
{
/*
* Make sure that the retrieval is still in progress. Then
* see how long it's been since any sort of response was received
* from the other side.
*/
return;
}
/*
* Use a careful procedure to store the error message, because
* the result could already be partially filled in with a partial
* selection return.
*/
} else {
(ClientData) retrPtr);
}
}
/*
*----------------------------------------------------------------------
*
* ConvertSelection --
*
* This procedure is invoked to handle SelectionRequest events.
* It responds to the requests, obeying the ICCCM protocols.
*
* Results:
* None.
*
* Side effects:
* Properties are created for the selection requestor, and a
* SelectionNotify event is generated for the selection
* requestor. In the event of long selections, this procedure
* implements INCR-mode transfers, using the ICCCM protocol.
*
*----------------------------------------------------------------------
*/
static void
* conversion request; may not be
* selection's current owner, be we
* set it to the current owner. */
register XSelectionRequestEvent *eventPtr;
/* Event describing request. */
{
* selection info is ready. */
* is being handled. */
* for multiple conversions. */
int i;
/*
* Initialize the reply event.
*/
}
break;
}
goto refuse;
}
/*
* Figure out which kind(s) of conversion to perform. If handling
* a MULTIPLE conversion, then read the property describing which
* conversions to perform.
*/
multiple = 0;
} else {
unsigned long bytesAfter;
multiple = 1;
goto refuse;
}
}
goto refuse;
}
}
/*
* Loop through all of the requested conversions, and either return
* the entire converted selection, if it can be returned in a single
* bunch, or return INCR information only (the actual selection will
* be returned below).
*/
(incr.numConversions*sizeof(int)));
for (i = 0; i < incr.numConversions; i++) {
char *propPtr;
break;
}
}
/*
* Nobody seems to know about this kind of request. If
* it's of a sort that we can handle without any help, do
* it. Otherwise mark the request as an errror.
*/
if (numItems < 0) {
continue;
}
} else {
pendingPtr = &ip;
(char *) buffer, TK_SEL_BYTES_AT_ONCE);
continue;
}
if (numItems > TK_SEL_BYTES_AT_ONCE) {
panic("selection handler returned too many bytes");
}
}
/*
* Got the selection; store it back on the requestor's property.
*/
if (numItems == TK_SEL_BYTES_AT_ONCE) {
/*
* Selection is too big to send at once; start an
* INCR-mode transfer.
*/
if (buffer[0] == 0) {
continue;
}
numItems = 1;
format = 32;
format = 8;
} else {
format = 32;
}
}
}
/*
* Send an event back to the requestor to indicate that the
* first stage of conversion is complete (everything is done
* except for long conversions that have to be done in INCR
* mode).
*/
(ClientData) &incr);
pendingIncrs = &incr;
}
if (multiple) {
} else {
/*
* Not a MULTIPLE request. The first property in "multAtoms"
* got set to None if there was an error in conversion.
*/
}
/*
* Handle any remaining INCR-mode transfers. This all happens
* in callbacks to TkSelPropProc, so just wait until the number
* of uncompleted INCR transfers drops to zero.
*/
Tcl_DoOneEvent(0);
}
if (pendingIncrs == &incr) {
} else {
break;
}
}
}
}
/*
* All done. Cleanup and return.
*/
if (multiple) {
}
return;
/*
* An error occurred. Send back a refusal message.
*/
return;
}
/*
*----------------------------------------------------------------------
*
* SelRcvIncrProc --
*
* This procedure handles the INCR protocol on the receiving
* side. It is invoked in response to property changes on
* the requestor's window (which hopefully are because a new
* chunk of the selection arrived).
*
* Results:
* None.
*
* Side effects:
* If a new piece of selection has arrived, a procedure is
* invoked to deal with that piece. When the whole selection
* is here, a flag is left for the higher-level procedure that
* initiated the selection retrieval.
*
*----------------------------------------------------------------------
*/
static void
{
char *propInfo;
return;
}
&bytesAfter, (unsigned char **) &propInfo);
return;
}
if (bytesAfter != 0) {
goto done;
}
if (numItems == 0) {
if (format != 8) {
"bad format for string selection: wanted \"8\", got \"%d\"",
format);
goto done;
}
}
} else {
char *string;
if (format != 32) {
"bad format for selection: wanted \"32\", got \"%d\"",
format);
goto done;
}
}
}
done:
}
/*
*----------------------------------------------------------------------
*
* SelectionSize --
*
* This procedure is called when the selection is too large to
* send in a single buffer; it computes the total length of
* the selection in bytes.
*
* Results:
* The return value is the number of bytes in the selection
* given by selPtr.
*
* Side effects:
* The selection is retrieved from its current owner (this is
* the only way to compute its size).
*
*----------------------------------------------------------------------
*/
static int
* the selection whose size is wanted. */
{
pendingPtr = &ip;
do {
(char *) buffer, TK_SEL_BYTES_AT_ONCE);
size = 0;
break;
}
} while (chunkSize == TK_SEL_BYTES_AT_ONCE);
return size;
}
/*
*----------------------------------------------------------------------
*
* IncrTimeoutProc --
*
* This procedure is invoked once a second while sending the
* selection to a requestor in INCR mode. After a while it
* gives up and aborts the selection operation.
*
* Results:
* None.
*
* Side effects:
* A new timeout gets registered so that this procedure gets
* called again in another second, unless too many seconds
* have elapsed, in which case incrPtr is marked as "all done".
*
*----------------------------------------------------------------------
*/
static void
* selection retrieval for which
* we are selection owner. */
{
} else {
(ClientData) incrPtr);
}
}
/*
*----------------------------------------------------------------------
*
* SelCvtToX --
*
* Given a selection represented as a string (the normal Tcl form),
* convert it to the ICCCM-mandated format for X, depending on
* the type argument. This procedure and SelCvtFromX are inverses.
*
* Results:
* The return value is a malloc'ed buffer holding a value
* equivalent to "string", but formatted as for "type". It is
* the caller's responsibility to free the string when done with
* it. The word at *numLongsPtr is filled in with the number of
* 32-bit words returned in the result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static long *
char *string; /* String representation of selection. */
* desired for the selection. Should not
* be XA_STRING (if so, don't bother calling
* this procedure at all). */
int *numLongsPtr; /* Number of 32-bit words contained in the
* result. */
{
register char *p;
char *field;
int numFields;
/*
* The string is assumed to consist of fields separated by spaces.
* The property gets generated by converting each field to an
* integer number, in one of two ways:
* 1. If type is XA_ATOM, convert each field to its corresponding
* atom.
* 2. If type is anything else, convert each field from an ASCII number
* to a 32-bit binary number.
*/
numFields = 1;
for (p = string; *p != 0; p++) {
numFields++;
}
}
/*
* Convert the fields one-by-one.
*/
; longPtr++, (*numLongsPtr)++) {
p++;
}
if (*p == 0) {
break;
}
field = p;
p++;
}
int length;
if (length > MAX_ATOM_NAME_LENGTH) {
}
} else {
char *dummy;
}
}
return propPtr;
}
/*
*----------------------------------------------------------------------
*
* SelCvtFromX --
*
* Given an X property value, formatted as a collection of 32-bit
* values according to "type" and the ICCCM conventions, convert
* the value to a string suitable for manipulation by Tcl. This
* procedure is the inverse of SelCvtToX.
*
* Results:
* The return value is the string equivalent of "property". It is
* malloc-ed and should be freed by the caller when no longer
* needed.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static char *
register long *propPtr; /* Property value from X. */
int numValues; /* Number of 32-bit values in property. */
* XA_STRING (if so, don't bother calling
* this procedure at all). */
{
char *result;
char *atomName;
/*
* Convert each long in the property to a string value, which is
* either the name of an atom (if type is XA_ATOM) or a hexadecimal
* string. Make an initial guess about the size of the result, but
* be prepared to enlarge the result if necessary.
*/
curSize = 0;
*result = '\0';
} else {
fieldSize = 12;
}
char *newResult;
resultSpace *= 2;
}
}
if (curSize != 0) {
curSize++;
}
} else {
}
}
return result;
}