REF XT_CALLBACK Adrian Howard Sep 92 COPYRIGHT University of Sussex 1991. All Rights Reserved. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< MANAGEMENT OF CALLBACK >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< PROCEDURES >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< External callbacks occur when functions outside Poplog "call back" to Poplog procedures. How such situations are handled by Pop-11 in general is fully explained in REF * EXTERNAL and REF * EXTERNAL_DATA. This file describes the generic procedures provided by the Poplog X interface for handling external callbacks in the toolkit. It also details the Pop-11 interface to the toolkit intrinsics relating to toolkit "callback" procedures. CONTENTS - (Use g to access required sections) 1 Introduction 2 Generic External Callbacks Under The Poplog X Interface 3 The Poplog Interface to X Toolkit Callback Management 4 The Format Of Toolkit Callback Procedures 5 LIB XT_CALLBACK 5.1 The XptCallbackRec Structure 5.2 The XptCallbackPtr Shadowclass 5.3 The XptCallbackList Shadowclass 5.4 Procedures For Toolkit Callback Management 6 LIB FAST_XT_CALLBACK 7 Possible Problems With Default External Callback Coercion --------------- 1 Introduction --------------- Many X toolkit intrinsics take, as one of their arguments, a procedure which will be called by the toolkit at a later date. Among these are "callback" procedures, "action hook" procedures, and "type converter" procedures. If the user wishes to pass a Pop-11 procedure, it must be converted into a suitable "external" form first. The Poplog X Interface tries to make these coercions as easy as possible and provides many convenience procedures for the different external callback types in the toolkit. These procedures operate via the external callback mechanisms explained in REF * EXTERNAL and REF * EXTERNAL_DATA. For details of the other libraries in the Poplog X interface that use external callbacks see REF * XT_UTIL, REF * XT_ACTION, REF * XT_CONVERTER, REF * XT_KEYBOARD, and REF * XT_EVENT. ---------------------------------------------------------- 2 Generic External Callbacks Under The Poplog X Interface ---------------------------------------------------------- To enable easier debugging and tracing, all the external callbacks to Pop-11 procedures used in the Poplog interface to the X toolkit use a single calling mechanism. The default calling mechanism can be summarised as follows. X INTRINSICS || \/ EXTERNAL FUNCTION CLOSURE A procedure created by Pop-11 that can be directly executed by the intrinsics || \/ CLOSURE OF A WRAPPER PROCEDURE Each callback type has its own wrapper procedure, eg XptCallbackWrapper || \/ XptCallbackHandler || (Possible tracing calls via XptTraceCallback) \/ XptApplyCallback || \/ Pop-11 PROCEDURE The external function closures are created by procedures with the prefix "XptExport" (eg, XptExportTypedCallback). The above mechanism is explained in more detail below. XptCallbackHandler(widentproc, type) [variable procedure] All external callback procedures used in the Poplog X interface call this procedure to execute user supplied Pop-11 callback procedures. By default this procedure prints the tracing information indicated by XptTraceCallback, and then applies XptApplyCallback to the procedure referred to by widentproc. When XptCallbackHandler is called widentproc should either be a Pop-11 procedure, an ident whose idval is a procedure, or a word whose valof is a procedure. type should be a Pop-11 item which indicates the type of external callback which caused XptCallbackHandler to be executed. Currently type is one of the following words: Word Procedure Type ---- -------------- action Action procedures (REF * XT_ACTION) actionhook ActionHook procedures (REF * XT_ACTION) callback Callback procedures, detailed in this file. case_proc CaseProc procedures (REF * XT_KEYBOARD) convert_arg_proc ConvertArgProc procedures (REF * XT_EVENT) destructor Destructor procedures (REF * XT_CONVERTER) event EventHandler procedures (REF * XT_EVENT) file_predicate FilePredicate procedures (REF * XT_UTIL) input Input procedures. see REF * XT_EVENT) key_proc KeyProc procedures (REF * XT_KEYBOARD) timeout TimeOut procedures (REF * XT_EVENT) type_converter TypeConverter procedures (REF *XT_CONVERTER) The value of type is currently only used for trace information. Care should be taken when altering this procedure to ensure that widentproc is appropriately handled in all cases. It is an error for XptCallbackHandler to leave items on the user stack when it returns. XptTraceCallback -> bool_or_list_or_p [variable] bool_or_list_or_p -> XptTraceCallback The value of this variable controls the tracing information displayed by XptCallbackHandler. If its value is false (the default) then no tracing information is displayed. If its value is true than tracing information is displayed for all callbacks. If the variable is a list, then tracing information is displayed on all callbacks whose type (as passed to XptCallbackHandler) is a member of that list. For example: [callback action] -> XptTraceCallback; would only print trace information on callback and action procedures. The default trace procedure produces a trace message of the following form: ;;; type: p(arg1, ..., argn) where type is the value of the type argument, p is the pdprops of the procedure about to be called, and arg1, ..., argn are the arguments to be passed to it. If the pdprops of the procedure is , no trace output is generated. If the variable cuchartrace contains a procedure, it is used as the character consumer for the trace output (that is, it is locally assigned to cucharout). See REF * cuchartrace for more details. If the variable is not a boolean or a list, it should be a procedure of the form: procedure(item_1, item_2, ..., item_n, n, p, type) This procedure should print trace information in an appropriate manner, overriding the default output described above. type is the type of callback which caused the call to XptCallbackHandler (see XptCallbackHandler for possible values). p is the procedure that will be called by XptCallbackHandler, n is the number of arguments p will take, and item_1 to item_n are the arguments themselves. It is an error for the tracing procedure to leave items on the user stack. XptApplyCallback -> false_or_p [variable] false_or_p -> XptApplyCallback The value of this variable is used by XptCallbackHandler to actually invoke the Pop-11 callback procedures specified by the user (after tracing if enabled), and so allows a localising context for all calls to be established. If XptApplyCallback is a procedure p, it is called as: p(arg_1, arg2, ..., arg_n, procedure) A value of false (the default) is equivalent to assigning fast_apply to the variable. It is an error for XptApplyCallback to leave items on the stack. XptCallbackFlags -> pef_return_abexit_next [macro] This holds a bit mask of status flags that is or-ed with pop_external_flags (see REF * EXTERNAL) before an X toolkit external callback procedure is executed. The value pef_return_abexit_next (see REF * EXTERNAL) will cause the callback to return after an abnormal exit. The value of this macro is used as the flags argument when the XptExport- procedures create external function closures using exfunc_export. -------------------------------------------------------- 3 The Poplog Interface to X Toolkit Callback Management -------------------------------------------------------- Applications have the ability to register procedures with a widget that get called under certain conditions. These procedures are called "callback" procedures, and they are added to different "callback lists". For example, every procedure on a widgets 'destroyCallback' callback list is called when that widget is destroyed. Different widgets have different callback lists depending on their function. For example a scrollbar widget could have callback list whose procedures are executed when the scrollbar is moved. Different callback lists are identified with strings. The XtN macro can be used to express these strings in a similar way to the C code in the toolkit intrinsics, eg, doing: XtN destroyCallback would be the same as using the macro "XtNdestroyCallback" in C. When a callback procedure is added to a widgets callback list, a piece of "client data" is also added which can be anything the user wishes. This is passed to the callback procedure every time it is executed. In addition to the client data, some "call data" is also passed to the callback procedure when it is executed. What this call data represents is dependent on the type of callback. With a scrollbar callback it might, for example, represent the position of the thumb on the scrollbar. The library LIB * XT_CALLBACK provides the Pop-11 interface to the various X Toolkit Intrinsics related to the management of callbacks, plus support for related data structures. LIB * FAST_XT_CALLBACK (loaded automatically by LIB * XT_CALLBACK) provides the non-checking Pop-11 interface to the same procedures. These libraries give the user the ability to perform the following functions: o Adding callback procedures to a widgets callback list. o Removing callback procedures from a widgets callback list. o Explicit execution of a callback procedure. o Testing the status of a widgets callback list. For full details of the exact structure of arguments and results for the following procedures, see REF * XPT_TYPES and the following sections. For more details of callbacks see chapter 8 of: X Toolkit Intrinsics - C Language Interface X Window System X Version 11, Release 4 Copyright (C) 1985, 1986, 1987, 1988, Massachusetts Institute of Technology, Cambridge, Massachusetts, and Digital Equipment Corporation, Maynard, Massachusetts. -------------------------------------------- 4 The Format Of Toolkit Callback Procedures -------------------------------------------- Many of the procedures in LIB * XT_CALLBACK and * FAST_XT_CALLBACK take callback procedure/client-data pairs. These are either appropriate external procedure/client-data pairs, or Pop-11 procedure/client-data pairs that are coerced with the XptExport(Typed)Callback(Cached) procedures. External procedures should be external function closures (for details see REF * EXTERNAL), or of the type XptProcedure. The external procedures should expect to be called in the same format as the following C function prototype: typedef void (*XtCallbackProc)(Widget, XtPointer, XtPointer); When the procedure is executed "Widget" will be the widget the callback was registered on, the first "XtPointer" will refer to the client data the callback was registered with, and the second "XtPointer" will refer to the call data the callback was executed with. As with all handling of external objects in Pop-11, care must be taken with garbage collection (see REF * EXTERNAL_DATA). A Pop-11 callback procedure should expect to be called as follows: p(widget, client_data, call_data) Where widget is the widget the callback was registered on, client_data is the arbitrary Pop-11 object the callback was registered with, and call_data is an external pointer that contains the call data as its pointer value (unless this has already been converted to the actual data by specifying a conversion procedure, see XptAddCallback below). It is an error for toolkit callback procedures to return items on the stack. Care must be taken when using Pop-11 callback procedures. It must be remembered that the Pop-11 procedure is NOT what is registered with the intrinsics, the COERCED procedure is. Thus, when you want to add and then remove a callback, you must ensure that you refer to the same COERCED procedure, not merely the same Pop procedure. This can be done by explicitly keeping track of the external procedure returned by the procedures XptExportCallback and XptExportTypedCallback, or by using the caching coercion procedures XptExportCallbackCached and XptExportTypedCallbackCached. This is done for you in most cases since the default coercion done by the procedures in LIB * XT_CALLBACK uses the caching coercion procedures. ------------------ 5 LIB XT_CALLBACK ------------------ The following sections describe the facilities provided by the library LIB * XT_CALLBACK. 5.1 The XptCallbackRec Structure --------------------------------- LIB * XT_CALLBACK provides support for the XptCallbackRec structure with the two shadowclasses XptCallbackPtr and XptCallbackList. These represent pointers to single and multiple instances of XptCallbackRec structures. Each XptCallbackRec structure consists of a callback procedure and a pointer to some client data. See REF * XPT_GENERALTYPES for details of the XptCallbackRec typespec. 5.2 The XptCallbackPtr Shadowclass ----------------------------------- initXptCallbackPtr() -> callbackptr [procedure] Initialise a new XptCallbackPtr shadowclass record pointing to an XptCallbackRec structure with a false (null) callback procedure and a null external pointer as client data. fillXptCallbackPtr(xptprocedure, xptpointer, callbackptr) [procedure] -> callbackptr Takes an instance of an XptCallbackPtr shadowclass record callbackptr, updates the XptCallbackRec it points to with the given callback procedure xptprocedure and client data xptpointer. The updated callbackptr is then returned. consXptCallbackPtr(xptprocedure, xptpointer) -> callbackptr [procedure] Constructs an instance of an XptCallbackPtr shadowclass record pointing to an XptCallbackRec with callback procedure xptprocedure and client data xptpointer. destXptCallbackPtr(callbackptr) -> (xptprocedure,xptpointer) [procedure] Given an XptCallbackPtr shadowclass record, returns the callback procedure and client data of the XptCallbackRec it points to. XptCRCallback(callbackptr) -> xptprocedure [procedure] xptprocedure -> XptCRCallback(callbackptr) Returns or updates the callback procedure of the XptCallbackRec pointed to by the XptCallbackPtr callbackptr. XptCRClosure(callbackptr) -> xptpointer [procedure] xptpointer -> XptCRClosure(callbackptr) Returns or updates the client data of the XptCallbackRec pointed to by the XptCallbackPtr callbackptr. isXptCallbackPtr(item) -> bool [procedure] Returns true if item is a XptCallbackPtr shadowclass record, false otherwise. refreshXptCallbackPtr(callbackptr) -> callbackptr [procedure] "Refreshes" the XptCallbackPtr shadowclass record callbackptr from its external representation, returning the refreshed record. See REF * SHADOWCLASS for details of refreshing shadowclass records. IMPORTANT NOTE: Refreshing callbackptr will cause it to lose any references to Poplog objects contained in its callback procedure and client data fields. A separate reference will have to be kept to any Poplog objects to prevent them being garbage collected during the lifetime of callbackptr. importXptCallbackPtr(exptrclass) -> callbackptr [procedure] Takes an external pointer class record that points to an XptCallbackRec structure, and returns the shadowclass instance referring to that structure (creating it if necessary). XptCallbackPtr_shadowkey -> shkey [shadowkey] The shadowkey for XptCallbackPtr shadowclass records. For details on shadowkeys see REF * SHADOWCLASS. 5.3 The XptCallbackList Shadowclass ------------------------------------ All XptCallbackList shadowclass records have their external_ptr_props set to the constant XDT_CALLBACKLIST to enable "weak" type checking. See REF * XptDescriptor and * XPT_CONSTANTS for more details. initXptCallbackList(n) -> callbacklist [procedure] Construct an XptCallbackList consisting of n XptCallbackRec structures. Each XptCallbackRec will contain a false (null) callback procedure and a null external pointer as client data. fillXptCallbackList(callbackptr_1, ..., callbackptr_n, [procedure] callbacklist) -> callbacklist Copies the contents of the XptCallbackRec structures, pointed to by the N XptCallbackPtr records, into callbacklist. callbacklist, with its new contents, is returned as the result. callbacklist must be an N element XptCallbackList shadowclass structure. Callback lists are normally null-terminated which means that callbackptr_n should point to a null XptCallbackRec structure (such as the XptCallbackRec pointed to by a XptCallbackPtr returned by initXptCallbackPtr). consXptCallbackList(callbackptr_1, ..., callbackptr_n, n) [procedure] -> callbacklist Construct an n element XptCallbackList shadowclass structure by copying the contents of the XptCallbackRec structures pointed to by the top n elements of the stack (which all must be XptCallbackPtr shadowclass records). Callback lists are normally null-terminated which means that callbackptr_n should point to a null XptCallbackRec structure (such as the XptCallbackRec structure pointed to by a XptCallbackPtr returned by initXptCallbackPtr). destXptCallbackList(callbacklist) [procedure] -> (callbackptr_1, ..., callbackptr_n, n) This procedure returns an XptCallbackPtr record for every XptCallbackRec structure in callbacklist, plus the number of structures n in that list. callbacklist is an n element XptCallbackList structure. NOTE: The XptCallbackPtr structures returned refer to COPIES of the items in callbacklist, not the items themselves. Changing CALLBACKPTR_X will NOT alter callbacklist. See REF * SHADOWCLASS for a more detailed explanation. subscrXptCallbackList(n, callbacklist) -> callbackptr [procedure] callbackptr -> subscrXptCallbackList(n, callbacklist) Returns an XptCallbackPtr record callbackptr for the Nth XptCallbackRec structure in the XptCallbackList callbacklist. NOTE: callbackptr refers to a COPY of the XptCallbackRec in callbacklist. Changing callbackptr will NOT alter callbacklist. See REF * SHADOWCLASS for a more detailed explanation. isXptCallbackList(item) -> bool [procedure] Returns true if item is an instance of an XptCallbackPtr shadowclass vector. refreshXptCallbackList(callbacklist) -> callbacklist [procedure] "Refreshes" the XptCallbackList shadowclass structure callbacklist from its external representation, returning the refreshed structure. See REF * SHADOWCLASS for details of refreshing Pop-11 representations from external representations. IMPORTANT NOTE: Refreshing callbacklist will cause it to lose reference to any Pop-11 objects it contains. Separate references will need to be kept if the objects are not to become garbage. importXptCallbackList(exptrclass, n) -> callbacklist [procedure] Takes an external pointer class record pointing to a series of n XptCallbackRec structures, and returns the XptCallbackList referring to those same structures (creating it if necessary). XptCallbackList_shadowkey -> shkey [shadowkey] The shadowkey for XptCallbackPtr shadowclass vectors. For details see REF * SHADOWCLASS. 5.4 Procedures For Toolkit Callback Management ----------------------------------------------- XptAddCallback(widget, string, widentproc, client_data, [procedure] conversion_p) Add a callback procedure widentproc to the callback list named string of the widget widget, passing client data client_data. If widentproc is a Pop-11 word, ident, or procedure, it, and client_data, are coerced automatically into a suitable external form with XptExportCallbackCached. A reference to the (possible coerced) callback procedure is kept by the widget widget so it cannot become garbage during the lifetime of the widget. If conversion_p is not false, it must be a procedure, and this will be run on the external pointer containing the call_data value to the callback. For example, if the call_data is an integer, a suitable conversion_p would be int_from_ptr as defined by defexacc int_from_ptr ^int; (Note that the call_data external pointer doesn't POINT to the value, it CONTAINS it. Thus the correct type-spec for int_from_ptr is ^int, not :int.) Note also that without a conversion procedure, a new external pointer will be constructed for each callback, whereas if conversion_p is supplied, it is given a fixed (i.e. constant) external pointer record (see * XptCallbackWrapper below). Unless the call_data value is actually a pointer to something, it is always preferable to supply a conversion_p, since then no new pointer is constructed, and tracing a callback with XptTraceCallback will show the actual value. (Specifying identfn for conversion_p is a way to stop new pointers being constructed without actually doing any conversion.) XtAddCallback(widget, string, widentproc, client_data) [procedure] This procedure is just XptAddCallback(% false %) that is, XptAddCallback with a false conversion_p argument. XtAddCallbacks(widget, string, callbacklist) [procedure] Adds the list of callback procedure/data pairs held in the XptCallbackList callbacklist to the callback list named string of the widget widget. IMPORTANT NOTE: the system will NOT automatically coerce Pop-11 structures into an external form when this routine is used. It is also the USERS RESPONSIBILITY to prevent callbacklist becoming garbage. XptAddCallbackList(widget, string, list) [procedure] Adds a list of callback procedure/data pairs, specified by the Pop-11 list list, to the callback list named string of the widget widget. list is of the form: [ [widentproc1 data1] [widentproc2 data2] ...] Pop-11 words, idents, and procedures are coerced to external forms where necessary, along with their associated data, using XptExportCallbackCached. A reference to the (possible coerced) callback procedures are kept by the widget widget so they cannot become garbage during the lifetime of the widget. Each element of list may also be of the form [widentproc data conversion_p] to specify a conversion procedure for the call_data argument to the callback. XtRemoveAllCallbacks(widget, string) [procedure] Removes all callbacks in the callback list named string from the widget widget. It is not an error for the specified callback list to be empty when XtRemoveAllCallbacks is called. XtRemoveCallback(widget, string, widentproc, client_data) [procedure] Remove the callback instance specified by widentproc and client_data from the callback list named string of widget widget. If widentproc is a Pop-11 word, ident, or procedure, it (and client_data are coerced automatically into a suitable external form with XptExportCallbackCached. No error will be given if the widentproc/client_data pair does not exist in the callback list. XtRemoveCallbacks(widget, string, callbacklist) [procedure] Removes a list of callbacks, specified by the XptCallbackList shadowclass structure callbacklist, from the callback list named string of the widget widget. No errors will be given if any of the specified callback/client-data pairs do not exist in the callback list. IMPORTANT NOTE: the system will NOT automatically coerce Pop-11 structures into an appropriate external form when this routine is used. XptRemoveCallbackList(widget, string, list) [procedure] Removes the callbacks specified by the Pop-11 list list from the callback list named string of the widget widget. list is in the same formats as for XptAddCallbackList. Pop-11 words, idents, and procedures are coerced to external forms where necessary, along with their associated DATA, using the coercion procedure XptExportCallbackCached. No errors will be given if the callbacks in list are not present in the callback list named string. XtCallCallbacks(widget, string, call_data) [procedure] Call all the callback procedures in the callback list named string of the widget widget, passing call_data (an arbitrary Pop-11 object) as the call argument to the callback procedures. XtHasCallbacks(widget, string) -> int [procedure] Returns the status of the callback list named string of the widget widget. Possible values for int are XtCallbackNoList if the callback list does not exists, XtCallbackHasNone if the callback list exists but is empty, and XtCallbackHasSome if at least one callback is registered on the list. The constant macros XtCallbackNoList, XtCallbackHasNone, and XtCallbackHasSome are defined in INCLUDE * XT_CONSTANTS, see REF * XT_CONSTANTS for details. ----------------------- 6 LIB FAST_XT_CALLBACK ----------------------- fast_XtAddCallback(widget, string, widentproc, client_data) [procedure] fast_XtAddCallbacks(widget, string, callbacklist) [procedure] fast_XptAddCallbackList(widget, string, list) [procedure] fast_XtRemoveCallback(widget,string,widentproc,client_data) [procedure] fast_XtRemoveCallbacks(widget, string, callbacklist) [procedure] fast_XptRemoveCallbackList(widget, string, list) [procedure] fast_XtRemoveAllCallbacks(widget, string) [procedure] fast_XtCallCallbacks(widget, string, call_data) [procedure] fast_XtHasCallbacks(widget, string) -> int [procedure] Non-checking versions of the procedures in LIB * XT_CALLBACK. There operation is the same except that: o There is no checking for valid arguments. o NO coercion of Pop-11 procedures is performed. These procedures should only be used in fully debugged programs. See REF * XTOOLKIT for full details of the Poplog X naming conventions for non-checking and checking procedures. XptExportTypedCallback(widentproc, client_data, [procedure] conversion_p, hold) -> (efc, item) This procedure coerces a Pop-11 callback procedure widentproc, and an arbitrary Pop-11 object client_data, into an external function closure efc and a Pop-11 item item, that are suitable to be passed as a callback procedure/arg pair. IMPORTANT NOTE: If the procedure is called on different occasions with the same widentproc, client_data, and conversion_p it will return DIFFERENT external function closures which perform the same operation. If you wish to use the same efc twice (for example, when you want to add and then remove a callback) you must keep a reference to the same efc in your program, or use the caching export procedures XptExportTypedCallbackCached and XptExportCallbackCached. If conversion_p is non false then it should contain a conversion procedure (see REF * DEFSTRUCT). When the external function closure efc is executed this conversion procedure will be run on the call data of the callback before widentproc is executed. If the Boolean argument hold is true then a reference to efc is added to the fixed hold list to prevent it getting garbage collected. To remove the efc from the list, use free_fixed_hold. See REF * EXTERNAL_DATA for more details. It should be noted that widget records attempt to keep a reference to their callback procedures (see REF * XptDescriptor) so the user does not have to have hold true, or keep a reference to the efc, when the efc is added as a toolkit callback using XtAddCallback or XptAddCallbackList. The procedure operates by creating an external function closure of the procedure XptCallbackWrapper. The value of efc is given by: exfunc_export( XptCallbackWrapper(% widentproc, client_data, conversion_p %), XptCallbackFlags, hold ); Since the client_data is passed to widentproc by the call to XptCallbackWrapper the callback argument item has no effect in the toolkit callbacks. item is therefore always returned containing a value of false. XptExportCallback(widentproc, client_data, hold) [procedure] -> (efc, item) This procedure coerces a Pop-11 callback procedure widentproc, and an arbitrary Pop-11 object client_data, into an external function closure efc and a Pop-11 item item, that are suitable to be passed as a callback procedure/arg pair. widentproc, client_data, hold, efc, and item are as for calls to XptExportTypedCallback. A call to XptExportCallback is equivalent to a call to XptExportTypedCallback with a false CONVERSION_P argument. XptExportTypedCallbackCached(widentproc, client_data, [procedure] conversion_p, hold) -> (efc, item) This procedure coerces a Pop-11 callback procedure widentproc, and an arbitrary Pop-11 object client_data, into an external function closure efc and a Pop-11 item item, that are suitable to be passed as a callback procedure/arg pair. The arguments and results are as for a call to XptExportTypedCallback, the difference being that the resultant external function closure efc is cached. This means that different calls to XptExportTypedCallbackCached WILL return the same external function closure efc; if the same widentproc, client_data and conversion_p are used (the cache considers the arguments to be the same if -sys_=- returns true when applied to them). This is important when you need to make two references to the same procedure, for example when adding and later removing a single callback. The entry in the cache for the external function closure efc becomes garbage when efc becomes garbage. It should be noted that widget records attempt to keep a reference to their callback procedures (see REF * XptDescriptor) so the user does not have to have hold true, or keep a reference to the efc, when the efc is added as a toolkit callback using XtAddCallback or XptAddCallbackList. XptExportCallbackCached(widentproc, client_data, hold) [procedure] -> (efc, item) This procedure coerces a Pop-11 callback procedure widentproc, and an arbitrary Pop-11 object client_data, into an external function closure efc and a Pop-11 item item, that are suitable to be passed as a callback procedure/arg pair. The external function closure efc is cached in the same way as the external function closure returned by XptExportCallbackCached. widentproc, client_data, hold, efc, and item are as for calls to XptExportTypedCallback. A call to XptExportCallbackCached is equivalent to a call to XptExportTypedCallbackCached with a false CONVERSION_P argument. XptCallbackWrapper(exptrclass, widentproc, client_data, [procedure] conversion_p) Closures of the procedure XptCallbackWrapper are used by the XptExport(Typed)Callback(Cached) procedures to create external function closures that can be used as toolkit callback procedures. For more details of external function closures see REF * EXTERNAL. exptrclass should be an external pointer class record pointing to an instance of the following structure: l_typespec extdata { widget :XptWidget, client_data :XptPointer, ;;; ignored call_data :exval }; The "widget" field of the above structure, the client_data passed to XptCallbackWrapper, and the "call_data" field of the above structure are then pushed onto the stack, ready for the call of the procedure referred to by widentproc. client_data, which can be any Pop-11 object, is used instead of whatever is in the "client_data" field of the structure referred to by exptrclass. The "call_data" field is accessed to produce an external pointer containing the data as its pointer value, that is exacc exptrclass.call_data -> call_data If conversion_p is non false then it should contain a conversion procedure to be run on the pointer, i.e. conversion_p( exacc[nc] exptrclass.call_data ) -> call_data Note that in this case, the "call_data" field is accessed with exacc[nc], which produces a fixed (i.e. constant) external pointer record. This is done on the assumption that the conversion procedure will either immediately extract the data from the pointer, or copy it otherwise. Without a conversion procedure, a new external pointer is constructed each time. Finally widentproc, which should refer to a Pop-11 toolkit callback procedure, is executed by a call to XptCallbackHandler with a type of "callback". ------------------------------------------------------------ 7 Possible Problems With Default External Callback Coercion ------------------------------------------------------------ The following discusses possible problems related to using caching coercion procedures to produce X toolkit callback procedures. The same comments apply to other caching coercion procedures used in the Poplog X interface (for example, those used by "action hook" procedures). The following comments should be kept in mind when using any caching coercion procedures for external callbacks. As previously stated, the libraries use the procedure XptCoerceCallbackCached to coerce the Pop-11 procedures to an appropriate external form. This means that the coerced procedures are cached in memory. The upshot of this is that two separate coercions on the same callback procedure and data will refer to the same external callback, thus: XtAddCallback(widget, XtN buttonEvent, callback, 'foo'); and XtRemoveCallback(widget, XtN buttonEvent, callback, 'foo'); will both refer to the same callback procedure. For most normal callback usage this is the behaviour you will want, but in some situations problems may arise. This is because sys_= is used to check when two Pop-11 procedure/argument pairs refer to the same external function closure. For example, if you wanted to have two references, ref1 and ref2, which would always contain the call data of the last buttonEvent in, respectively, widgets wig1 and wig2, you might expect to be able to do something like this: vars ref1 = consref(false); vars ref2 = consref(false); define a_callback(widget, reference, call_data); lvars widget, reference, call_data; call_data -> cont(reference); enddefine; XtAddCallback(wig1, XtN buttonEvent, a_callback, ref1); XtAddCallback(wig1, XtN buttonEvent, a_callback, ref2); This will NOT work. The procedure call XtAddCallback(wig1, XtN buttonEvent, a_callback, ref1); will cause a_callback and ref1 to be coerced into an external procedure (lets call it EXTPROC) which is cached in memory. This means that the procedure call XtAddCallback(wig1, XtN buttonEvent, a_callback, ref2); instead of adding a new callback procedure to widget wig1, will add the cached callback EXTPROC, because the Pop-11 procedures and the callback client data are SINGLE equals equivalent (a_callback = a_callback and ref1 = ref2). In situations like this you must perform the coercion yourself, using the non-caching callback coercion procedures XptExportCallback and XptExportTypedCallback. A correct version of the above example would be as follows. vars ref1 = consref(false); vars ref2 = consref(false); define a_callback(widget, reference, call_data); lvars widget, reference, call_data; call_data -> cont(reference); enddefine; XtAddCallback( wig1, XtN buttonEvent, XptExportCallback(a_callback, ref1, false) ); XtAddCallback( wig1, XtN buttonEvent, XptExportCallback(a_callback, ref2, false) ); --- C.x/x/pop/ref/xt_callback --- Copyright University of Sussex 1992. All rights reserved.