[comp.windows.x.motif] Wcl callback resources

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