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