guy@auspex.auspex.com (Guy Harris) (09/30/90)
1) Andrew doesn't handle the INCR property mechanism, used for handling large selections, properly. The value of the INCR property, which is supposed to be a lower bound on the number of characters in the selection, is *NOT* supposed to be an ASCII string for that number, it's supposed to be the number itself (yes, this is supposed to work even between machines with different byte orders; the X server knows the byte order of all its clients and, since properties are composed of items all the same number of bytes in size, it can translate properties to the appropriate byte order). Without this fix, sucking "/etc/termcap" into, for example, "ez", selecting the entire file (assuming you have a normal humongous "/etc/termcap" file), and trying to paste it into, for example, "xedit", won't work, nor will sucking it into "xedit", selecting it all, and trying to paste it into "ez". 2) XView incorrectly gives the TARGETS target the type TARGETS rather than ATOM. A bug report has been sent to Sun, along with a fix (the fix is pretty straightforward); however, not everybody with XView necessarily has source or necessarily wants to run a version they've built from source, and the Open Windows 2.0 distribution has the bug, so it's probably polite to have Andrew compensate for XView's deficiencies here. 3) Speaking of XView, it insists that the LENGTH target be supported. The ICCCM doesn't say what its value should be; it's supposed to be the "number of bytes in (the) selection", but that number can vary depending on which target is requested; XView seems to want it to be the number of bytes in the STRING target, so that's what we give it. 4) Whilst we're at it, we have the code that handles selections issue complaints in some situations, rather than silently ignoring the selection requests; had it done so in the first place, I would have spent less time trying to figure out why I couldn't cut and paste between "ez" and "textedit".... *** atk/basics/x/xim.c.dist Thu Sep 27 16:54:07 1990 --- atk/basics/x/xim.c Thu Sep 27 17:03:00 1990 *************** *** 194,199 **** --- 194,200 ---- static Atom xim_TEXT; static Atom xim_INCR; static Atom xim_CLIPBOARD; + static Atom xim_LENGTH; static long LeftIncrement, TopIncrement, CurrLeftIncr, CurrTopIncr; *************** *** 762,767 **** --- 763,769 ---- xim_TEXT = XInternAtom(xDisplay, "TEXT", FALSE); xim_INCR = XInternAtom(xDisplay, "INCR", FALSE); xim_CLIPBOARD = XInternAtom(xDisplay, "CLIPBOARD", FALSE); + xim_LENGTH = XInternAtom(xDisplay, "LENGTH", FALSE); } for (i=0;i<8;i++) { Atom RetAtom; *************** *** 2868,2880 **** &actualtype, &actualformat, &nitems, &remainingbytes, &propList); target = None; ! if (success == Success && actualtype == XA_ATOM) ! for (i = 0; DesirableTargets[i] != None && target == None; i++) ! for (j = 0; j < nitems && target == None; j++) if (DesirableTargets[i] == ((Atom *)propList)[j]) target = DesirableTargets[i]; XFree((caddr_t)propList); ! if (target == None) break; /* okay, we'll ask for the selection in type 'target' */ --- 2870,2898 ---- &actualtype, &actualformat, &nitems, &remainingbytes, &propList); target = None; ! if (success == Success) { ! /* ! * XXX - work around XView bug, wherein it gives the type ! * TARGETS rather than ATOM to the result. ! */ ! if (actualtype == xim_TARGETS) ! actualtype = XA_ATOM; ! if (actualtype == XA_ATOM) { ! for (i = 0; DesirableTargets[i] != None && target == None; i++) ! for (j = 0; j < nitems && target == None; j++) if (DesirableTargets[i] == ((Atom *)propList)[j]) target = DesirableTargets[i]; + } else + fprintf(stderr,"TARGETS targets isn't of type ATOM\n"); + } XFree((caddr_t)propList); ! if (target == None) { ! /* ! * They don't speak our language. ! */ ! fprintf(stderr,"Owner of selection handles neither ATK nor STRING nor TEXT\n"); ! break; ! } /* okay, we'll ask for the selection in type 'target' */ *************** *** 2898,2904 **** /* is is an INCR ? */ if (actualtype == xim_INCR) { /* nuts, it is INCR. start multiple retrievals */ ! remainingbytes = atoi(elt->string->string); if (*elt->xfree) XFree(elt->string->string); else free(elt->string->string); *elt->xfree = FALSE; --- 2916,2922 ---- /* is is an INCR ? */ if (actualtype == xim_INCR) { /* nuts, it is INCR. start multiple retrievals */ ! remainingbytes = *(long *)elt->string->string; if (*elt->xfree) XFree(elt->string->string); else free(elt->string->string); *elt->xfree = FALSE; *************** *** 3057,3065 **** ProcessRequest(req) XSelectionRequestEvent *req; { ! Atom targets[6]; struct expandstring cutBuffer; - char m[12]; boolean xfree; struct proplistelt *elt; Atom actualtype; --- 3075,3082 ---- ProcessRequest(req) XSelectionRequestEvent *req; { ! Atom targets[7]; struct expandstring cutBuffer; boolean xfree; struct proplistelt *elt; Atom actualtype; *************** *** 3075,3082 **** targets[3] = xim_TEXT; targets[4] = xim_TARGETS; targets[5] = xim_MULTIPLE; XChangeProperty(req->display, req->requestor, req->property, ! XA_ATOM, 32, PropModeReplace, (char *)targets, 6); } else if (req->target == xim_TIMESTAMP) { XChangeProperty(req->display, req->requestor, req->property, --- 3092,3100 ---- targets[3] = xim_TEXT; targets[4] = xim_TARGETS; targets[5] = xim_MULTIPLE; + targets[6] = xim_LENGTH; XChangeProperty(req->display, req->requestor, req->property, ! XA_ATOM, 32, PropModeReplace, (char *)targets, 7); } else if (req->target == xim_TIMESTAMP) { XChangeProperty(req->display, req->requestor, req->property, *************** *** 3084,3090 **** (char *)&SelectionStartTime, 1); } else if (req->target == xim_ATK || req->target == XA_STRING ! || req->target == xim_TEXT) { if ( ! IOwnSelection || (req->time != CurrentTime && 0 > (long)(req->time - SelectionStartTime))) { --- 3102,3109 ---- (char *)&SelectionStartTime, 1); } else if (req->target == xim_ATK || req->target == XA_STRING ! || req->target == xim_TEXT ! || req->target == xim_LENGTH) { if ( ! IOwnSelection || (req->time != CurrentTime && 0 > (long)(req->time - SelectionStartTime))) { *************** *** 3103,3142 **** req->property = None; return FALSE; } ! if (req->target == XA_STRING || req->target == xim_TEXT) { ! /* delete objects and remove styles */ Unscribe(&cutBuffer); - if (req->target == xim_TEXT) - req->target = XA_STRING; - } - - /* send the data to the requestor */ - if (cutBuffer.length < MAXXFER) { /* send it with one XChangeProperty */ ! XChangeProperty(req->display, req->requestor, req->property, ! req->target, 8, PropModeReplace, ! cutBuffer.string, cutBuffer.length); if (xfree) XFree(cutBuffer.string); else free(cutBuffer.string); ! } ! else { ! /* send it via INCR scheme */ ! SetPNMask(req->display, req->requestor); ! elt = PostPropList(req->requestor, req->property, ! prop_OutIncr, req->time); ! elt->string = (struct expandstring *) ! malloc(sizeof(struct expandstring)); ! *(elt->string) = cutBuffer; ! elt->xfree = (xfree) ? &xfree : NULL; ! /* the value of elt->xfree is tested ! for non-NULL, but *elt->xfree is not used */ ! elt->type = req->target; ! sprintf(m, "%d", elt->string->length); ! XChangeProperty(req->display, req->requestor, req->property, ! xim_INCR, 8, PropModeReplace, ! m, strlen(m)); ! /* the main Interact loop will handle PropertyEvents ! we have to exit to do the SelectionNotify */ } if (OriginalNerrors != Nerrors) { /* OOPS. There was an error. Reject the request. */ --- 3122,3184 ---- req->property = None; return FALSE; } ! if (req->target == xim_LENGTH) { ! /* ! * Keep XView happy by telling it how big the ! * selection is. The SunView System Programmer's ! * Guide says that SELN_REQ_BYTESIZE is "the number ! * of bytes in the selection's ascii(sic) contents", ! * and that's what XView turns into a request for ! * LENGTH, so we delete objects and remove styles, ! * and give them the resulting size. ! */ Unscribe(&cutBuffer); /* send it with one XChangeProperty */ ! XChangeProperty(req->display, req->requestor, ! req->property, req->target, 32, ! PropModeReplace, ! (unsigned char *)&cutBuffer.length, 1); if (xfree) XFree(cutBuffer.string); else free(cutBuffer.string); ! } else { ! if (req->target == XA_STRING || req->target == xim_TEXT) { ! /* delete objects and remove styles */ ! Unscribe(&cutBuffer); ! if (req->target == xim_TEXT) ! req->target = XA_STRING; ! } ! ! /* send the data to the requestor */ ! if (cutBuffer.length < MAXXFER) { ! /* send it with one XChangeProperty */ ! XChangeProperty(req->display, req->requestor, ! req->property, req->target, 8, ! PropModeReplace, cutBuffer.string, ! cutBuffer.length); ! if (xfree) XFree(cutBuffer.string); ! else free(cutBuffer.string); ! } ! else { ! /* send it via INCR scheme */ ! SetPNMask(req->display, req->requestor); ! elt = PostPropList(req->requestor, ! req->property, prop_OutIncr, req->time); ! elt->string = (struct expandstring *) ! malloc(sizeof(struct expandstring)); ! *(elt->string) = cutBuffer; ! elt->xfree = (xfree) ? &xfree : NULL; ! /* the value of elt->xfree is tested ! for non-NULL, but *elt->xfree is not used */ ! elt->type = req->target; ! XChangeProperty(req->display, req->requestor, ! req->property,xim_INCR, 32, ! PropModeReplace, ! (unsigned char *)&elt->string->length, ! 1); ! /* the main Interact loop will handle ! PropertyEvents we have to exit to do the ! SelectionNotify */ ! } } if (OriginalNerrors != Nerrors) { /* OOPS. There was an error. Reject the request. */