?? tkunixselect.c
字號:
/* * 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 { TkWindow *winPtr; /* Window that owns selection. */ Atom selection; /* Selection that is being retrieved. */ Atom *multAtoms; /* Information about conversions to * 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). */ int *offsets; /* One entry for each pair in * 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. */ int numIncrs; /* Number of entries in offsets that * aren't -1 (i.e. # of INCR-mode transfers * not yet completed). */ Tcl_TimerToken timeout; /* Token for timer procedure. */ int idleTime; /* Number of seconds since we heard * anything from the selection * requestor. */ Window reqWindow; /* Requestor's window id. */ Time time; /* Timestamp corresponding to * selection at beginning of request; * used to abort transfer if selection * changes. */ struct IncrInfo *nextPtr; /* Next in list of all INCR-style * retrievals currently pending. */} IncrInfo;static IncrInfo *pendingIncrs = NULL; /* List of all incr structures * currently active. *//* * Largest property that we'll accept when sending or receiving the * selection: */#define MAX_PROP_WORDS 100000static TkSelRetrievalInfo *pendingRetrievals = NULL; /* List of all retrievals currently * being waited for. *//* * Forward declarations for procedures defined in this file: */static void ConvertSelection _ANSI_ARGS_((TkWindow *winPtr, XSelectionRequestEvent *eventPtr));static void IncrTimeoutProc _ANSI_ARGS_((ClientData clientData));static char * SelCvtFromX _ANSI_ARGS_((long *propPtr, int numValues, Atom type, Tk_Window tkwin));static long * SelCvtToX _ANSI_ARGS_((char *string, Atom type, Tk_Window tkwin, int *numLongsPtr));static int SelectionSize _ANSI_ARGS_((TkSelHandler *selPtr));static void SelRcvIncrProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr));static void SelTimeoutProc _ANSI_ARGS_((ClientData clientData));/* *---------------------------------------------------------------------- * * 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. * *---------------------------------------------------------------------- */intTkSelGetSelection(interp, tkwin, selection, target, proc, clientData) Tcl_Interp *interp; /* Interpreter to use for reporting * errors. */ Tk_Window tkwin; /* Window on whose behalf to retrieve * the selection (determines display * from which to retrieve). */ Atom selection; /* Selection to retrieve. */ Atom target; /* Desired form in which selection * is to be returned. */ Tk_GetSelProc *proc; /* Procedure to call to process the * selection, once it has been retrieved. */ ClientData clientData; /* Arbitrary value to pass to proc. */{ TkSelRetrievalInfo retr; TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; /* * 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. */ retr.interp = interp; if (dispPtr->clipWindow == NULL) { int result; result = TkClipInit(interp, dispPtr); if (result != TCL_OK) { return result; } } retr.winPtr = (TkWindow *) dispPtr->clipWindow; retr.selection = selection; retr.property = selection; retr.target = target; retr.proc = proc; retr.clientData = clientData; retr.result = -1; retr.idleTime = 0; retr.nextPtr = pendingRetrievals; pendingRetrievals = &retr; /* * 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. */ XConvertSelection(winPtr->display, retr.selection, retr.target, retr.property, retr.winPtr->window, CurrentTime); /* * 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. */ retr.timeout = Tcl_CreateTimerHandler(1000, SelTimeoutProc, (ClientData) &retr); while (retr.result == -1) { Tcl_DoOneEvent(0); } Tcl_DeleteTimerHandler(retr.timeout); /* * Unregister the information about the selection retrieval * in progress. */ if (pendingRetrievals == &retr) { pendingRetrievals = retr.nextPtr; } else { TkSelRetrievalInfo *retrPtr; for (retrPtr = pendingRetrievals; retrPtr != NULL; retrPtr = retrPtr->nextPtr) { if (retrPtr->nextPtr == &retr) { retrPtr->nextPtr = retr.nextPtr; break; } } } return retr.result;}/* *---------------------------------------------------------------------- * * 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. * *---------------------------------------------------------------------- */voidTkSelPropProc(eventPtr) register XEvent *eventPtr; /* X PropertyChange event. */{ register IncrInfo *incrPtr; int i, format; Atom target, formatType; register TkSelHandler *selPtr; long buffer[TK_SEL_WORDS_AT_ONCE]; int numItems; char *propPtr; Tk_ErrorHandler errorHandler; /* * 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. */ if (eventPtr->xproperty.state != PropertyDelete) { return; } for (incrPtr = pendingIncrs; incrPtr != NULL; incrPtr = incrPtr->nextPtr) { if (incrPtr->reqWindow != eventPtr->xproperty.window) { continue; } for (i = 0; i < incrPtr->numConversions; i++) { if ((eventPtr->xproperty.atom != incrPtr->multAtoms[2*i + 1]) || (incrPtr->offsets[i] == -1)){ continue; } target = incrPtr->multAtoms[2*i]; incrPtr->idleTime = 0; for (selPtr = incrPtr->winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) { if (selPtr == NULL) { incrPtr->multAtoms[2*i + 1] = None; incrPtr->offsets[i] = -1; incrPtr->numIncrs --; return; } if ((selPtr->target == target) && (selPtr->selection == incrPtr->selection)) { formatType = selPtr->format; if (incrPtr->offsets[i] == -2) { numItems = 0; ((char *) buffer)[0] = 0; } else { TkSelInProgress ip; ip.selPtr = selPtr; ip.nextPtr = pendingPtr; pendingPtr = &ip; numItems = (*selPtr->proc)(selPtr->clientData, incrPtr->offsets[i], (char *) buffer, TK_SEL_BYTES_AT_ONCE); pendingPtr = ip.nextPtr; if (ip.selPtr == NULL) { /* * 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; } } ((char *) buffer)[numItems] = '\0'; } if (numItems < TK_SEL_BYTES_AT_ONCE) { if (numItems <= 0) { incrPtr->offsets[i] = -1; incrPtr->numIncrs--; } else { incrPtr->offsets[i] = -2; } } else { incrPtr->offsets[i] += numItems; } if (formatType == XA_STRING) { propPtr = (char *) buffer; format = 8; } else { propPtr = (char *) SelCvtToX((char *) buffer, formatType, (Tk_Window) incrPtr->winPtr, &numItems); format = 32; } errorHandler = Tk_CreateErrorHandler( eventPtr->xproperty.display, -1, -1, -1, (int (*)()) NULL, (ClientData) NULL); XChangeProperty(eventPtr->xproperty.display, eventPtr->xproperty.window, eventPtr->xproperty.atom, formatType, format, PropModeReplace, (unsigned char *) propPtr, numItems); Tk_DeleteErrorHandler(errorHandler); if (propPtr != (char *) buffer) { ckfree(propPtr); } 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. * *-------------------------------------------------------------- */voidTkSelEventProc(tkwin, eventPtr) Tk_Window tkwin; /* Window for which event was * targeted. */ register XEvent *eventPtr; /* X event: either SelectionClear, * SelectionRequest, or * SelectionNotify. */{ register TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; Tcl_Interp *interp; /* * Case #1: SelectionClear events. */ if (eventPtr->type == SelectionClear) { TkSelClearSelection(tkwin, eventPtr); } /* * Case #2: SelectionNotify events. Call the relevant procedure * to handle the incoming selection. */ if (eventPtr->type == SelectionNotify) { register TkSelRetrievalInfo *retrPtr; char *propInfo; Atom type; int format, result; unsigned long numItems, bytesAfter; for (retrPtr = pendingRetrievals; ; retrPtr = retrPtr->nextPtr) { if (retrPtr == NULL) { return; } if ((retrPtr->winPtr == winPtr) && (retrPtr->selection == eventPtr->xselection.selection) && (retrPtr->target == eventPtr->xselection.target) && (retrPtr->result == -1)) { if (retrPtr->property == eventPtr->xselection.property) { break; } if (eventPtr->xselection.property == None) { Tcl_SetResult(retrPtr->interp, (char *) NULL, TCL_STATIC); Tcl_AppendResult(retrPtr->interp, Tk_GetAtomName(tkwin, retrPtr->selection), " selection doesn't exist or form \"",
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -