1/* 2 * tkSelect.c -- 3 * 4 * This file manages the selection for the Tk toolkit, 5 * translating between the standard X ICCCM conventions 6 * and Tcl commands. 7 * 8 * Copyright (c) 1990-1993 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: tkSelect.c,v 1.13.2.1 2005/11/22 11:32:37 dkf Exp $ 15 */ 16 17#include "tkInt.h" 18#include "tkSelect.h" 19 20/* 21 * When a selection handler is set up by invoking "selection handle", 22 * one of the following data structures is set up to hold information 23 * about the command to invoke and its interpreter. 24 */ 25 26typedef struct { 27 Tcl_Interp *interp; /* Interpreter in which to invoke command. */ 28 int cmdLength; /* # of non-NULL bytes in command. */ 29 int charOffset; /* The offset of the next char to retrieve. */ 30 int byteOffset; /* The expected byte offset of the next 31 * chunk. */ 32 char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character 33 * that is split across chunks.*/ 34 char command[4]; /* Command to invoke. Actual space is 35 * allocated as large as necessary. This 36 * must be the last entry in the structure. */ 37} CommandInfo; 38 39/* 40 * When selection ownership is claimed with the "selection own" Tcl command, 41 * one of the following structures is created to record the Tcl command 42 * to be executed when the selection is lost again. 43 */ 44 45typedef struct LostCommand { 46 Tcl_Interp *interp; /* Interpreter in which to invoke command. */ 47 char command[4]; /* Command to invoke. Actual space is 48 * allocated as large as necessary. This 49 * must be the last entry in the structure. */ 50} LostCommand; 51 52/* 53 * The structure below is used to keep each thread's pending list 54 * separate. 55 */ 56 57typedef struct ThreadSpecificData { 58 TkSelInProgress *pendingPtr; 59 /* Topmost search in progress, or 60 * NULL if none. */ 61} ThreadSpecificData; 62static Tcl_ThreadDataKey dataKey; 63 64/* 65 * Forward declarations for procedures defined in this file: 66 */ 67 68static int HandleTclCommand _ANSI_ARGS_((ClientData clientData, 69 int offset, char *buffer, int maxBytes)); 70static void LostSelection _ANSI_ARGS_((ClientData clientData)); 71static int SelGetProc _ANSI_ARGS_((ClientData clientData, 72 Tcl_Interp *interp, char *portion)); 73 74/* 75 *-------------------------------------------------------------- 76 * 77 * Tk_CreateSelHandler -- 78 * 79 * This procedure is called to register a procedure 80 * as the handler for selection requests of a particular 81 * target type on a particular window for a particular 82 * selection. 83 * 84 * Results: 85 * None. 86 * 87 * Side effects: 88 * In the future, whenever the selection is in tkwin's 89 * window and someone requests the selection in the 90 * form given by target, proc will be invoked to provide 91 * part or all of the selection in the given form. If 92 * there was already a handler declared for the given 93 * window, target and selection type, then it is replaced. 94 * Proc should have the following form: 95 * 96 * int 97 * proc(clientData, offset, buffer, maxBytes) 98 * ClientData clientData; 99 * int offset; 100 * char *buffer; 101 * int maxBytes; 102 * { 103 * } 104 * 105 * The clientData argument to proc will be the same as 106 * the clientData argument to this procedure. The offset 107 * argument indicates which portion of the selection to 108 * return: skip the first offset bytes. Buffer is a 109 * pointer to an area in which to place the converted 110 * selection, and maxBytes gives the number of bytes 111 * available at buffer. Proc should place the selection 112 * in buffer as a string, and return a count of the number 113 * of bytes of selection actually placed in buffer (not 114 * including the terminating NULL character). If the 115 * return value equals maxBytes, this is a sign that there 116 * is probably still more selection information available. 117 * 118 *-------------------------------------------------------------- 119 */ 120 121void 122Tk_CreateSelHandler(tkwin, selection, target, proc, clientData, format) 123 Tk_Window tkwin; /* Token for window. */ 124 Atom selection; /* Selection to be handled. */ 125 Atom target; /* The kind of selection conversions 126 * that can be handled by proc, 127 * e.g. TARGETS or STRING. */ 128 Tk_SelectionProc *proc; /* Procedure to invoke to convert 129 * selection to type "target". */ 130 ClientData clientData; /* Value to pass to proc. */ 131 Atom format; /* Format in which the selection 132 * information should be returned to 133 * the requestor. XA_STRING is best by 134 * far, but anything listed in the ICCCM 135 * will be tolerated (blech). */ 136{ 137 register TkSelHandler *selPtr; 138 TkWindow *winPtr = (TkWindow *) tkwin; 139 140 if (winPtr->dispPtr->multipleAtom == None) { 141 TkSelInit(tkwin); 142 } 143 144 /* 145 * See if there's already a handler for this target and selection on 146 * this window. If so, re-use it. If not, create a new one. 147 */ 148 149 for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) { 150 if (selPtr == NULL) { 151 selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler)); 152 selPtr->nextPtr = winPtr->selHandlerList; 153 winPtr->selHandlerList = selPtr; 154 break; 155 } 156 if ((selPtr->selection == selection) && (selPtr->target == target)) { 157 158 /* 159 * Special case: when replacing handler created by 160 * "selection handle", free up memory. Should there be a 161 * callback to allow other clients to do this too? 162 */ 163 164 if (selPtr->proc == HandleTclCommand) { 165 ckfree((char *) selPtr->clientData); 166 } 167 break; 168 } 169 } 170 selPtr->selection = selection; 171 selPtr->target = target; 172 selPtr->format = format; 173 selPtr->proc = proc; 174 selPtr->clientData = clientData; 175 if (format == XA_STRING) { 176 selPtr->size = 8; 177 } else { 178 selPtr->size = 32; 179 } 180 181 if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) { 182 /* 183 * If the user asked for a STRING handler and we understand 184 * UTF8_STRING, we implicitly create a UTF8_STRING handler for them. 185 */ 186 187 target = winPtr->dispPtr->utf8Atom; 188 for (selPtr = winPtr->selHandlerList; ; 189 selPtr = selPtr->nextPtr) { 190 if (selPtr == NULL) { 191 selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler)); 192 selPtr->nextPtr = winPtr->selHandlerList; 193 winPtr->selHandlerList = selPtr; 194 selPtr->selection = selection; 195 selPtr->target = target; 196 selPtr->format = target; /* We want UTF8_STRING format */ 197 selPtr->proc = proc; 198 if (selPtr->proc == HandleTclCommand) { 199 /* 200 * The clientData is selection controlled memory, so 201 * we should make a copy for this selPtr. 202 */ 203 unsigned cmdInfoLen = sizeof(CommandInfo) + 204 ((CommandInfo*)clientData)->cmdLength - 3; 205 selPtr->clientData = (ClientData)ckalloc(cmdInfoLen); 206 memcpy(selPtr->clientData, clientData, cmdInfoLen); 207 } else { 208 selPtr->clientData = clientData; 209 } 210 selPtr->size = 8; 211 break; 212 } 213 if ((selPtr->selection == selection) 214 && (selPtr->target == target)) { 215 /* 216 * Looks like we had a utf-8 target already. Leave it alone. 217 */ 218 219 break; 220 } 221 } 222 } 223} 224 225/* 226 *---------------------------------------------------------------------- 227 * 228 * Tk_DeleteSelHandler -- 229 * 230 * Remove the selection handler for a given window, target, and 231 * selection, if it exists. 232 * 233 * Results: 234 * None. 235 * 236 * Side effects: 237 * The selection handler for tkwin and target is removed. If there 238 * is no such handler then nothing happens. 239 * 240 *---------------------------------------------------------------------- 241 */ 242 243void 244Tk_DeleteSelHandler(tkwin, selection, target) 245 Tk_Window tkwin; /* Token for window. */ 246 Atom selection; /* The selection whose handler 247 * is to be removed. */ 248 Atom target; /* The target whose selection 249 * handler is to be removed. */ 250{ 251 TkWindow *winPtr = (TkWindow *) tkwin; 252 register TkSelHandler *selPtr, *prevPtr; 253 register TkSelInProgress *ipPtr; 254 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 255 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 256 257 /* 258 * Find the selection handler to be deleted, or return if it doesn't 259 * exist. 260 */ 261 262 for (selPtr = winPtr->selHandlerList, prevPtr = NULL; ; 263 prevPtr = selPtr, selPtr = selPtr->nextPtr) { 264 if (selPtr == NULL) { 265 return; 266 } 267 if ((selPtr->selection == selection) && (selPtr->target == target)) { 268 break; 269 } 270 } 271 272 /* 273 * If ConvertSelection is processing this handler, tell it that the 274 * handler is dead. 275 */ 276 277 for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 278 ipPtr = ipPtr->nextPtr) { 279 if (ipPtr->selPtr == selPtr) { 280 ipPtr->selPtr = NULL; 281 } 282 } 283 284 /* 285 * Free resources associated with the handler. 286 */ 287 288 if (prevPtr == NULL) { 289 winPtr->selHandlerList = selPtr->nextPtr; 290 } else { 291 prevPtr->nextPtr = selPtr->nextPtr; 292 } 293 294 if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) { 295 /* 296 * If the user asked for a STRING handler and we understand 297 * UTF8_STRING, we may have implicitly created a UTF8_STRING handler 298 * for them. Look for it and delete it as necessary. 299 */ 300 TkSelHandler *utf8selPtr; 301 302 target = winPtr->dispPtr->utf8Atom; 303 for (utf8selPtr = winPtr->selHandlerList; utf8selPtr != NULL; 304 utf8selPtr = utf8selPtr->nextPtr) { 305 if ((utf8selPtr->selection == selection) 306 && (utf8selPtr->target == target)) { 307 break; 308 } 309 } 310 if (utf8selPtr != NULL) { 311 if ((utf8selPtr->format == target) 312 && (utf8selPtr->proc == selPtr->proc) 313 && (utf8selPtr->size == selPtr->size)) { 314 /* 315 * This recursive call is OK, because we've 316 * changed the value of 'target' 317 */ 318 Tk_DeleteSelHandler(tkwin, selection, target); 319 } 320 } 321 } 322 323 if (selPtr->proc == HandleTclCommand) { 324 /* 325 * Mark the CommandInfo as deleted and free it if we can. 326 */ 327 328 ((CommandInfo*)selPtr->clientData)->interp = NULL; 329 Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC); 330 } 331 ckfree((char *) selPtr); 332} 333 334/* 335 *-------------------------------------------------------------- 336 * 337 * Tk_OwnSelection -- 338 * 339 * Arrange for tkwin to become the owner of a selection. 340 * 341 * Results: 342 * None. 343 * 344 * Side effects: 345 * From now on, requests for the selection will be directed 346 * to procedures associated with tkwin (they must have been 347 * declared with calls to Tk_CreateSelHandler). When the 348 * selection is lost by this window, proc will be invoked 349 * (see the manual entry for details). This procedure may 350 * invoke callbacks, including Tcl scripts, so any calling 351 * function should be reentrant at the point where 352 * Tk_OwnSelection is invoked. 353 * 354 *-------------------------------------------------------------- 355 */ 356 357void 358Tk_OwnSelection(tkwin, selection, proc, clientData) 359 Tk_Window tkwin; /* Window to become new selection 360 * owner. */ 361 Atom selection; /* Selection that window should own. */ 362 Tk_LostSelProc *proc; /* Procedure to call when selection 363 * is taken away from tkwin. */ 364 ClientData clientData; /* Arbitrary one-word argument to 365 * pass to proc. */ 366{ 367 register TkWindow *winPtr = (TkWindow *) tkwin; 368 TkDisplay *dispPtr = winPtr->dispPtr; 369 TkSelectionInfo *infoPtr; 370 Tk_LostSelProc *clearProc = NULL; 371 ClientData clearData = NULL; /* Initialization needed only to 372 * prevent compiler warning. */ 373 374 375 if (dispPtr->multipleAtom == None) { 376 TkSelInit(tkwin); 377 } 378 Tk_MakeWindowExist(tkwin); 379 380 /* 381 * This code is somewhat tricky. First, we find the specified selection 382 * on the selection list. If the previous owner is in this process, and 383 * is a different window, then we need to invoke the clearProc. However, 384 * it's dangerous to call the clearProc right now, because it could 385 * invoke a Tcl script that wrecks the current state (e.g. it could 386 * delete the window). To be safe, defer the call until the end of the 387 * procedure when we no longer care about the state. 388 */ 389 390 for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; 391 infoPtr = infoPtr->nextPtr) { 392 if (infoPtr->selection == selection) { 393 break; 394 } 395 } 396 if (infoPtr == NULL) { 397 infoPtr = (TkSelectionInfo*) ckalloc(sizeof(TkSelectionInfo)); 398 infoPtr->selection = selection; 399 infoPtr->nextPtr = dispPtr->selectionInfoPtr; 400 dispPtr->selectionInfoPtr = infoPtr; 401 } else if (infoPtr->clearProc != NULL) { 402 if (infoPtr->owner != tkwin) { 403 clearProc = infoPtr->clearProc; 404 clearData = infoPtr->clearData; 405 } else if (infoPtr->clearProc == LostSelection) { 406 /* 407 * If the selection handler is one created by "selection own", 408 * be sure to free the record for it; otherwise there will be 409 * a memory leak. 410 */ 411 412 ckfree((char *) infoPtr->clearData); 413 } 414 } 415 416 infoPtr->owner = tkwin; 417 infoPtr->serial = NextRequest(winPtr->display); 418 infoPtr->clearProc = proc; 419 infoPtr->clearData = clientData; 420 421 /* 422 * Note that we are using CurrentTime, even though ICCCM recommends against 423 * this practice (the problem is that we don't necessarily have a valid 424 * time to use). We will not be able to retrieve a useful timestamp for 425 * the TIMESTAMP target later. 426 */ 427 428 infoPtr->time = CurrentTime; 429 430 /* 431 * Note that we are not checking to see if the selection claim succeeded. 432 * If the ownership does not change, then the clearProc may never be 433 * invoked, and we will return incorrect information when queried for the 434 * current selection owner. 435 */ 436 437 XSetSelectionOwner(winPtr->display, infoPtr->selection, winPtr->window, 438 infoPtr->time); 439 440 /* 441 * Now that we are done, we can invoke clearProc without running into 442 * reentrancy problems. 443 */ 444 445 if (clearProc != NULL) { 446 (*clearProc)(clearData); 447 } 448} 449 450/* 451 *---------------------------------------------------------------------- 452 * 453 * Tk_ClearSelection -- 454 * 455 * Eliminate the specified selection on tkwin's display, if there is one. 456 * 457 * Results: 458 * None. 459 * 460 * Side effects: 461 * The specified selection is cleared, so that future requests to retrieve 462 * it will fail until some application owns it again. This procedure 463 * invokes callbacks, possibly including Tcl scripts, so any calling 464 * function should be reentrant at the point Tk_ClearSelection is invoked. 465 * 466 *---------------------------------------------------------------------- 467 */ 468 469void 470Tk_ClearSelection(tkwin, selection) 471 Tk_Window tkwin; /* Window that selects a display. */ 472 Atom selection; /* Selection to be cancelled. */ 473{ 474 register TkWindow *winPtr = (TkWindow *) tkwin; 475 TkDisplay *dispPtr = winPtr->dispPtr; 476 TkSelectionInfo *infoPtr; 477 TkSelectionInfo *prevPtr; 478 TkSelectionInfo *nextPtr; 479 Tk_LostSelProc *clearProc = NULL; 480 ClientData clearData = NULL; /* Initialization needed only to 481 * prevent compiler warning. */ 482 483 if (dispPtr->multipleAtom == None) { 484 TkSelInit(tkwin); 485 } 486 487 for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL; 488 infoPtr != NULL; infoPtr = nextPtr) { 489 nextPtr = infoPtr->nextPtr; 490 if (infoPtr->selection == selection) { 491 if (prevPtr == NULL) { 492 dispPtr->selectionInfoPtr = nextPtr; 493 } else { 494 prevPtr->nextPtr = nextPtr; 495 } 496 break; 497 } 498 prevPtr = infoPtr; 499 } 500 501 if (infoPtr != NULL) { 502 clearProc = infoPtr->clearProc; 503 clearData = infoPtr->clearData; 504 ckfree((char *) infoPtr); 505 } 506 XSetSelectionOwner(winPtr->display, selection, None, CurrentTime); 507 508 if (clearProc != NULL) { 509 (*clearProc)(clearData); 510 } 511} 512 513/* 514 *-------------------------------------------------------------- 515 * 516 * Tk_GetSelection -- 517 * 518 * Retrieve the value of a selection and pass it off (in 519 * pieces, possibly) to a given procedure. 520 * 521 * Results: 522 * The return value is a standard Tcl return value. 523 * If an error occurs (such as no selection exists) 524 * then an error message is left in the interp's result. 525 * 526 * Side effects: 527 * The standard X11 protocols are used to retrieve the 528 * selection. When it arrives, it is passed to proc. If 529 * the selection is very large, it will be passed to proc 530 * in several pieces. Proc should have the following 531 * structure: 532 * 533 * int 534 * proc(clientData, interp, portion) 535 * ClientData clientData; 536 * Tcl_Interp *interp; 537 * char *portion; 538 * { 539 * } 540 * 541 * The interp and clientData arguments to proc will be the 542 * same as the corresponding arguments to Tk_GetSelection. 543 * The portion argument points to a character string 544 * containing part of the selection, and numBytes indicates 545 * the length of the portion, not including the terminating 546 * NULL character. If the selection arrives in several pieces, 547 * the "portion" arguments in separate calls will contain 548 * successive parts of the selection. Proc should normally 549 * return TCL_OK. If it detects an error then it should return 550 * TCL_ERROR and leave an error message in the interp's result; the 551 * remainder of the selection retrieval will be aborted. 552 * 553 *-------------------------------------------------------------- 554 */ 555 556int 557Tk_GetSelection(interp, tkwin, selection, target, proc, clientData) 558 Tcl_Interp *interp; /* Interpreter to use for reporting 559 * errors. */ 560 Tk_Window tkwin; /* Window on whose behalf to retrieve 561 * the selection (determines display 562 * from which to retrieve). */ 563 Atom selection; /* Selection to retrieve. */ 564 Atom target; /* Desired form in which selection 565 * is to be returned. */ 566 Tk_GetSelProc *proc; /* Procedure to call to process the 567 * selection, once it has been retrieved. */ 568 ClientData clientData; /* Arbitrary value to pass to proc. */ 569{ 570 TkWindow *winPtr = (TkWindow *) tkwin; 571 TkDisplay *dispPtr = winPtr->dispPtr; 572 TkSelectionInfo *infoPtr; 573 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 574 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 575 576 if (dispPtr->multipleAtom == None) { 577 TkSelInit(tkwin); 578 } 579 580 /* 581 * If the selection is owned by a window managed by this 582 * process, then call the retrieval procedure directly, 583 * rather than going through the X server (it's dangerous 584 * to go through the X server in this case because it could 585 * result in deadlock if an INCR-style selection results). 586 */ 587 588 for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; 589 infoPtr = infoPtr->nextPtr) { 590 if (infoPtr->selection == selection) 591 break; 592 } 593 if (infoPtr != NULL) { 594 register TkSelHandler *selPtr; 595 int offset, result, count; 596 char buffer[TK_SEL_BYTES_AT_ONCE+1]; 597 TkSelInProgress ip; 598 599 for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList; 600 selPtr != NULL; selPtr = selPtr->nextPtr) { 601 if ((selPtr->target == target) 602 && (selPtr->selection == selection)) { 603 break; 604 } 605 } 606 if (selPtr == NULL) { 607 Atom type; 608 609 count = TkSelDefaultSelection(infoPtr, target, buffer, 610 TK_SEL_BYTES_AT_ONCE, &type); 611 if (count > TK_SEL_BYTES_AT_ONCE) { 612 panic("selection handler returned too many bytes"); 613 } 614 if (count < 0) { 615 goto cantget; 616 } 617 buffer[count] = 0; 618 result = (*proc)(clientData, interp, buffer); 619 } else { 620 offset = 0; 621 result = TCL_OK; 622 ip.selPtr = selPtr; 623 ip.nextPtr = tsdPtr->pendingPtr; 624 tsdPtr->pendingPtr = &ip; 625 while (1) { 626 count = (selPtr->proc)(selPtr->clientData, offset, buffer, 627 TK_SEL_BYTES_AT_ONCE); 628 if ((count < 0) || (ip.selPtr == NULL)) { 629 tsdPtr->pendingPtr = ip.nextPtr; 630 goto cantget; 631 } 632 if (count > TK_SEL_BYTES_AT_ONCE) { 633 panic("selection handler returned too many bytes"); 634 } 635 buffer[count] = '\0'; 636 result = (*proc)(clientData, interp, buffer); 637 if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE) 638 || (ip.selPtr == NULL)) { 639 break; 640 } 641 offset += count; 642 } 643 tsdPtr->pendingPtr = ip.nextPtr; 644 } 645 return result; 646 } 647 648 /* 649 * The selection is owned by some other process. 650 */ 651 652 return TkSelGetSelection(interp, tkwin, selection, target, proc, 653 clientData); 654 655 cantget: 656 Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), 657 " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), 658 "\" not defined", (char *) NULL); 659 return TCL_ERROR; 660} 661 662/* 663 *-------------------------------------------------------------- 664 * 665 * Tk_SelectionObjCmd -- 666 * 667 * This procedure is invoked to process the "selection" Tcl 668 * command. See the user documentation for details on what 669 * it does. 670 * 671 * Results: 672 * A standard Tcl result. 673 * 674 * Side effects: 675 * See the user documentation. 676 * 677 *-------------------------------------------------------------- 678 */ 679 680int 681Tk_SelectionObjCmd(clientData, interp, objc, objv) 682 ClientData clientData; /* Main window associated with 683 * interpreter. */ 684 Tcl_Interp *interp; /* Current interpreter. */ 685 int objc; /* Number of arguments. */ 686 Tcl_Obj *CONST objv[]; /* Argument objects. */ 687{ 688 Tk_Window tkwin = (Tk_Window) clientData; 689 char *path = NULL; 690 Atom selection; 691 char *selName = NULL, *string; 692 int count, index; 693 Tcl_Obj **objs; 694 static CONST char *optionStrings[] = { 695 "clear", "get", "handle", "own", (char *) NULL 696 }; 697 enum options { SELECTION_CLEAR, SELECTION_GET, SELECTION_HANDLE, 698 SELECTION_OWN }; 699 700 if (objc < 2) { 701 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); 702 return TCL_ERROR; 703 } 704 705 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 706 &index) != TCL_OK) { 707 return TCL_ERROR; 708 } 709 710 switch ((enum options) index) { 711 case SELECTION_CLEAR: { 712 static CONST char *clearOptionStrings[] = { 713 "-displayof", "-selection", (char *) NULL 714 }; 715 enum clearOptions { CLEAR_DISPLAYOF, CLEAR_SELECTION }; 716 int clearIndex; 717 718 for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0; 719 count-=2, objs+=2) { 720 string = Tcl_GetString(objs[0]); 721 if (string[0] != '-') { 722 break; 723 } 724 if (count < 2) { 725 Tcl_AppendResult(interp, "value for \"", string, 726 "\" missing", (char *) NULL); 727 return TCL_ERROR; 728 } 729 730 if (Tcl_GetIndexFromObj(interp, objs[0], clearOptionStrings, 731 "option", 0, &clearIndex) != TCL_OK) { 732 return TCL_ERROR; 733 } 734 switch ((enum clearOptions) clearIndex) { 735 case CLEAR_DISPLAYOF: 736 path = Tcl_GetString(objs[1]); 737 break; 738 case CLEAR_SELECTION: 739 selName = Tcl_GetString(objs[1]); 740 break; 741 } 742 } 743 if (count == 1) { 744 path = Tcl_GetString(objs[0]); 745 } else if (count > 1) { 746 Tcl_WrongNumArgs(interp, 2, objv, "?options?"); 747 return TCL_ERROR; 748 } 749 if (path != NULL) { 750 tkwin = Tk_NameToWindow(interp, path, tkwin); 751 } 752 if (tkwin == NULL) { 753 return TCL_ERROR; 754 } 755 if (selName != NULL) { 756 selection = Tk_InternAtom(tkwin, selName); 757 } else { 758 selection = XA_PRIMARY; 759 } 760 761 Tk_ClearSelection(tkwin, selection); 762 break; 763 } 764 765 case SELECTION_GET: { 766 Atom target; 767 char *targetName = NULL; 768 Tcl_DString selBytes; 769 int result; 770 static CONST char *getOptionStrings[] = { 771 "-displayof", "-selection", "-type", (char *) NULL 772 }; 773 enum getOptions { GET_DISPLAYOF, GET_SELECTION, GET_TYPE }; 774 int getIndex; 775 776 for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count>0; 777 count-=2, objs+=2) { 778 string = Tcl_GetString(objs[0]); 779 if (string[0] != '-') { 780 break; 781 } 782 if (count < 2) { 783 Tcl_AppendResult(interp, "value for \"", string, 784 "\" missing", (char *) NULL); 785 return TCL_ERROR; 786 } 787 788 if (Tcl_GetIndexFromObj(interp, objs[0], getOptionStrings, 789 "option", 0, &getIndex) != TCL_OK) { 790 return TCL_ERROR; 791 } 792 793 switch ((enum getOptions) getIndex) { 794 case GET_DISPLAYOF: 795 path = Tcl_GetString(objs[1]); 796 break; 797 case GET_SELECTION: 798 selName = Tcl_GetString(objs[1]); 799 break; 800 case GET_TYPE: 801 targetName = Tcl_GetString(objs[1]); 802 break; 803 } 804 } 805 if (path != NULL) { 806 tkwin = Tk_NameToWindow(interp, path, tkwin); 807 } 808 if (tkwin == NULL) { 809 return TCL_ERROR; 810 } 811 if (selName != NULL) { 812 selection = Tk_InternAtom(tkwin, selName); 813 } else { 814 selection = XA_PRIMARY; 815 } 816 if (count > 1) { 817 Tcl_WrongNumArgs(interp, 2, objv, "?options?"); 818 return TCL_ERROR; 819 } else if (count == 1) { 820 target = Tk_InternAtom(tkwin, Tcl_GetString(objs[0])); 821 } else if (targetName != NULL) { 822 target = Tk_InternAtom(tkwin, targetName); 823 } else { 824 target = XA_STRING; 825 } 826 827 Tcl_DStringInit(&selBytes); 828 result = Tk_GetSelection(interp, tkwin, selection, target, 829 SelGetProc, (ClientData) &selBytes); 830 if (result == TCL_OK) { 831 Tcl_DStringResult(interp, &selBytes); 832 } else { 833 Tcl_DStringFree(&selBytes); 834 } 835 return result; 836 } 837 838 case SELECTION_HANDLE: { 839 Atom target, format; 840 char *targetName = NULL; 841 char *formatName = NULL; 842 register CommandInfo *cmdInfoPtr; 843 int cmdLength; 844 static CONST char *handleOptionStrings[] = { 845 "-format", "-selection", "-type", (char *) NULL 846 }; 847 enum handleOptions { HANDLE_FORMAT, HANDLE_SELECTION, 848 HANDLE_TYPE }; 849 int handleIndex; 850 851 for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0; 852 count-=2, objs+=2) { 853 string = Tcl_GetString(objs[0]); 854 if (string[0] != '-') { 855 break; 856 } 857 if (count < 2) { 858 Tcl_AppendResult(interp, "value for \"", string, 859 "\" missing", (char *) NULL); 860 return TCL_ERROR; 861 } 862 863 if (Tcl_GetIndexFromObj(interp, objs[0],handleOptionStrings, 864 "option", 0, &handleIndex) != TCL_OK) { 865 return TCL_ERROR; 866 } 867 868 switch ((enum handleOptions) handleIndex) { 869 case HANDLE_FORMAT: 870 formatName = Tcl_GetString(objs[1]); 871 break; 872 case HANDLE_SELECTION: 873 selName = Tcl_GetString(objs[1]); 874 break; 875 case HANDLE_TYPE: 876 targetName = Tcl_GetString(objs[1]); 877 break; 878 } 879 } 880 881 if ((count < 2) || (count > 4)) { 882 Tcl_WrongNumArgs(interp, 2, objv, "?options? window command"); 883 return TCL_ERROR; 884 } 885 tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin); 886 if (tkwin == NULL) { 887 return TCL_ERROR; 888 } 889 if (selName != NULL) { 890 selection = Tk_InternAtom(tkwin, selName); 891 } else { 892 selection = XA_PRIMARY; 893 } 894 895 if (count > 2) { 896 target = Tk_InternAtom(tkwin, Tcl_GetString(objs[2])); 897 } else if (targetName != NULL) { 898 target = Tk_InternAtom(tkwin, targetName); 899 } else { 900 target = XA_STRING; 901 } 902 if (count > 3) { 903 format = Tk_InternAtom(tkwin, Tcl_GetString(objs[3])); 904 } else if (formatName != NULL) { 905 format = Tk_InternAtom(tkwin, formatName); 906 } else { 907 format = XA_STRING; 908 } 909 string = Tcl_GetStringFromObj(objs[1], &cmdLength); 910 if (cmdLength == 0) { 911 Tk_DeleteSelHandler(tkwin, selection, target); 912 } else { 913 cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) ( 914 sizeof(CommandInfo) - 3 + cmdLength)); 915 cmdInfoPtr->interp = interp; 916 cmdInfoPtr->charOffset = 0; 917 cmdInfoPtr->byteOffset = 0; 918 cmdInfoPtr->buffer[0] = '\0'; 919 cmdInfoPtr->cmdLength = cmdLength; 920 strcpy(cmdInfoPtr->command, string); 921 Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand, 922 (ClientData) cmdInfoPtr, format); 923 } 924 return TCL_OK; 925 } 926 927 case SELECTION_OWN: { 928 register LostCommand *lostPtr; 929 char *script = NULL; 930 int cmdLength; 931 static CONST char *ownOptionStrings[] = { 932 "-command", "-displayof", "-selection", (char *) NULL 933 }; 934 enum ownOptions { OWN_COMMAND, OWN_DISPLAYOF, OWN_SELECTION }; 935 int ownIndex; 936 937 for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0; 938 count-=2, objs+=2) { 939 string = Tcl_GetString(objs[0]); 940 if (string[0] != '-') { 941 break; 942 } 943 if (count < 2) { 944 Tcl_AppendResult(interp, "value for \"", string, 945 "\" missing", (char *) NULL); 946 return TCL_ERROR; 947 } 948 949 if (Tcl_GetIndexFromObj(interp, objs[0], ownOptionStrings, 950 "option", 0, &ownIndex) != TCL_OK) { 951 return TCL_ERROR; 952 } 953 954 switch ((enum ownOptions) ownIndex) { 955 case OWN_COMMAND: 956 script = Tcl_GetString(objs[1]); 957 break; 958 case OWN_DISPLAYOF: 959 path = Tcl_GetString(objs[1]); 960 break; 961 case OWN_SELECTION: 962 selName = Tcl_GetString(objs[1]); 963 break; 964 } 965 } 966 967 if (count > 2) { 968 Tcl_WrongNumArgs(interp, 2, objv, "?options? ?window?"); 969 return TCL_ERROR; 970 } 971 if (selName != NULL) { 972 selection = Tk_InternAtom(tkwin, selName); 973 } else { 974 selection = XA_PRIMARY; 975 } 976 if (count == 0) { 977 TkSelectionInfo *infoPtr; 978 TkWindow *winPtr; 979 if (path != NULL) { 980 tkwin = Tk_NameToWindow(interp, path, tkwin); 981 } 982 if (tkwin == NULL) { 983 return TCL_ERROR; 984 } 985 winPtr = (TkWindow *)tkwin; 986 for (infoPtr = winPtr->dispPtr->selectionInfoPtr; 987 infoPtr != NULL; infoPtr = infoPtr->nextPtr) { 988 if (infoPtr->selection == selection) 989 break; 990 } 991 992 /* 993 * Ignore the internal clipboard window. 994 */ 995 996 if ((infoPtr != NULL) 997 && (infoPtr->owner != winPtr->dispPtr->clipWindow)) { 998 Tcl_SetResult(interp, Tk_PathName(infoPtr->owner), 999 TCL_STATIC); 1000 } 1001 return TCL_OK; 1002 } 1003 tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin); 1004 if (tkwin == NULL) { 1005 return TCL_ERROR; 1006 } 1007 if (count == 2) { 1008 script = Tcl_GetString(objs[1]); 1009 } 1010 if (script == NULL) { 1011 Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL, 1012 (ClientData) NULL); 1013 return TCL_OK; 1014 } 1015 cmdLength = strlen(script); 1016 lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand) 1017 -3 + cmdLength)); 1018 lostPtr->interp = interp; 1019 strcpy(lostPtr->command, script); 1020 Tk_OwnSelection(tkwin, selection, LostSelection, 1021 (ClientData) lostPtr); 1022 return TCL_OK; 1023 } 1024 } 1025 return TCL_OK; 1026} 1027 1028/* 1029 *---------------------------------------------------------------------- 1030 * 1031 * TkSelGetInProgress -- 1032 * 1033 * This procedure returns a pointer to the thread-local 1034 * list of pending searches. 1035 * 1036 * Results: 1037 * The return value is a pointer to the first search in progress, 1038 * or NULL if there are none. 1039 * 1040 * Side effects: 1041 * None. 1042 * 1043 *---------------------------------------------------------------------- 1044 */ 1045 1046TkSelInProgress * 1047TkSelGetInProgress _ANSI_ARGS_((void)) 1048{ 1049 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1050 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1051 1052 return tsdPtr->pendingPtr; 1053} 1054 1055/* 1056 *---------------------------------------------------------------------- 1057 * 1058 * TkSelSetInProgress -- 1059 * 1060 * This procedure is used to set the thread-local list of pending 1061 * searches. It is required because the pending list is kept 1062 * in thread local storage. 1063 * 1064 * Results: 1065 * None. 1066 * 1067 * Side effects: 1068 * None. 1069 * 1070 *---------------------------------------------------------------------- 1071 */ 1072void 1073TkSelSetInProgress(pendingPtr) 1074 TkSelInProgress *pendingPtr; 1075{ 1076 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1077 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1078 1079 tsdPtr->pendingPtr = pendingPtr; 1080} 1081 1082/* 1083 *---------------------------------------------------------------------- 1084 * 1085 * TkSelDeadWindow -- 1086 * 1087 * This procedure is invoked just before a TkWindow is deleted. 1088 * It performs selection-related cleanup. 1089 * 1090 * Results: 1091 * None. 1092 * 1093 * Side effects: 1094 * Frees up memory associated with the selection. 1095 * 1096 *---------------------------------------------------------------------- 1097 */ 1098 1099void 1100TkSelDeadWindow(winPtr) 1101 register TkWindow *winPtr; /* Window that's being deleted. */ 1102{ 1103 register TkSelHandler *selPtr; 1104 register TkSelInProgress *ipPtr; 1105 TkSelectionInfo *infoPtr, *prevPtr, *nextPtr; 1106 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1107 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1108 1109 /* 1110 * While deleting all the handlers, be careful to check whether 1111 * ConvertSelection or TkSelPropProc are about to process one of the 1112 * deleted handlers. 1113 */ 1114 1115 while (winPtr->selHandlerList != NULL) { 1116 selPtr = winPtr->selHandlerList; 1117 winPtr->selHandlerList = selPtr->nextPtr; 1118 for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 1119 ipPtr = ipPtr->nextPtr) { 1120 if (ipPtr->selPtr == selPtr) { 1121 ipPtr->selPtr = NULL; 1122 } 1123 } 1124 if (selPtr->proc == HandleTclCommand) { 1125 /* 1126 * Mark the CommandInfo as deleted and free it when we can. 1127 */ 1128 1129 ((CommandInfo*)selPtr->clientData)->interp = NULL; 1130 Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC); 1131 } 1132 ckfree((char *) selPtr); 1133 } 1134 1135 /* 1136 * Remove selections owned by window being deleted. 1137 */ 1138 1139 for (infoPtr = winPtr->dispPtr->selectionInfoPtr, prevPtr = NULL; 1140 infoPtr != NULL; infoPtr = nextPtr) { 1141 nextPtr = infoPtr->nextPtr; 1142 if (infoPtr->owner == (Tk_Window) winPtr) { 1143 if (infoPtr->clearProc == LostSelection) { 1144 ckfree((char *) infoPtr->clearData); 1145 } 1146 ckfree((char *) infoPtr); 1147 infoPtr = prevPtr; 1148 if (prevPtr == NULL) { 1149 winPtr->dispPtr->selectionInfoPtr = nextPtr; 1150 } else { 1151 prevPtr->nextPtr = nextPtr; 1152 } 1153 } 1154 prevPtr = infoPtr; 1155 } 1156} 1157 1158/* 1159 *---------------------------------------------------------------------- 1160 * 1161 * TkSelInit -- 1162 * 1163 * Initialize selection-related information for a display. 1164 * 1165 * Results: 1166 * None. 1167 * 1168 * Side effects: 1169 * Selection-related information is initialized. 1170 * 1171 *---------------------------------------------------------------------- 1172 */ 1173 1174void 1175TkSelInit(tkwin) 1176 Tk_Window tkwin; /* Window token (used to find 1177 * display to initialize). */ 1178{ 1179 register TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; 1180 1181 /* 1182 * Fetch commonly-used atoms. 1183 */ 1184 1185 dispPtr->multipleAtom = Tk_InternAtom(tkwin, "MULTIPLE"); 1186 dispPtr->incrAtom = Tk_InternAtom(tkwin, "INCR"); 1187 dispPtr->targetsAtom = Tk_InternAtom(tkwin, "TARGETS"); 1188 dispPtr->timestampAtom = Tk_InternAtom(tkwin, "TIMESTAMP"); 1189 dispPtr->textAtom = Tk_InternAtom(tkwin, "TEXT"); 1190 dispPtr->compoundTextAtom = Tk_InternAtom(tkwin, "COMPOUND_TEXT"); 1191 dispPtr->applicationAtom = Tk_InternAtom(tkwin, "TK_APPLICATION"); 1192 dispPtr->windowAtom = Tk_InternAtom(tkwin, "TK_WINDOW"); 1193 dispPtr->clipboardAtom = Tk_InternAtom(tkwin, "CLIPBOARD"); 1194 1195 /* 1196 * Using UTF8_STRING instead of the XA_UTF8_STRING macro allows us 1197 * to support older X servers that didn't have UTF8_STRING yet. 1198 * This is necessary on Unix systems. 1199 * For more information, see: 1200 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#x11 1201 */ 1202 1203#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK)) 1204 dispPtr->utf8Atom = Tk_InternAtom(tkwin, "UTF8_STRING"); 1205#else 1206 dispPtr->utf8Atom = (Atom) NULL; 1207#endif 1208} 1209 1210/* 1211 *---------------------------------------------------------------------- 1212 * 1213 * TkSelClearSelection -- 1214 * 1215 * This procedure is invoked to process a SelectionClear event. 1216 * 1217 * Results: 1218 * None. 1219 * 1220 * Side effects: 1221 * Invokes the clear procedure for the window which lost the 1222 * selection. 1223 * 1224 *---------------------------------------------------------------------- 1225 */ 1226 1227void 1228TkSelClearSelection(tkwin, eventPtr) 1229 Tk_Window tkwin; /* Window for which event was targeted. */ 1230 register XEvent *eventPtr; /* X SelectionClear event. */ 1231{ 1232 register TkWindow *winPtr = (TkWindow *) tkwin; 1233 TkDisplay *dispPtr = winPtr->dispPtr; 1234 TkSelectionInfo *infoPtr; 1235 TkSelectionInfo *prevPtr; 1236 1237 /* 1238 * Invoke clear procedure for window that just lost the selection. This 1239 * code is a bit tricky, because any callbacks due to selection changes 1240 * between windows managed by the process have already been made. Thus, 1241 * ignore the event unless it refers to the window that's currently the 1242 * selection owner and the event was generated after the server saw the 1243 * SetSelectionOwner request. 1244 */ 1245 1246 for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL; 1247 infoPtr != NULL; infoPtr = infoPtr->nextPtr) { 1248 if (infoPtr->selection == eventPtr->xselectionclear.selection) { 1249 break; 1250 } 1251 prevPtr = infoPtr; 1252 } 1253 1254 if (infoPtr != NULL && (infoPtr->owner == tkwin) 1255 && (eventPtr->xselectionclear.serial >= (unsigned) infoPtr->serial)) { 1256 if (prevPtr == NULL) { 1257 dispPtr->selectionInfoPtr = infoPtr->nextPtr; 1258 } else { 1259 prevPtr->nextPtr = infoPtr->nextPtr; 1260 } 1261 1262 /* 1263 * Because of reentrancy problems, calling clearProc must be done 1264 * after the infoPtr has been removed from the selectionInfoPtr 1265 * list (clearProc could modify the list, e.g. by creating 1266 * a new selection). 1267 */ 1268 1269 if (infoPtr->clearProc != NULL) { 1270 (*infoPtr->clearProc)(infoPtr->clearData); 1271 } 1272 ckfree((char *) infoPtr); 1273 } 1274} 1275 1276/* 1277 *-------------------------------------------------------------- 1278 * 1279 * SelGetProc -- 1280 * 1281 * This procedure is invoked to process pieces of the selection 1282 * as they arrive during "selection get" commands. 1283 * 1284 * Results: 1285 * Always returns TCL_OK. 1286 * 1287 * Side effects: 1288 * Bytes get appended to the dynamic string pointed to by the 1289 * clientData argument. 1290 * 1291 *-------------------------------------------------------------- 1292 */ 1293 1294 /* ARGSUSED */ 1295static int 1296SelGetProc(clientData, interp, portion) 1297 ClientData clientData; /* Dynamic string holding partially 1298 * assembled selection. */ 1299 Tcl_Interp *interp; /* Interpreter used for error 1300 * reporting (not used). */ 1301 char *portion; /* New information to be appended. */ 1302{ 1303 Tcl_DStringAppend((Tcl_DString *) clientData, portion, -1); 1304 return TCL_OK; 1305} 1306 1307/* 1308 *---------------------------------------------------------------------- 1309 * 1310 * HandleTclCommand -- 1311 * 1312 * This procedure acts as selection handler for handlers created 1313 * by the "selection handle" command. It invokes a Tcl command to 1314 * retrieve the selection. 1315 * 1316 * Results: 1317 * The return value is a count of the number of bytes actually 1318 * stored at buffer, or -1 if an error occurs while executing 1319 * the Tcl command to retrieve the selection. 1320 * 1321 * Side effects: 1322 * None except for things done by the Tcl command. 1323 * 1324 *---------------------------------------------------------------------- 1325 */ 1326 1327static int 1328HandleTclCommand(clientData, offset, buffer, maxBytes) 1329 ClientData clientData; /* Information about command to execute. */ 1330 int offset; /* Return selection bytes starting at this 1331 * offset. */ 1332 char *buffer; /* Place to store converted selection. */ 1333 int maxBytes; /* Maximum # of bytes to store at buffer. */ 1334{ 1335 CommandInfo *cmdInfoPtr = (CommandInfo *) clientData; 1336 int spaceNeeded, length; 1337#define MAX_STATIC_SIZE 100 1338 char staticSpace[MAX_STATIC_SIZE]; 1339 char *command, *string; 1340 Tcl_Interp *interp = cmdInfoPtr->interp; 1341 Tcl_DString oldResult; 1342 Tcl_Obj *objPtr; 1343 int extraBytes, charOffset, count, numChars; 1344 CONST char *p; 1345 1346 /* 1347 * We must also protect the interpreter and the command from being 1348 * deleted too soon. 1349 */ 1350 1351 Tcl_Preserve(clientData); 1352 Tcl_Preserve((ClientData) interp); 1353 1354 /* 1355 * Compute the proper byte offset in the case where the last chunk 1356 * split a character. 1357 */ 1358 1359 if (offset == cmdInfoPtr->byteOffset) { 1360 charOffset = cmdInfoPtr->charOffset; 1361 extraBytes = strlen(cmdInfoPtr->buffer); 1362 if (extraBytes > 0) { 1363 strcpy(buffer, cmdInfoPtr->buffer); 1364 maxBytes -= extraBytes; 1365 buffer += extraBytes; 1366 } 1367 } else { 1368 cmdInfoPtr->byteOffset = 0; 1369 cmdInfoPtr->charOffset = 0; 1370 extraBytes = 0; 1371 charOffset = 0; 1372 } 1373 1374 /* 1375 * First, generate a command by taking the command string 1376 * and appending the offset and maximum # of bytes. 1377 */ 1378 1379 spaceNeeded = cmdInfoPtr->cmdLength + 30; 1380 if (spaceNeeded < MAX_STATIC_SIZE) { 1381 command = staticSpace; 1382 } else { 1383 command = (char *) ckalloc((unsigned) spaceNeeded); 1384 } 1385 sprintf(command, "%s %d %d", cmdInfoPtr->command, charOffset, maxBytes); 1386 1387 /* 1388 * Execute the command. Be sure to restore the state of the 1389 * interpreter after executing the command. 1390 */ 1391 1392 Tcl_DStringInit(&oldResult); 1393 Tcl_DStringGetResult(interp, &oldResult); 1394 if (TkCopyAndGlobalEval(interp, command) == TCL_OK) { 1395 objPtr = Tcl_GetObjResult(interp); 1396 string = Tcl_GetStringFromObj(objPtr, &length); 1397 count = (length > maxBytes) ? maxBytes : length; 1398 memcpy((VOID *) buffer, (VOID *) string, (size_t) count); 1399 buffer[count] = '\0'; 1400 1401 /* 1402 * Update the partial character information for the next 1403 * retrieval if the command has not been deleted. 1404 */ 1405 1406 if (cmdInfoPtr->interp != NULL) { 1407 if (length <= maxBytes) { 1408 cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1); 1409 cmdInfoPtr->buffer[0] = '\0'; 1410 } else { 1411 p = string; 1412 string += count; 1413 numChars = 0; 1414 while (p < string) { 1415 p = Tcl_UtfNext(p); 1416 numChars++; 1417 } 1418 cmdInfoPtr->charOffset += numChars; 1419 length = p - string; 1420 if (length > 0) { 1421 strncpy(cmdInfoPtr->buffer, string, (size_t) length); 1422 } 1423 cmdInfoPtr->buffer[length] = '\0'; 1424 } 1425 cmdInfoPtr->byteOffset += count + extraBytes; 1426 } 1427 count += extraBytes; 1428 } else { 1429 count = -1; 1430 } 1431 Tcl_DStringResult(interp, &oldResult); 1432 1433 if (command != staticSpace) { 1434 ckfree(command); 1435 } 1436 1437 1438 Tcl_Release(clientData); 1439 Tcl_Release((ClientData) interp); 1440 return count; 1441} 1442 1443/* 1444 *---------------------------------------------------------------------- 1445 * 1446 * TkSelDefaultSelection -- 1447 * 1448 * This procedure is called to generate selection information 1449 * for a few standard targets such as TIMESTAMP and TARGETS. 1450 * It is invoked only if no handler has been declared by the 1451 * application. 1452 * 1453 * Results: 1454 * If "target" is a standard target understood by this procedure, 1455 * the selection is converted to that form and stored as a 1456 * character string in buffer. The type of the selection (e.g. 1457 * STRING or ATOM) is stored in *typePtr, and the return value is 1458 * a count of the # of non-NULL bytes at buffer. If the target 1459 * wasn't understood, or if there isn't enough space at buffer 1460 * to hold the entire selection (no INCR-mode transfers for this 1461 * stuff!), then -1 is returned. 1462 * 1463 * Side effects: 1464 * None. 1465 * 1466 *---------------------------------------------------------------------- 1467 */ 1468 1469int 1470TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr) 1471 TkSelectionInfo *infoPtr; /* Info about selection being retrieved. */ 1472 Atom target; /* Desired form of selection. */ 1473 char *buffer; /* Place to put selection characters. */ 1474 int maxBytes; /* Maximum # of bytes to store at buffer. */ 1475 Atom *typePtr; /* Store here the type of the selection, 1476 * for use in converting to proper X format. */ 1477{ 1478 register TkWindow *winPtr = (TkWindow *) infoPtr->owner; 1479 TkDisplay *dispPtr = winPtr->dispPtr; 1480 1481 if (target == dispPtr->timestampAtom) { 1482 if (maxBytes < 20) { 1483 return -1; 1484 } 1485 sprintf(buffer, "0x%x", (unsigned int) infoPtr->time); 1486 *typePtr = XA_INTEGER; 1487 return strlen(buffer); 1488 } 1489 1490 if (target == dispPtr->targetsAtom) { 1491 register TkSelHandler *selPtr; 1492 int length; 1493 Tcl_DString ds; 1494 1495 if (maxBytes < 50) { 1496 return -1; 1497 } 1498 Tcl_DStringInit(&ds); 1499 Tcl_DStringAppend(&ds, 1500 "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW", -1); 1501 for (selPtr = winPtr->selHandlerList; selPtr != NULL; 1502 selPtr = selPtr->nextPtr) { 1503 if ((selPtr->selection == infoPtr->selection) 1504 && (selPtr->target != dispPtr->applicationAtom) 1505 && (selPtr->target != dispPtr->windowAtom)) { 1506 CONST char *atomString = Tk_GetAtomName((Tk_Window) winPtr, 1507 selPtr->target); 1508 Tcl_DStringAppendElement(&ds, atomString); 1509 } 1510 } 1511 length = Tcl_DStringLength(&ds); 1512 if (length >= maxBytes) { 1513 Tcl_DStringFree(&ds); 1514 return -1; 1515 } 1516 memcpy(buffer, Tcl_DStringValue(&ds), (unsigned) (1+length)); 1517 Tcl_DStringFree(&ds); 1518 *typePtr = XA_ATOM; 1519 return length; 1520 } 1521 1522 if (target == dispPtr->applicationAtom) { 1523 int length; 1524 Tk_Uid name = winPtr->mainPtr->winPtr->nameUid; 1525 1526 length = strlen(name); 1527 if (maxBytes <= length) { 1528 return -1; 1529 } 1530 strcpy(buffer, name); 1531 *typePtr = XA_STRING; 1532 return length; 1533 } 1534 1535 if (target == dispPtr->windowAtom) { 1536 int length; 1537 char *name = winPtr->pathName; 1538 1539 length = strlen(name); 1540 if (maxBytes <= length) { 1541 return -1; 1542 } 1543 strcpy(buffer, name); 1544 *typePtr = XA_STRING; 1545 return length; 1546 } 1547 1548 return -1; 1549} 1550 1551/* 1552 *---------------------------------------------------------------------- 1553 * 1554 * LostSelection -- 1555 * 1556 * This procedure is invoked when a window has lost ownership of 1557 * the selection and the ownership was claimed with the command 1558 * "selection own". 1559 * 1560 * Results: 1561 * None. 1562 * 1563 * Side effects: 1564 * A Tcl script is executed; it can do almost anything. 1565 * 1566 *---------------------------------------------------------------------- 1567 */ 1568 1569static void 1570LostSelection(clientData) 1571 ClientData clientData; /* Pointer to LostCommand structure. */ 1572{ 1573 LostCommand *lostPtr = (LostCommand *) clientData; 1574 Tcl_Obj *objPtr; 1575 Tcl_Interp *interp; 1576 1577 interp = lostPtr->interp; 1578 Tcl_Preserve((ClientData) interp); 1579 1580 /* 1581 * Execute the command. Save the interpreter's result, if any, and 1582 * restore it after executing the command. 1583 */ 1584 1585 objPtr = Tcl_GetObjResult(interp); 1586 Tcl_IncrRefCount(objPtr); 1587 Tcl_ResetResult(interp); 1588 1589 if (TkCopyAndGlobalEval(interp, lostPtr->command) != TCL_OK) { 1590 Tcl_BackgroundError(interp); 1591 } 1592 1593 Tcl_SetObjResult(interp, objPtr); 1594 Tcl_DecrRefCount(objPtr); 1595 1596 Tcl_Release((ClientData) interp); 1597 1598 /* 1599 * Free the storage for the command, since we're done with it now. 1600 */ 1601 1602 ckfree((char *) lostPtr); 1603} 1604