/[dtapublic]/to_be_filed/sf_code/esrgpcpj/shared/tk_base/tkselect.c
ViewVC logotype

Contents of /to_be_filed/sf_code/esrgpcpj/shared/tk_base/tkselect.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25