aw@bae.bellcore.com (Andrew Wason) (04/12/91)
Some people have been having problems using callback resources with Wcl and Motif (Mri) (specifically XmNpopupCallback). I think I have finally tracked the problem down. It seems to all boil down to the fact that Motif calls XtGetSubresources() to refetch all of a widgets resources back into the widget itself, and does not subsequently recompile (_XtCompileCallbackList) any of the widgets callback list resources. I think that this is only a problem for widgets which are a subclass of VendorShell (so should affect only XmNpopupCallback, XmNpopdownCallback, XmNdestroyCallback). Using this resource file as an example: Mri.wcChildren: button Mri.wcPopups: popup *button.wcClassName: XmPushButton *button.activateCallback: WcPopupCB( *popup ) *popup.wcClassName: TopLevelShell *popup.popupCallback: WcSystemCB( echo popupCallback ) *popup.wcChildren: label *label.wcClassName: XmLabel If you run this through Mri, the popupCallback will never be called (it should be called when you press 'button'). When the 'popup' widget is created, Xt/Create.c`_XtCreate() calls Xt/Resources.c`_XtGetResources() which calls Xt/Resources.c`GetResources() to fetch and type convert the widgets resources. This is where the Wcl CvtStringToWidget type converter gets invoked to convert the String "WcSystemCB( echo popupCallback )" to an XtCallbackList. After _XtGetResources() returns, _XtCreate() calls Xt/Callback.c`_XtCompileCallbackList() for each callback resource. This converts the XtCallbackList returned by the converter into a CallbackStruct which is an internal representation. All of this works fine. The problem is that later, a Motif "secondary" object (which VendorShell creates as a hidden child of 'popup') calls XtGetSubresources() on the 'popup' widget (see Xm/VendorE.c`InitializePrehook:1443). XtGetSubresources(object, base, name, class, resources, num_resources, args, num_args); It passes the 'popup' widget as both the 'object' and 'base' parameters, and the XtResourceList of TopLevelShell as the 'resources' and 'num_resources' parameters. XtGetSubresources() calls GetResources() which refetches all of 'popup's resources again (they were already fetched above when _XtCreate() called GetResources()). They are placed in the 'popup' Widget instance record, overwriting the resources which where fetched in _XtCreate(). The problem is, none of 'popup's callback resources get recompiled by _XtCompileCallbackList() into the correct internal form. We are left with a callback resource (ShellWidget)w)->shell.popup_callback which is in the wrong form - the Intrinsics can't use it, so our callback never gets called. Should GetResources() take over compiling callback lists? Right now the only places they are compiled is in _XtCreate() and Xt/Object.c`ObjectSetValues(). --- Details --- To see where this is happening, run Mri under a debugger on the resource file above. Place a breakpoint in Xm/VendorE.c`InitializePrehook():1443 (Motif 1.1 source) at the call to XtGetSubresources() on widget 'parent' with the (*pcePtr)->ext_resources resource list. This resource list was fetched for the TopLevelShell widget class a few lines above in the call to XtGetResourceList() (line 1421). The second time you stop at this breakpoint, 'parent' will be the 'popup' widget. Print the popupCallback list: print *((CallbackStruct *)((ShellWidget)parent)->shell.popup_callback) (struct _CallbackStruct) = { struct _XtCallbackRec *external_form = 0x0; int array_size = 0; struct _CallbackRec *internal_form = 0x144c90 /* (allocated) */; } This is the normal internal form which was compiled in _XtCreate() when 'popup' was created. After you step over the call to XtGetSubresources, print the popupCallback list again: print *((CallbackStruct *)((ShellWidget)parent)->shell.popup_callback) (struct _CallbackStruct) = { struct _XtCallbackRec *external_form = 0x772b94 /* 0x767000+48020 (<initialized data>) */; int array_size = 1330448; struct _CallbackRec *internal_form = 0x0; } It is no longer in the correct internal form, this is actually an XtCallbackList (the external form returned by the type converter). Type coerce it to see: print *((XtCallbackList)((ShellWidget)parent)->shell.popup_callback) (struct _XtCallbackRec) = { void (*callback)() = 0x772b94 < 'WcSystemCB' module "/u/acp/aw/X/wcl-1.05/install/lib/libWc_d.a(WcCallb.o)" >; char *closure = 0x144d10 "echo popupCallback"; } When the Intrinsics attempts to call the callbacks on this list, it assumes this is a pointer to CallbackStruct. It uses (((CallbackStruct *)((ShellWidget)parent)->shell.popup_callback)->internal_form) which is NULL, so the Intrinsics thinks there are no callbacks on this list. The ((ShellWidget)parent)->shell.popup_callback needs to be compiled by _XtCompileCallbackList before this list can be used. What should be done to fix this? Why does Motif need to refetch all of a widgets resources back into the widget, what was wrong with the original fetch in _XtCreate()? Is it correct that XtGetSubresources() doesn't compile callback resources? Here is a stack trace of where you will be the second time you stop at the breakpoint. InitializePrehook() at "/fs/10/m/motif.src/lib/Xm/VendorE.c":1448 InitializeRootWrapper() at "/fs/10/m/motif.src/lib/Xm/BaseClass.c":591 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":145 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 _XtCreate() at "/u/XV11R4/src/mit/lib/Xt/Create.c":259 _XtCreateWidget() at "/u/XV11R4/src/mit/lib/Xt/Create.c":364 XtCreateWidget() at "/u/XV11R4/src/mit/lib/Xt/Create.c":390 SecondaryObjectCreate() at "/fs/10/m/motif.src/lib/Xm/Vendor.c":1118 InitializePrehook() at "/fs/10/m/motif.src/lib/Xm/Vendor.c":1152 InitializeRootWrapper() at "/fs/10/m/motif.src/lib/Xm/BaseClass.c":591 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":145 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 CallInitialize() at "/u/XV11R4/src/mit/lib/Xt/Create.c":142 _XtCreate() at "/u/XV11R4/src/mit/lib/Xt/Create.c":259 _XtCreatePopupShell() at "/u/XV11R4/src/mit/lib/Xt/Create.c":437 XtCreatePopupShell() at "/u/XV11R4/src/mit/lib/Xt/Create.c":455 CreatePopup() at "/u/acp/aw/X/wcl-1.05/Wc/WcCreate.c":700 WcCreateDatabasePopup() at "/u/acp/aw/X/wcl-1.05/Wc/WcCreate.c":549 WcCreateNamedPopups() at "/u/acp/aw/X/wcl-1.05/Wc/WcCreate.c":469 WcWidgetCreation() at "/u/acp/aw/X/wcl-1.05/Wc/WcCreate.c":365 main() at "Mri.c":104 Andrew _______________________________________________________________________________ Andrew Wason Bell Communications Research aw@bae.bellcore.com Piscataway, NJ bellcore!bae!aw