📄 tkselect.c
字号:
/* * tkSelect.c -- * * This file manages the selection for the Tk toolkit, * translating between the standard X ICCCM conventions * and Tcl commands. * * Copyright (c) 1990-1993 The Regents of the University of California. * Copyright (c) 1994-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: @(#) tkSelect.c 1.57 96/05/03 10:52:40 */#include "tkInt.h"#include "tkSelect.h"/* * When a selection handler is set up by invoking "selection handle", * one of the following data structures is set up to hold information * about the command to invoke and its interpreter. */typedef struct { Tcl_Interp *interp; /* Interpreter in which to invoke command. */ int cmdLength; /* # of non-NULL bytes in command. */ char command[4]; /* Command to invoke. Actual space is * allocated as large as necessary. This * must be the last entry in the structure. */} CommandInfo;/* * When selection ownership is claimed with the "selection own" Tcl command, * one of the following structures is created to record the Tcl command * to be executed when the selection is lost again. */typedef struct LostCommand { Tcl_Interp *interp; /* Interpreter in which to invoke command. */ char command[4]; /* Command to invoke. Actual space is * allocated as large as necessary. This * must be the last entry in the structure. */} LostCommand;/* * Shared variables: */TkSelInProgress *pendingPtr = NULL; /* Topmost search in progress, or * NULL if none. *//* * Forward declarations for procedures defined in this file: */static int HandleTclCommand _ANSI_ARGS_((ClientData clientData, int offset, char *buffer, int maxBytes));static void LostSelection _ANSI_ARGS_((ClientData clientData));static int SelGetProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *portion));/* *-------------------------------------------------------------- * * Tk_CreateSelHandler -- * * This procedure is called to register a procedure * as the handler for selection requests of a particular * target type on a particular window for a particular * selection. * * Results: * None. * * Side effects: * In the future, whenever the selection is in tkwin's * window and someone requests the selection in the * form given by target, proc will be invoked to provide * part or all of the selection in the given form. If * there was already a handler declared for the given * window, target and selection type, then it is replaced. * Proc should have the following form: * * int * proc(clientData, offset, buffer, maxBytes) * ClientData clientData; * int offset; * char *buffer; * int maxBytes; * { * } * * The clientData argument to proc will be the same as * the clientData argument to this procedure. The offset * argument indicates which portion of the selection to * return: skip the first offset bytes. Buffer is a * pointer to an area in which to place the converted * selection, and maxBytes gives the number of bytes * available at buffer. Proc should place the selection * in buffer as a string, and return a count of the number * of bytes of selection actually placed in buffer (not * including the terminating NULL character). If the * return value equals maxBytes, this is a sign that there * is probably still more selection information available. * *-------------------------------------------------------------- */voidTk_CreateSelHandler(tkwin, selection, target, proc, clientData, format) Tk_Window tkwin; /* Token for window. */ Atom selection; /* Selection to be handled. */ Atom target; /* The kind of selection conversions * that can be handled by proc, * e.g. TARGETS or STRING. */ Tk_SelectionProc *proc; /* Procedure to invoke to convert * selection to type "target". */ ClientData clientData; /* Value to pass to proc. */ Atom format; /* Format in which the selection * information should be returned to * the requestor. XA_STRING is best by * far, but anything listed in the ICCCM * will be tolerated (blech). */{ register TkSelHandler *selPtr; TkWindow *winPtr = (TkWindow *) tkwin; if (winPtr->dispPtr->multipleAtom == None) { TkSelInit(tkwin); } /* * See if there's already a handler for this target and selection on * this window. If so, re-use it. If not, create a new one. */ for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) { if (selPtr == NULL) { selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler)); selPtr->nextPtr = winPtr->selHandlerList; winPtr->selHandlerList = selPtr; break; } if ((selPtr->selection == selection) && (selPtr->target == target)) { /* * Special case: when replacing handler created by * "selection handle", free up memory. Should there be a * callback to allow other clients to do this too? */ if (selPtr->proc == HandleTclCommand) { ckfree((char *) selPtr->clientData); } break; } } selPtr->selection = selection; selPtr->target = target; selPtr->format = format; selPtr->proc = proc; selPtr->clientData = clientData; if (format == XA_STRING) { selPtr->size = 8; } else { selPtr->size = 32; }}/* *---------------------------------------------------------------------- * * Tk_DeleteSelHandler -- * * Remove the selection handler for a given window, target, and * selection, if it exists. * * Results: * None. * * Side effects: * The selection handler for tkwin and target is removed. If there * is no such handler then nothing happens. * *---------------------------------------------------------------------- */voidTk_DeleteSelHandler(tkwin, selection, target) Tk_Window tkwin; /* Token for window. */ Atom selection; /* The selection whose handler * is to be removed. */ Atom target; /* The target whose selection * handler is to be removed. */{ TkWindow *winPtr = (TkWindow *) tkwin; register TkSelHandler *selPtr, *prevPtr; register TkSelInProgress *ipPtr; /* * Find the selection handler to be deleted, or return if it doesn't * exist. */ for (selPtr = winPtr->selHandlerList, prevPtr = NULL; ; prevPtr = selPtr, selPtr = selPtr->nextPtr) { if (selPtr == NULL) { return; } if ((selPtr->selection == selection) && (selPtr->target == target)) { break; } } /* * If ConvertSelection is processing this handler, tell it that the * handler is dead. */ for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { if (ipPtr->selPtr == selPtr) { ipPtr->selPtr = NULL; } } /* * Free resources associated with the handler. */ if (prevPtr == NULL) { winPtr->selHandlerList = selPtr->nextPtr; } else { prevPtr->nextPtr = selPtr->nextPtr; } if (selPtr->proc == HandleTclCommand) { ckfree((char *) selPtr->clientData); } ckfree((char *) selPtr);}/* *-------------------------------------------------------------- * * Tk_OwnSelection -- * * Arrange for tkwin to become the owner of a selection. * * Results: * None. * * Side effects: * From now on, requests for the selection will be directed * to procedures associated with tkwin (they must have been * declared with calls to Tk_CreateSelHandler). When the * selection is lost by this window, proc will be invoked * (see the manual entry for details). This procedure may * invoke callbacks, including Tcl scripts, so any calling * function should be reentrant at the point where * Tk_OwnSelection is invoked. * *-------------------------------------------------------------- */voidTk_OwnSelection(tkwin, selection, proc, clientData) Tk_Window tkwin; /* Window to become new selection * owner. */ Atom selection; /* Selection that window should own. */ Tk_LostSelProc *proc; /* Procedure to call when selection * is taken away from tkwin. */ ClientData clientData; /* Arbitrary one-word argument to * pass to proc. */{ register TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; TkSelectionInfo *infoPtr; Tk_LostSelProc *clearProc = NULL; ClientData clearData = NULL; /* Initialization needed only to * prevent compiler warning. */ if (dispPtr->multipleAtom == None) { TkSelInit(tkwin); } Tk_MakeWindowExist(tkwin); /* * This code is somewhat tricky. First, we find the specified selection * on the selection list. If the previous owner is in this process, and * is a different window, then we need to invoke the clearProc. However, * it's dangerous to call the clearProc right now, because it could * invoke a Tcl script that wrecks the current state (e.g. it could * delete the window). To be safe, defer the call until the end of the * procedure when we no longer care about the state. */ for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->selection == selection) { break; } } if (infoPtr == NULL) { infoPtr = (TkSelectionInfo*) ckalloc(sizeof(TkSelectionInfo)); infoPtr->selection = selection; infoPtr->nextPtr = dispPtr->selectionInfoPtr; dispPtr->selectionInfoPtr = infoPtr; } else if (infoPtr->clearProc != NULL) { if (infoPtr->owner != tkwin) { clearProc = infoPtr->clearProc; clearData = infoPtr->clearData; } else if (infoPtr->clearProc == LostSelection) { /* * If the selection handler is one created by "selection own", * be sure to free the record for it; otherwise there will be * a memory leak. */ ckfree((char *) infoPtr->clearData); } } infoPtr->owner = tkwin; infoPtr->serial = NextRequest(winPtr->display); infoPtr->clearProc = proc; infoPtr->clearData = clientData; /* * Note that we are using CurrentTime, even though ICCCM recommends against * this practice (the problem is that we don't necessarily have a valid * time to use). We will not be able to retrieve a useful timestamp for * the TIMESTAMP target later. */ infoPtr->time = CurrentTime; /* * Note that we are not checking to see if the selection claim succeeded. * If the ownership does not change, then the clearProc may never be * invoked, and we will return incorrect information when queried for the * current selection owner. */ XSetSelectionOwner(winPtr->display, infoPtr->selection, winPtr->window, infoPtr->time); /* * Now that we are done, we can invoke clearProc without running into * reentrancy problems. */ if (clearProc != NULL) { (*clearProc)(clearData); }}/* *---------------------------------------------------------------------- * * Tk_ClearSelection -- * * Eliminate the specified selection on tkwin's display, if there is one. * * Results: * None. * * Side effects: * The specified selection is cleared, so that future requests to retrieve * it will fail until some application owns it again. This procedure * invokes callbacks, possibly including Tcl scripts, so any calling * function should be reentrant at the point Tk_ClearSelection is invoked. * *---------------------------------------------------------------------- */voidTk_ClearSelection(tkwin, selection) Tk_Window tkwin; /* Window that selects a display. */ Atom selection; /* Selection to be cancelled. */{ register TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; TkSelectionInfo *infoPtr; TkSelectionInfo *prevPtr; TkSelectionInfo *nextPtr; Tk_LostSelProc *clearProc = NULL; ClientData clearData = NULL; /* Initialization needed only to * prevent compiler warning. */ if (dispPtr->multipleAtom == None) { TkSelInit(tkwin); } for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL; infoPtr != NULL; infoPtr = nextPtr) { nextPtr = infoPtr->nextPtr; if (infoPtr->selection == selection) { if (prevPtr == NULL) { dispPtr->selectionInfoPtr = nextPtr; } else { prevPtr->nextPtr = nextPtr; } break; } prevPtr = infoPtr; } if (infoPtr != NULL) { clearProc = infoPtr->clearProc; clearData = infoPtr->clearData; ckfree((char *) infoPtr); } XSetSelectionOwner(winPtr->display, selection, None, CurrentTime); if (clearProc != NULL) { (*clearProc)(clearData); }}/* *-------------------------------------------------------------- * * Tk_GetSelection -- * * Retrieve the value of a selection and pass it off (in * pieces, possibly) to a given procedure. * * 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: * The standard X11 protocols are used to retrieve the * selection. When it arrives, it is passed to proc. If * the selection is very large, it will be passed to proc * in several pieces. Proc should have the following * structure: * * int * proc(clientData, interp, portion) * ClientData clientData; * Tcl_Interp *interp; * char *portion; * {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -