/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkselect.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkselect.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.69  
changed lines
  Added in v.98

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25