tkClipboard.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkClipboard.c --
  3.  *
  4.  *  This file manages the clipboard for the Tk toolkit,
  5.  *  maintaining a collection of data buffers that will be
  6.  *  supplied on demand to requesting applications.
  7.  *
  8.  * Copyright (c) 1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkClipboard.c,v 1.12.2.1 2004/05/03 22:23:08 hobbs Exp $
  15.  */
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18. #include "tkSelect.h"
  19. /*
  20.  * Prototypes for procedures used only in this file:
  21.  */
  22. static int ClipboardAppHandler _ANSI_ARGS_((ClientData clientData,
  23.     int offset, char *buffer, int maxBytes));
  24. static int ClipboardHandler _ANSI_ARGS_((ClientData clientData,
  25.     int offset, char *buffer, int maxBytes));
  26. static int ClipboardWindowHandler _ANSI_ARGS_((
  27.     ClientData clientData, int offset, char *buffer,
  28.     int maxBytes));
  29. static void ClipboardLostSel _ANSI_ARGS_((ClientData clientData));
  30. static int ClipboardGetProc _ANSI_ARGS_((ClientData clientData,
  31.     Tcl_Interp *interp, char *portion));
  32. /*
  33.  *----------------------------------------------------------------------
  34.  *
  35.  * ClipboardHandler --
  36.  *
  37.  * This procedure acts as selection handler for the
  38.  * clipboard manager.  It extracts the required chunk of
  39.  * data from the buffer chain for a given selection target.
  40.  *
  41.  * Results:
  42.  * The return value is a count of the number of bytes
  43.  * actually stored at buffer.
  44.  *
  45.  * Side effects:
  46.  * None.
  47.  *
  48.  *----------------------------------------------------------------------
  49.  */
  50. static int
  51. ClipboardHandler(clientData, offset, buffer, maxBytes)
  52.     ClientData clientData; /* Information about data to fetch. */
  53.     int offset; /* Return selection bytes starting at this
  54.  * offset. */
  55.     char *buffer; /* Place to store converted selection. */
  56.     int maxBytes; /* Maximum # of bytes to store at buffer. */
  57. {
  58.     TkClipboardTarget *targetPtr = (TkClipboardTarget*) clientData;
  59.     TkClipboardBuffer *cbPtr;
  60.     char *srcPtr, *destPtr;
  61.     int count = 0;
  62.     int scanned = 0;
  63.     size_t length, freeCount;
  64.     /*
  65.      * Skip to buffer containing offset byte
  66.      */
  67.     for (cbPtr = targetPtr->firstBufferPtr; ; cbPtr = cbPtr->nextPtr) {
  68. if (cbPtr == NULL) {
  69.     return 0;
  70. }
  71. if (scanned + cbPtr->length > offset) {
  72.     break;
  73. }
  74. scanned += cbPtr->length;
  75.     }
  76.     /*
  77.      * Copy up to maxBytes or end of list, switching buffers as needed.
  78.      */
  79.     freeCount = maxBytes;
  80.     srcPtr = cbPtr->buffer + (offset - scanned);
  81.     destPtr = buffer;
  82.     length = cbPtr->length - (offset - scanned);
  83.     while (1) {
  84. if (length > freeCount) {
  85.     strncpy(destPtr, srcPtr, freeCount);
  86.     return maxBytes;
  87. } else {
  88.     strncpy(destPtr, srcPtr, length);
  89.     destPtr += length;
  90.     count += length;
  91.     freeCount -= length;
  92. }
  93. cbPtr = cbPtr->nextPtr;
  94. if (cbPtr == NULL) {
  95.     break;
  96. }
  97. srcPtr = cbPtr->buffer;
  98. length = cbPtr->length;
  99.     }
  100.     return count;
  101. }
  102. /*
  103.  *----------------------------------------------------------------------
  104.  *
  105.  * ClipboardAppHandler --
  106.  *
  107.  * This procedure acts as selection handler for retrievals of type
  108.  * TK_APPLICATION.  It returns the name of the application that
  109.  * owns the clipboard.  Note:  we can't use the default Tk
  110.  * selection handler for this selection type, because the clipboard
  111.  * window isn't a "real" window and doesn't have the necessary
  112.  * information.
  113.  *
  114.  * Results:
  115.  * The return value is a count of the number of bytes
  116.  * actually stored at buffer.
  117.  *
  118.  * Side effects:
  119.  * None.
  120.  *
  121.  *----------------------------------------------------------------------
  122.  */
  123. static int
  124. ClipboardAppHandler(clientData, offset, buffer, maxBytes)
  125.     ClientData clientData; /* Pointer to TkDisplay structure. */
  126.     int offset; /* Return selection bytes starting at this
  127.  * offset. */
  128.     char *buffer; /* Place to store converted selection. */
  129.     int maxBytes; /* Maximum # of bytes to store at buffer. */
  130. {
  131.     TkDisplay *dispPtr = (TkDisplay *) clientData;
  132.     size_t length;
  133.     CONST char *p;
  134.     p = dispPtr->clipboardAppPtr->winPtr->nameUid;
  135.     length = strlen(p);
  136.     length -= offset;
  137.     if (length <= 0) {
  138. return 0;
  139.     }
  140.     if (length > (size_t) maxBytes) {
  141. length = maxBytes;
  142.     }
  143.     strncpy(buffer, p, length);
  144.     return length;
  145. }
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * ClipboardWindowHandler --
  150.  *
  151.  * This procedure acts as selection handler for retrievals of
  152.  * type TK_WINDOW.  Since the clipboard doesn't correspond to
  153.  * any particular window, we just return ".".  We can't use Tk's
  154.  * default handler for this selection type, because the clipboard
  155.  * window isn't a valid window.
  156.  *
  157.  * Results:
  158.  * The return value is 1, the number of non-null bytes stored
  159.  * at buffer.
  160.  *
  161.  * Side effects:
  162.  * None.
  163.  *
  164.  *----------------------------------------------------------------------
  165.  */
  166. static int
  167. ClipboardWindowHandler(clientData, offset, buffer, maxBytes)
  168.     ClientData clientData; /* Not used. */
  169.     int offset; /* Return selection bytes starting at this
  170.  * offset. */
  171.     char *buffer; /* Place to store converted selection. */
  172.     int maxBytes; /* Maximum # of bytes to store at buffer. */
  173. {
  174.     buffer[0] = '.';
  175.     buffer[1] = 0;
  176.     return 1;
  177. }
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * ClipboardLostSel --
  182.  *
  183.  * This procedure is invoked whenever clipboard ownership is
  184.  * claimed by another window.  It just sets a flag so that we
  185.  * know the clipboard was taken away.
  186.  *
  187.  * Results:
  188.  * None.
  189.  *
  190.  * Side effects:
  191.  * The clipboard is marked as inactive.
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195. static void
  196. ClipboardLostSel(clientData)
  197.     ClientData clientData; /* Pointer to TkDisplay structure. */
  198. {
  199.     TkDisplay *dispPtr = (TkDisplay*) clientData;
  200.     dispPtr->clipboardActive = 0;
  201. }
  202. /*
  203.  *----------------------------------------------------------------------
  204.  *
  205.  * Tk_ClipboardClear --
  206.  *
  207.  * Take control of the clipboard and clear out the previous
  208.  * contents.  This procedure must be invoked before any
  209.  * calls to Tk_ClipboardAppend.
  210.  *
  211.  * Results:
  212.  * A standard Tcl result.  If an error occurs, an error message is
  213.  * left in the interp's result.
  214.  *
  215.  * Side effects:
  216.  * From now on, requests for the CLIPBOARD selection will be
  217.  * directed to the clipboard manager routines associated with
  218.  * clipWindow for the display of tkwin.  In order to guarantee
  219.  * atomicity, no event handling should occur between
  220.  * Tk_ClipboardClear and the following Tk_ClipboardAppend
  221.  * calls.  This procedure may cause a user-defined LostSel command 
  222.  *  to be invoked when the CLIPBOARD is claimed, so any calling
  223.  * function should be reentrant at the point Tk_ClipboardClear is
  224.  * invoked.
  225.  *
  226.  *----------------------------------------------------------------------
  227.  */
  228. int
  229. Tk_ClipboardClear(interp, tkwin)
  230.     Tcl_Interp *interp; /* Interpreter to use for error reporting. */
  231.     Tk_Window tkwin; /* Window in application that is clearing
  232.  * clipboard;  identifies application and
  233.  * display. */
  234. {
  235.     TkWindow *winPtr = (TkWindow *) tkwin;
  236.     TkDisplay *dispPtr = winPtr->dispPtr;
  237.     TkClipboardTarget *targetPtr, *nextTargetPtr;
  238.     TkClipboardBuffer *cbPtr, *nextCbPtr;
  239.     if (dispPtr->clipWindow == NULL) {
  240. int result;
  241. result = TkClipInit(interp, dispPtr);
  242. if (result != TCL_OK) {
  243.     return result;
  244. }
  245.     }
  246.     /*
  247.      * Discard any existing clipboard data and delete the selection
  248.      * handler(s) associated with that data.
  249.      */
  250.     for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL;
  251.     targetPtr = nextTargetPtr) {
  252. for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL;
  253. cbPtr = nextCbPtr) {
  254.     ckfree(cbPtr->buffer);
  255.     nextCbPtr = cbPtr->nextPtr;
  256.     ckfree((char *) cbPtr);
  257. }
  258. nextTargetPtr = targetPtr->nextPtr;
  259. Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  260. targetPtr->type);
  261. ckfree((char *) targetPtr);
  262.     }
  263.     dispPtr->clipTargetPtr = NULL;
  264.     /*
  265.      * Reclaim the clipboard selection if we lost it.
  266.      */
  267.     if (!dispPtr->clipboardActive) {
  268. Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom,
  269. ClipboardLostSel, (ClientData) dispPtr);
  270. dispPtr->clipboardActive = 1;
  271.     }
  272.     dispPtr->clipboardAppPtr = winPtr->mainPtr;
  273.     return TCL_OK;
  274. }
  275. /*
  276.  *----------------------------------------------------------------------
  277.  *
  278.  * Tk_ClipboardAppend --
  279.  *
  280.  *  Append a buffer of data to the clipboard.  The first buffer of
  281.  * a given type determines the format for that type.  Any successive
  282.  * appends to that type must have the same format or an error will
  283.  * be returned.  Tk_ClipboardClear must be called before a sequence
  284.  * of Tk_ClipboardAppend calls can be issued.  In order to guarantee
  285.  * atomicity, no event handling should occur between Tk_ClipboardClear
  286.  * and the following Tk_ClipboardAppend calls.
  287.  *
  288.  * Results:
  289.  * A standard Tcl result.  If an error is returned, an error message
  290.  * is left in the interp's result.
  291.  *
  292.  * Side effects:
  293.  *  The specified buffer will be copied onto the end of the clipboard.
  294.  * The clipboard maintains a list of buffers which will be used to
  295.  * supply the data for a selection get request.  The first time a given
  296.  * type is appended, Tk_ClipboardAppend will register a selection
  297.  *  handler of the appropriate type.
  298.  *
  299.  *----------------------------------------------------------------------
  300.  */
  301. int
  302. Tk_ClipboardAppend(interp, tkwin, type, format, buffer)
  303.     Tcl_Interp *interp; /* Used for error reporting. */
  304.     Tk_Window tkwin; /* Window that selects a display. */
  305.     Atom type; /* The desired conversion type for this
  306.  * clipboard item, e.g. STRING or LENGTH. */
  307.     Atom format; /* Format in which the selection
  308.  * information should be returned to
  309.  * the requestor. */
  310.     char* buffer; /* NULL terminated string containing the data
  311.  * to be added to the clipboard. */
  312. {
  313.     TkWindow *winPtr = (TkWindow *) tkwin;
  314.     TkDisplay *dispPtr = winPtr->dispPtr;
  315.     TkClipboardTarget *targetPtr;
  316.     TkClipboardBuffer *cbPtr;
  317.     /*
  318.      * If this application doesn't already own the clipboard, clear
  319.      * the clipboard.  If we don't own the clipboard selection, claim it.
  320.      */
  321.     if (dispPtr->clipboardAppPtr != winPtr->mainPtr) {
  322. Tk_ClipboardClear(interp, tkwin);
  323.     } else if (!dispPtr->clipboardActive) {
  324. Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom,
  325. ClipboardLostSel, (ClientData) dispPtr);
  326. dispPtr->clipboardActive = 1;
  327.     }
  328.     /*
  329.      * Check to see if the specified target is already present on the
  330.      * clipboard.  If it isn't, we need to create a new target; otherwise,
  331.      * we just append the new buffer to the clipboard list.
  332.      */
  333.     for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL;
  334.     targetPtr = targetPtr->nextPtr) {
  335. if (targetPtr->type == type)
  336.     break;
  337.     }
  338.     if (targetPtr == NULL) {
  339. targetPtr = (TkClipboardTarget*) ckalloc(sizeof(TkClipboardTarget));
  340. targetPtr->type = type;
  341. targetPtr->format = format;
  342. targetPtr->firstBufferPtr = targetPtr->lastBufferPtr = NULL;
  343. targetPtr->nextPtr = dispPtr->clipTargetPtr;
  344. dispPtr->clipTargetPtr = targetPtr;
  345. Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  346. type, ClipboardHandler, (ClientData) targetPtr, format);
  347.     } else if (targetPtr->format != format) {
  348. Tcl_AppendResult(interp, "format "", Tk_GetAtomName(tkwin, format),
  349. "" does not match current format "",
  350. Tk_GetAtomName(tkwin, targetPtr->format),"" for ",
  351. Tk_GetAtomName(tkwin, type), (char *) NULL);
  352. return TCL_ERROR;
  353.     }
  354.     /*
  355.      * Append a new buffer to the buffer chain.
  356.      */
  357.     cbPtr = (TkClipboardBuffer*) ckalloc(sizeof(TkClipboardBuffer));
  358.     cbPtr->nextPtr = NULL;
  359.     if (targetPtr->lastBufferPtr != NULL) {
  360. targetPtr->lastBufferPtr->nextPtr = cbPtr;
  361.     } else {
  362. targetPtr->firstBufferPtr = cbPtr;
  363.     }
  364.     targetPtr->lastBufferPtr = cbPtr;
  365.     cbPtr->length = strlen(buffer);
  366.     cbPtr->buffer = (char *) ckalloc((unsigned) (cbPtr->length + 1));
  367.     strcpy(cbPtr->buffer, buffer);
  368.     TkSelUpdateClipboard((TkWindow*)(dispPtr->clipWindow), targetPtr);
  369.     return TCL_OK;
  370. }
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * Tk_ClipboardObjCmd --
  375.  *
  376.  * This procedure is invoked to process the "clipboard" Tcl
  377.  * command.  See the user documentation for details on what
  378.  * it does.
  379.  *
  380.  * Results:
  381.  * A standard Tcl result.
  382.  *
  383.  * Side effects:
  384.  * See the user documentation.
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388. int
  389. Tk_ClipboardObjCmd(clientData, interp, objc, objv)
  390.     ClientData clientData; /* Main window associated with
  391.  * interpreter. */
  392.     Tcl_Interp *interp; /* Current interpreter. */
  393.     int objc; /* Number of arguments. */
  394.     Tcl_Obj *CONST objv[]; /* Argument strings. */
  395. {
  396.     Tk_Window tkwin = (Tk_Window) clientData;
  397.     char *path = NULL;
  398.     Atom selection;
  399.     static CONST char *optionStrings[] = { "append", "clear", "get", NULL };
  400.     enum options { CLIPBOARD_APPEND, CLIPBOARD_CLEAR, CLIPBOARD_GET };
  401.     int index, i;
  402.     if (objc < 2) {
  403. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
  404. return TCL_ERROR;
  405.     }
  406.     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
  407.     &index) != TCL_OK) {
  408. return TCL_ERROR;
  409.     }
  410.     switch ((enum options) index) {
  411. case CLIPBOARD_APPEND: {
  412.     Atom target, format;
  413.     char *targetName = NULL;
  414.     char *formatName = NULL;
  415.     char *string;
  416.     static CONST char *appendOptionStrings[] = {
  417. "-displayof", "-format", "-type", NULL
  418.     };
  419.     enum appendOptions { APPEND_DISPLAYOF, APPEND_FORMAT,
  420.      APPEND_TYPE };
  421.     int subIndex, length;
  422.     
  423.     for (i = 2; i < objc - 1; i++) {
  424. string = Tcl_GetStringFromObj(objv[i], &length);
  425. if (string[0] != '-') {
  426.     break;
  427. }
  428. /*
  429.  * If the argument is "--", it signifies the end of arguments.
  430.  */
  431. if (string[1] == '-' && length == 2) {
  432.     i++;
  433.     break;
  434. }
  435. if (Tcl_GetIndexFromObj(interp, objv[i], appendOptionStrings,
  436. "option", 0, &subIndex) != TCL_OK) {
  437.     return TCL_ERROR;
  438. }
  439. /*
  440.  * Increment i so that it points to the value for the flag
  441.  * instead of the flag itself.
  442.  */
  443. i++;
  444. if (i >= objc) {
  445.     Tcl_AppendResult(interp, "value for "", string,
  446.     "" missing", (char *) NULL);
  447.     return TCL_ERROR;
  448. }
  449. switch ((enum appendOptions) subIndex) {
  450.     case APPEND_DISPLAYOF:
  451. path = Tcl_GetString(objv[i]);
  452. break;
  453.     case APPEND_FORMAT:
  454. formatName = Tcl_GetString(objv[i]);
  455. break;
  456.     case APPEND_TYPE:
  457. targetName = Tcl_GetString(objv[i]);
  458. break;
  459. }
  460.     }
  461.     if (objc - i != 1) {
  462. Tcl_WrongNumArgs(interp, 2, objv, "?options? data");
  463. return TCL_ERROR;
  464.     }
  465.     if (path != NULL) {
  466. tkwin = Tk_NameToWindow(interp, path, tkwin);
  467.     }
  468.     if (tkwin == NULL) {
  469. return TCL_ERROR;
  470.     }
  471.     if (targetName != NULL) {
  472. target = Tk_InternAtom(tkwin, targetName);
  473.     } else {
  474. target = XA_STRING;
  475.     }
  476.     if (formatName != NULL) {
  477. format = Tk_InternAtom(tkwin, formatName);
  478.     } else {
  479. format = XA_STRING;
  480.     }
  481.     return Tk_ClipboardAppend(interp, tkwin, target, format,
  482.     Tcl_GetString(objv[i]));
  483. }
  484. case CLIPBOARD_CLEAR: {
  485.     static CONST char *clearOptionStrings[] = { "-displayof", NULL };
  486.     enum clearOptions { CLEAR_DISPLAYOF };
  487.     int subIndex;
  488.     if (objc != 2 && objc != 4) {
  489. Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
  490. return TCL_ERROR;
  491.     }
  492.     if (objc == 4) {
  493. if (Tcl_GetIndexFromObj(interp, objv[2], clearOptionStrings,
  494. "option", 0, &subIndex) != TCL_OK) {
  495.     return TCL_ERROR;
  496. }
  497. if ((enum clearOptions) subIndex == CLEAR_DISPLAYOF) {
  498.     path = Tcl_GetString(objv[3]);
  499. }
  500.     }
  501.     if (path != NULL) {
  502. tkwin = Tk_NameToWindow(interp, path, tkwin);
  503.     }
  504.     if (tkwin == NULL) {
  505. return TCL_ERROR;
  506.     }
  507.     return Tk_ClipboardClear(interp, tkwin);
  508. }
  509. case CLIPBOARD_GET: {
  510.     Atom target;
  511.     char *targetName = NULL;
  512.     Tcl_DString selBytes;
  513.     int result;
  514.     char *string;
  515.     static CONST char *getOptionStrings[] = {
  516. "-displayof", "-type", NULL
  517.     };
  518.     enum getOptions { APPEND_DISPLAYOF, APPEND_TYPE };
  519.     int subIndex;
  520.     for (i = 2; i < objc; i++) {
  521. string = Tcl_GetString(objv[i]);
  522. if (string[0] != '-') {
  523.     break;
  524. }
  525. if (Tcl_GetIndexFromObj(interp, objv[i], getOptionStrings,
  526. "option", 0, &subIndex) != TCL_OK) {
  527.     return TCL_ERROR;
  528. }
  529. i++;
  530. if (i >= objc) {
  531.     Tcl_AppendResult(interp, "value for "", string,
  532.     "" missing", (char *) NULL);
  533.     return TCL_ERROR;
  534. }
  535. switch ((enum getOptions) subIndex) {
  536.     case APPEND_DISPLAYOF:
  537. path = Tcl_GetString(objv[i]);
  538. break;
  539.     case APPEND_TYPE:
  540. targetName = Tcl_GetString(objv[i]);
  541. break;
  542. }
  543.     }
  544.     if (path != NULL) {
  545. tkwin = Tk_NameToWindow(interp, path, tkwin);
  546.     }
  547.     if (tkwin == NULL) {
  548. return TCL_ERROR;
  549.     }
  550.     selection = Tk_InternAtom(tkwin, "CLIPBOARD");
  551.     if (objc - i > 1) {
  552. Tcl_WrongNumArgs(interp, 2, objv, "?options?");
  553. return TCL_ERROR;
  554.     } else if (objc - i == 1) {
  555. target = Tk_InternAtom(tkwin, Tcl_GetString(objv[i]));
  556.     } else if (targetName != NULL) {
  557. target = Tk_InternAtom(tkwin, targetName);
  558.     } else {
  559. target = XA_STRING;
  560.     }
  561.     Tcl_DStringInit(&selBytes);
  562.     result = Tk_GetSelection(interp, tkwin, selection, target,
  563.     ClipboardGetProc, (ClientData) &selBytes);
  564.     if (result == TCL_OK) {
  565. Tcl_DStringResult(interp, &selBytes);
  566.     } else {
  567. Tcl_DStringFree(&selBytes);
  568.     }
  569.     return result;
  570. }
  571.     }
  572.     return TCL_OK;
  573. }
  574. /*
  575.  *----------------------------------------------------------------------
  576.  *
  577.  * TkClipInit --
  578.  *
  579.  * This procedure is called to initialize the window for claiming
  580.  * clipboard ownership and for receiving selection get results.  This
  581.  * function is called from tkSelect.c as well as tkClipboard.c.
  582.  *
  583.  * Results:
  584.  * The result is a standard Tcl return value, which is normally TCL_OK.
  585.  * If an error occurs then an error message is left in the interp's
  586.  * result and TCL_ERROR is returned.
  587.  *
  588.  * Side effects:
  589.  * Sets up the clipWindow and related data structures.
  590.  *
  591.  *----------------------------------------------------------------------
  592.  */
  593. int
  594. TkClipInit(interp, dispPtr)
  595.     Tcl_Interp *interp; /* Interpreter to use for error
  596.  * reporting. */
  597.     register TkDisplay *dispPtr;/* Display to initialize. */
  598. {
  599.     XSetWindowAttributes atts;
  600.     dispPtr->clipTargetPtr = NULL;
  601.     dispPtr->clipboardActive = 0;
  602.     dispPtr->clipboardAppPtr = NULL;
  603.     
  604.     /*
  605.      * Create the window used for clipboard ownership and selection retrieval,
  606.      * and set up an event handler for it.
  607.      */
  608.     dispPtr->clipWindow = Tk_CreateWindow(interp, (Tk_Window) NULL,
  609.     "_clip", DisplayString(dispPtr->display));
  610.     if (dispPtr->clipWindow == NULL) {
  611. return TCL_ERROR;
  612.     }
  613.     Tcl_Preserve((ClientData) dispPtr->clipWindow);
  614.     atts.override_redirect = True;
  615.     Tk_ChangeWindowAttributes(dispPtr->clipWindow, CWOverrideRedirect, &atts);
  616.     Tk_MakeWindowExist(dispPtr->clipWindow);
  617.     if (dispPtr->multipleAtom == None) {
  618. /*
  619.  * Need to invoke selection initialization to make sure that
  620.  * atoms we depend on below are defined.
  621.  */
  622. TkSelInit(dispPtr->clipWindow);
  623.     }
  624.     /*
  625.      * Create selection handlers for types TK_APPLICATION and TK_WINDOW
  626.      * on this window.  Can't use the default handlers for these types
  627.      * because this isn't a full-fledged window.
  628.      */
  629.     Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  630.     dispPtr->applicationAtom, ClipboardAppHandler,
  631.     (ClientData) dispPtr, XA_STRING);
  632.     Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  633.     dispPtr->windowAtom, ClipboardWindowHandler,
  634.     (ClientData) dispPtr, XA_STRING);
  635.     return TCL_OK;
  636. }
  637. /*
  638.  *--------------------------------------------------------------
  639.  *
  640.  * ClipboardGetProc --
  641.  *
  642.  * This procedure is invoked to process pieces of the selection
  643.  * as they arrive during "clipboard get" commands.
  644.  *
  645.  * Results:
  646.  * Always returns TCL_OK.
  647.  *
  648.  * Side effects:
  649.  * Bytes get appended to the dynamic string pointed to by the
  650.  * clientData argument.
  651.  *
  652.  *--------------------------------------------------------------
  653.  */
  654. /* ARGSUSED */
  655. static int
  656. ClipboardGetProc(clientData, interp, portion)
  657.     ClientData clientData; /* Dynamic string holding partially
  658.  * assembled selection. */
  659.     Tcl_Interp *interp; /* Interpreter used for error
  660.  * reporting (not used). */
  661.     char *portion; /* New information to be appended. */
  662. {
  663.     Tcl_DStringAppend((Tcl_DString *) clientData, portion, -1);
  664.     return TCL_OK;
  665. }