?? tkunixselect.c
字號:
Tk_GetAtomName(tkwin, retrPtr->target), "\" not defined", (char *) NULL); retrPtr->result = TCL_ERROR; return; } } } propInfo = NULL; result = XGetWindowProperty(eventPtr->xselection.display, eventPtr->xselection.requestor, retrPtr->property, 0, MAX_PROP_WORDS, False, (Atom) AnyPropertyType, &type, &format, &numItems, &bytesAfter, (unsigned char **) &propInfo); if ((result != Success) || (type == None)) { return; } if (bytesAfter != 0) { Tcl_SetResult(retrPtr->interp, "selection property too large", TCL_STATIC); retrPtr->result = TCL_ERROR; XFree(propInfo); return; } if ((type == XA_STRING) || (type == dispPtr->textAtom) || (type == dispPtr->compoundTextAtom)) { if (format != 8) { sprintf(retrPtr->interp->result, "bad format for string selection: wanted \"8\", got \"%d\"", format); retrPtr->result = TCL_ERROR; return; } interp = retrPtr->interp; Tcl_Preserve((ClientData) interp); retrPtr->result = (*retrPtr->proc)(retrPtr->clientData, interp, propInfo); Tcl_Release((ClientData) interp); } else if (type == dispPtr->incrAtom) { /* * 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. */ retrPtr->idleTime = 0; Tk_CreateEventHandler(tkwin, PropertyChangeMask, SelRcvIncrProc, (ClientData) retrPtr); XDeleteProperty(Tk_Display(tkwin), Tk_WindowId(tkwin), retrPtr->property); while (retrPtr->result == -1) { Tcl_DoOneEvent(0); } Tk_DeleteEventHandler(tkwin, PropertyChangeMask, SelRcvIncrProc, (ClientData) retrPtr); } else { char *string; if (format != 32) { sprintf(retrPtr->interp->result, "bad format for selection: wanted \"32\", got \"%d\"", format); retrPtr->result = TCL_ERROR; return; } string = SelCvtFromX((long *) propInfo, (int) numItems, type, (Tk_Window) winPtr); interp = retrPtr->interp; Tcl_Preserve((ClientData) interp); retrPtr->result = (*retrPtr->proc)(retrPtr->clientData, interp, string); Tcl_Release((ClientData) interp); ckfree(string); } XFree(propInfo); return; } /* * Case #3: SelectionRequest events. Call ConvertSelection to * do the dirty work. */ if (eventPtr->type == SelectionRequest) { ConvertSelection(winPtr, &eventPtr->xselectionrequest); 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 voidSelTimeoutProc(clientData) ClientData clientData; /* Information about retrieval * in progress. */{ register TkSelRetrievalInfo *retrPtr = (TkSelRetrievalInfo *) clientData; /* * 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. */ if (retrPtr->result != -1) { return; } retrPtr->idleTime++; if (retrPtr->idleTime >= 5) { /* * Use a careful procedure to store the error message, because * the result could already be partially filled in with a partial * selection return. */ Tcl_SetResult(retrPtr->interp, "selection owner didn't respond", TCL_STATIC); retrPtr->result = TCL_ERROR; } else { retrPtr->timeout = Tcl_CreateTimerHandler(1000, SelTimeoutProc, (ClientData) retrPtr); }}/* *---------------------------------------------------------------------- * * ConvertSelection -- * * This procedure is invoked to handle SelectionRequest events. * It responds to the requests, obeying the ICCCM protocols. * * Results: * None. * * Side effects: * 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 voidConvertSelection(winPtr, eventPtr) TkWindow *winPtr; /* Window that received the * conversion request; may not be * selection's current owner, be we * set it to the current owner. */ register XSelectionRequestEvent *eventPtr; /* Event describing request. */{ XSelectionEvent reply; /* Used to notify requestor that * selection info is ready. */ int multiple; /* Non-zero means a MULTIPLE request * is being handled. */ IncrInfo incr; /* State of selection conversion. */ Atom singleInfo[2]; /* incr.multAtoms points here except * for multiple conversions. */ int i; Tk_ErrorHandler errorHandler; TkSelectionInfo *infoPtr; TkSelInProgress ip; errorHandler = Tk_CreateErrorHandler(eventPtr->display, -1, -1,-1, (int (*)()) NULL, (ClientData) NULL); /* * Initialize the reply event. */ reply.type = SelectionNotify; reply.serial = 0; reply.send_event = True; reply.display = eventPtr->display; reply.requestor = eventPtr->requestor; reply.selection = eventPtr->selection; reply.target = eventPtr->target; reply.property = eventPtr->property; if (reply.property == None) { reply.property = reply.target; } reply.time = eventPtr->time; for (infoPtr = winPtr->dispPtr->selectionInfoPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->selection == eventPtr->selection) break; } if (infoPtr == NULL) { goto refuse; } winPtr = (TkWindow *) infoPtr->owner; /* * Figure out which kind(s) of conversion to perform. If handling * a MULTIPLE conversion, then read the property describing which * conversions to perform. */ incr.winPtr = winPtr; incr.selection = eventPtr->selection; if (eventPtr->target != winPtr->dispPtr->multipleAtom) { multiple = 0; singleInfo[0] = reply.target; singleInfo[1] = reply.property; incr.multAtoms = singleInfo; incr.numConversions = 1; } else { Atom type; int format, result; unsigned long bytesAfter; multiple = 1; incr.multAtoms = NULL; if (eventPtr->property == None) { goto refuse; } result = XGetWindowProperty(eventPtr->display, eventPtr->requestor, eventPtr->property, 0, MAX_PROP_WORDS, False, XA_ATOM, &type, &format, &incr.numConversions, &bytesAfter, (unsigned char **) &incr.multAtoms); if ((result != Success) || (bytesAfter != 0) || (format != 32) || (type == None)) { if (incr.multAtoms != NULL) { XFree((char *) incr.multAtoms); } goto refuse; } incr.numConversions /= 2; /* Two atoms per conversion. */ } /* * 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.offsets = (int *) ckalloc((unsigned) (incr.numConversions*sizeof(int))); incr.numIncrs = 0; for (i = 0; i < incr.numConversions; i++) { Atom target, property, type; long buffer[TK_SEL_WORDS_AT_ONCE]; register TkSelHandler *selPtr; int numItems, format; char *propPtr; target = incr.multAtoms[2*i]; property = incr.multAtoms[2*i + 1]; incr.offsets[i] = -1; for (selPtr = winPtr->selHandlerList; selPtr != NULL; selPtr = selPtr->nextPtr) { if ((selPtr->target == target) && (selPtr->selection == eventPtr->selection)) { break; } } if (selPtr == NULL) { /* * 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. */ numItems = TkSelDefaultSelection(infoPtr, target, (char *) buffer, TK_SEL_BYTES_AT_ONCE, &type); if (numItems < 0) { incr.multAtoms[2*i + 1] = None; continue; } } else { ip.selPtr = selPtr; ip.nextPtr = pendingPtr; pendingPtr = &ip; type = selPtr->format; numItems = (*selPtr->proc)(selPtr->clientData, 0, (char *) buffer, TK_SEL_BYTES_AT_ONCE); pendingPtr = ip.nextPtr; if ((ip.selPtr == NULL) || (numItems < 0)) { incr.multAtoms[2*i + 1] = None; continue; } if (numItems > TK_SEL_BYTES_AT_ONCE) { panic("selection handler returned too many bytes"); } ((char *) buffer)[numItems] = '\0'; } /* * 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. */ incr.numIncrs++; type = winPtr->dispPtr->incrAtom; buffer[0] = SelectionSize(selPtr); if (buffer[0] == 0) { incr.multAtoms[2*i + 1] = None; continue; } numItems = 1; propPtr = (char *) buffer; format = 32; incr.offsets[i] = 0; } else if (type == XA_STRING) { propPtr = (char *) buffer; format = 8; } else { propPtr = (char *) SelCvtToX((char *) buffer, type, (Tk_Window) winPtr, &numItems); format = 32; } XChangeProperty(reply.display, reply.requestor, property, type, format, PropModeReplace, (unsigned char *) propPtr, numItems); if (propPtr != (char *) buffer) { ckfree(propPtr); } } /* * 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). */ if (incr.numIncrs > 0) { XSelectInput(reply.display, reply.requestor, PropertyChangeMask); incr.timeout = Tcl_CreateTimerHandler(1000, IncrTimeoutProc, (ClientData) &incr); incr.idleTime = 0; incr.reqWindow = reply.requestor; incr.time = infoPtr->time; incr.nextPtr = pendingIncrs; pendingIncrs = &incr; } if (multiple) { XChangeProperty(reply.display, reply.requestor, reply.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) incr.multAtoms, (int) incr.numConversions*2); } else { /* * Not a MULTIPLE request. The first property in "multAtoms" * got set to None if there was an error in conversion. */ reply.property = incr.multAtoms[1]; } XSendEvent(reply.display, reply.requestor, False, 0, (XEvent *) &reply); Tk_DeleteErrorHandler(errorHandler); /* * 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. */ if (incr.numIncrs > 0) { IncrInfo *incrPtr2; while (incr.numIncrs > 0) { Tcl_DoOneEvent(0);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -