int TkClipInit( Tcl_Interp *interp, /* Interpreter to use for error reporting. */ register TkDisplay *dispPtr)/* Display to initialize. */ { XSetWindowAttributes atts; dispPtr->clipTargetPtr = NULL; dispPtr->clipboardActive = 0; dispPtr->clipboardAppPtr = NULL; /* * Create the window used for clipboard ownership and selection retrieval, * and set up an event handler for it. */ dispPtr->clipWindow = Tk_CreateWindow(interp, NULL, "_clip", DisplayString(dispPtr->display)); if (dispPtr->clipWindow == NULL) { return TCL_ERROR; } Tcl_Preserve(dispPtr->clipWindow); atts.override_redirect = True; Tk_ChangeWindowAttributes(dispPtr->clipWindow, CWOverrideRedirect, &atts); Tk_MakeWindowExist(dispPtr->clipWindow); if (dispPtr->multipleAtom == None) { /* * Need to invoke selection initialization to make sure that atoms we * depend on below are defined. */ TkSelInit(dispPtr->clipWindow); } /* * Create selection handlers for types TK_APPLICATION and TK_WINDOW on * this window. Can't use the default handlers for these types because * this isn't a full-fledged window. */ Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, dispPtr->applicationAtom, ClipboardAppHandler, dispPtr,XA_STRING); Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, dispPtr->windowAtom, ClipboardWindowHandler, dispPtr, XA_STRING); return TCL_OK; }
void Tk_ClearSelection( 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); } }
int Tk_GetSelection( 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, /* Function to call to process the selection, * once it has been retrieved. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; TkSelectionInfo *infoPtr; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (dispPtr->multipleAtom == None) { TkSelInit(tkwin); } /* * If the selection is owned by a window managed by this process, then * call the retrieval function directly, rather than going through the X * server (it's dangerous to go through the X server in this case because * it could result in deadlock if an INCR-style selection results). */ for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->selection == selection) { break; } } if (infoPtr != NULL) { register TkSelHandler *selPtr; int offset, result, count; char buffer[TK_SEL_BYTES_AT_ONCE+1]; TkSelInProgress ip; for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList; selPtr != NULL; selPtr = selPtr->nextPtr) { if (selPtr->target==target && selPtr->selection==selection) { break; } } if (selPtr == NULL) { Atom type; count = TkSelDefaultSelection(infoPtr, target, buffer, TK_SEL_BYTES_AT_ONCE, &type); if (count > TK_SEL_BYTES_AT_ONCE) { Tcl_Panic("selection handler returned too many bytes"); } if (count < 0) { goto cantget; } buffer[count] = 0; result = (*proc)(clientData, interp, buffer); } else { offset = 0; result = TCL_OK; ip.selPtr = selPtr; ip.nextPtr = tsdPtr->pendingPtr; tsdPtr->pendingPtr = &ip; while (1) { count = (selPtr->proc)(selPtr->clientData, offset, buffer, TK_SEL_BYTES_AT_ONCE); if ((count < 0) || (ip.selPtr == NULL)) { tsdPtr->pendingPtr = ip.nextPtr; goto cantget; } if (count > TK_SEL_BYTES_AT_ONCE) { Tcl_Panic("selection handler returned too many bytes"); } buffer[count] = '\0'; result = (*proc)(clientData, interp, buffer); if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE) || (ip.selPtr == NULL)) { break; } offset += count; } tsdPtr->pendingPtr = ip.nextPtr; } return result; } /* * The selection is owned by some other process. */ return TkSelGetSelection(interp, tkwin, selection, target, proc, clientData); cantget: Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), "\" not defined", NULL); return TCL_ERROR; }
void Tk_OwnSelection( Tk_Window tkwin, /* Window to become new selection owner. */ Atom selection, /* Selection that window should own. */ Tk_LostSelProc *proc, /* Function 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 function 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); } }
void Tk_CreateSelHandler( 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, /* Function 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; } if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) { /* * If the user asked for a STRING handler and we understand * UTF8_STRING, we implicitly create a UTF8_STRING handler for them. */ target = winPtr->dispPtr->utf8Atom; for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) { if (selPtr == NULL) { selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler)); selPtr->nextPtr = winPtr->selHandlerList; winPtr->selHandlerList = selPtr; selPtr->selection = selection; selPtr->target = target; selPtr->format = target; /* We want UTF8_STRING format */ selPtr->proc = proc; if (selPtr->proc == HandleTclCommand) { /* * The clientData is selection controlled memory, so we * should make a copy for this selPtr. */ unsigned cmdInfoLen = sizeof(CommandInfo) + ((CommandInfo*)clientData)->cmdLength - 3; selPtr->clientData = (ClientData)ckalloc(cmdInfoLen); memcpy(selPtr->clientData, clientData, cmdInfoLen); } else { selPtr->clientData = clientData; } selPtr->size = 8; break; } if (selPtr->selection==selection && selPtr->target==target) { /* * Looks like we had a utf-8 target already. Leave it alone. */ break; } } } }