[comp.windows.x] Storing data structure as a property

doug@ntvax.uucp (Douglas Scott) (11/29/89)

I have an application in which I wish to transfer a structure containing some
data between two instances of the same application, using the Selection
mechanism.  It is a small structure containing the name and size of a
temporary file (created by the requestee) wthat will be read by the requestor.
Since none of the standard format types or Atoms match what I am doing, I
figured I would just treat the struct as if it were just a string of raw
chars (as far as the property was concerned) and then recast it after it
is retrieved by the requestor:

store_selection(event)	/* loads selected region into cut buffer & property */
XSelectionRequestEvent *event;
{
	...

	ext_buff ext_info;	/* the struct with name & size of buffer */

		...in here the temp file is created, opened, written to,
		and closed in preparation for use by the requestor

		...

		/* set up the information struct to pass to requestor */

		strcpy(ext_info.name, bufname);
		ext_info.bufsize = c->bufsize;

		XChangeProperty(dpy,		/* load into property */
			event->requestor,	/* these are ok */
			event->property,
			event->target,
			format,			/* set to 8 */
			PropModeReplace,
			(char *) &ext_info,	/* cast as char array */
			(int) sizeof(ext_buff)); /* no. of bytes in struct */
		
...and so forth -- but as soon as XChangeProperty is called, I get:

XIO:  fatal IO error 32 (Broken pipe) on X server "woof:0.0"
      after 1388 requests (1388 known processed) with 0 events remaining.
      The connection was probably broken by a server shutdown or KillClient.

Is there a better way to send this data structure than as a char array?
Is there a format or size problem here?
Am I trying to do something illegal, and if so, why cant you send arbitrary
chunks of data as chars and recast on the other side?  I have my own Atom
type for this that I create with XInternAtom, so I am sure to send and recieve
something that both sides recognize.

Thank you in advance!

----------------------------------------------------------------------
Douglas Scott
Research Associate, CEMI, University of North Texas
doug@dept.csci.unt.edu

doug@ntvax.uucp (Douglas Scott) (12/01/89)

A simple change of cast from (char *) &ext_info to (unsigned char *) &ext_info
seems to have made the difference...what the h___ is an unsigned char?

______________________________________________________________________
Douglas Scott
doug@dept.csci.unt.edu

karlton@sgi.com (Phil Karlton) (12/13/89)

In article <1989Nov29.072922.18738@ntvax.uucp>, doug@ntvax.uucp (Douglas
Scott) writes:
> I have an application in which I wish to transfer a structure containing some
> data between two instances of the same application, using the Selection
> mechanism.  It is a small structure containing the name and size of a
> temporary file (created by the requestee) wthat will be read by the
requestor.
> Since none of the standard format types or Atoms match what I am doing, I
> figured I would just treat the struct as if it were just a string of raw
> chars (as far as the property was concerned) and then recast it after it
> is retrieved by the requestor:
 
 <sample code deleted>
 
> Is there a better way to send this data structure than as a char array?
> Is there a format or size problem here?
> Am I trying to do something illegal, and if so, why cant you send arbitrary
> chunks of data as chars and recast on the other side?  I have my own Atom
> type for this that I create with XInternAtom, so I am sure to send and
recieve
> something that both sides recognize.

I have no idea why your application was being killed or why changing the
cast would fix this, but I would like to address the property you are
using. It seems a little odd to me that your structure will only hold a
fixed length file name. However, you know your application, and maybe
that is appropriate. The principle problem is that you have enclosed an
integer (probably 32 bits wide) into the same data structure with the
file name. This will not work across applications that are running on
different endian machines.

There are two straightforward ways of solving this.

One is to convert the length into a string, and bundle the two "strings"
into a single text property by using XStringListToTextProperty and
XSetTextProperty. (I can hear the people complaining about the runtime
cost of doing the sprintf and the atoi. Compare that to the cost sending
a packet.)

The second is to use the MULTIPLE target and get both the FILE_NAME and
LENGTH targets converted with a single request. See the ICCCM for
details. This would imply that FILE_NAME as a target has no other
meaning within the context of your application

Note that the target of a selecton and the type of the returned value
need not be the same.

PK
--
Phil Karlton                            karlton@sgi.com
Silicon Graphics Computer Systems       415-335-1557
2011 N. Shoreline Blvd.
Mountain View, CA 94039

madd@world.std.com (jim frost) (12/14/89)

karlton@sgi.com (Phil Karlton) writes:
>In article <1989Nov29.072922.18738@ntvax.uucp>, doug@ntvax.uucp (Douglas
>Scott) writes:
>> I have an application in which I wish to transfer a structure containing some
>> data between two instances of the same application, using the Selection
>> mechanism.  It is a small structure containing the name and size of a
>> temporary file

>The principle problem is that you have enclosed an
>integer (probably 32 bits wide) into the same data structure with the
>file name. This will not work across applications that are running on
>different endian machines.

Your solutions are fine, but you could also use the networker's
approach towards byte-ordering problems, ntohl()/htonl(), which also
makes those people who avoid atoi() because of performance happier.

Or, if you don't trust the network byte-ordering functions:

  unsigned char *intToStr(i)
       unsigned int i;
  { static char s[4];

    s[3]= i & 0xff;
    s[2]= (i >> 8) & 0xff;
    s[1]= (i >> 16) & 0xff;
    s[0]= (i >> 24) & 0xff;
    return(s);
  }

  unsigned int strToInt(s)
       unsigned s[4];
  {
    return((s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[0]);
  }

This will work regardless of which endian the machine is.

Personally I like the idea of saving the number as a string but
there are a variety of ways to deal with the problem.

jim frost
saber software
jimf@saber.com