How does the built-in "window close" work (the red

When a PtWindow is built with these resources set:
Ph_WM_RENDER_TITLE, Ph_WM_RENDER_CLOSE, and Ph_WM_CLOSE
you get the friendly red X in the window’s upper right hand corner.
Click on it and the window closes as expected.

Question: What is the built-in callback that accomplishes this? Code
details, if possible.

Background for the curious:
I’m implementing a PhAB application that has compiled-in windows but
also invokes another widget from a DLL using the dlopen() and dlsym()
calls.
We need a much larger “close window” button because user will probably
be wearing gloves. In the main app, I use a big button whose
“activate” callback is the handy “Done:” or “Cancel” option. But
when trying to implement such a button in the DLL-based window, the
“Done” callback closes everything. However, the “native” close
widget (little red X, upper RH corner) works as I would like.

Even more detail:
I tried implementing a big-close-button callback using
PtForwardWindowEvent() with an event of Ph_WM_CLOSE after finding the
region ID of the button’s parent window. This did not work in the
DLL-based window. A variation of this technique (Ph_WM_HELP) used in
the main PhAB app does work – but, again, not in my DLL widget.

rlb wrote:

When a PtWindow is built with these resources set:
Ph_WM_RENDER_TITLE, Ph_WM_RENDER_CLOSE, and Ph_WM_CLOSE
you get the friendly red X in the window’s upper right hand corner.
Click on it and the window closes as expected.

Question: What is the built-in callback that accomplishes this? Code
details, if possible.

When you click on the Close button, the window manager sends a
Ph_WM_CLOSE event to the application. PtWindow’s event handler checks
the widget’s managed flags and if Ph_WM_CLOSE is set, it either closes
the window using PtDestroyWidget(), or exist using PtExit(), depending
on whether that was the application’s last window.

Background for the curious:
I’m implementing a PhAB application that has compiled-in windows but
also invokes another widget from a DLL using the dlopen() and dlsym()
calls.
We need a much larger “close window” button because user will probably
be wearing gloves. In the main app, I use a big button whose
“activate” callback is the handy “Done:” or “Cancel” option. But
when trying to implement such a button in the DLL-based window, the
“Done” callback closes everything. However, the “native” close
widget (little red X, upper RH corner) works as I would like.

Do you mean the Done callback causes the entire application to exit? It
should only do that when the button is in the base window. Is it?

If you want the callback to just close the window, and it indeed is a
base window, use a Cancel callback instead. Or just a code callback
that calls PtDestroyWidget(). Keep in mind that if you destroy your
base window, the library may pick a window module that you subsequently
open, and consider it a new base window. The rules for when it happens
are somewhat convoluted.

Even more detail:
I tried implementing a big-close-button callback using
PtForwardWindowEvent() with an event of Ph_WM_CLOSE after finding the
region ID of the button’s parent window. This did not work in the
DLL-based window. A variation of this technique (Ph_WM_HELP) used in
the main PhAB app does work – but, again, not in my DLL widget.

Since all the code involved is running within the process that owns the
window, the best way to close the window is by calling
PtDestroyWidget(). Forwarding a Ph_WM_CLOSE event means asking PWM to
politely ask the owner of the window to close it, possibly involving an
“Are you sure” dialog; if the window is yours and you know you want to
close it, there’s no need to ask pwm to ask you.

My main app. does a dlopen() on the file containing a PhAB window-type
widget (MyWindow) and the associated init_DLL(). The main app then
gets a pointer to init_DLL() via the dlsym() call and, referencing
that pointer, the DLL-based window appears.
In brief, init_DLL() does this:
ApAddContext( &AbContext, dll_path)
which, I think, informs the Photon main loop that there are
additional events to manage
and this:
ApCreateModule(ABM_MyWindow, NULL, NULL)
whose function is to realize the DLL-based widget “MyWindow”

Now I see the window I created with PhAB and it contains a
PtNumericFloat which I can edit successfully. It also contains a
custom button with an Activate callback of “Cancel” or an exit
function of my own design. In either case, clicking on my button
closes MyWindow AND the base window of the main app. Clicking on the
small, red X in the title bar simply closes MyWindow but not the main
app.
I suspect I’ve not set up the DLL or the transition to it correctly
because a printf()/fflush() placed in my explicit exit callback does
not show up in the Momentics console output window.

Thanks Wojtech for your look at my puzzle. (And the same to any
others who may contribute.)

rlb wrote:

My main app. does a dlopen() on the file containing a PhAB window-type
widget (MyWindow) and the associated init_DLL(). The main app then
gets a pointer to init_DLL() via the dlsym() call and, referencing
that pointer, the DLL-based window appears.
In brief, init_DLL() does this:
ApAddContext( &AbContext, dll_path)
which, I think, informs the Photon main loop that there are
additional events to manage

Not exactly; the AbContext is a structure that tells PhAB library what
file (executable or DLL) to find module resources in and where to find
certain internal global variables. Each PhAB-generated executable or
DLL has its own copy of AbContext and a few other arrays and structures.
Various data structures describing PhAB modules and callbacks contain
pointers to their local AbContext to let the library figure out which
file to read resources and translations from. Also, all the contexts
are linked on a list to let ApSetTranslation() load translation files
for all PhAB DLLs.

Just to make sure: are you linking your DLL with the -Bsymbolic linker
option (-Wl,-Bsymbolic qcc option)? That’s necessary for this scheme to
work – without it, all the references to AbContext in the DLL are
resolved to use the AbContext defined in the executable, instead of the
local one defined in the DLL’s abmain.c.

and this:
ApCreateModule(ABM_MyWindow, NULL, NULL)
whose function is to realize the DLL-based widget “MyWindow”

What function is the main application calling this from --is it an
initialisation function? The setup function of the base window? Other?

Now I see the window I created with PhAB and it contains a
PtNumericFloat which I can edit successfully. It also contains a
custom button with an Activate callback of “Cancel” or an exit
function of my own design. In either case, clicking on my button
closes MyWindow AND the base window of the main app. Clicking on the
small, red X in the title bar simply closes MyWindow but not the main
app.
I suspect I’ve not set up the DLL or the transition to it correctly
because a printf()/fflush() placed in my explicit exit callback does
not show up in the Momentics console output window.

One thing to make sure that the DLL is linked correctly is to put the line

printf( “%p\n”, &AbContext );

in the executable and in the DLL. They should print out different
addresses.

Thanks Wojtech for your look at my puzzle. (And the same to any
others who may contribute.)

You’re welcome…

Just to make sure: are you linking your DLL with the -Bsymbolic
linker
option (-Wl,-Bsymbolic qcc option)?

Yes. By the way, I didn’t have to run the addvariant script to get a
subdirectory like ~/x86/dll. Clicking on the DLL’s Properties and
selecting the Library tab, there are a number of radio-style buttons.
The bottom one is “Choose shared library without export (xx.dll)” and
this causes a ~/dll directory to be created. It is also apparently
the reason the -W1 and -Bsymbol link options are present. Perhaps
this is a feature of SP1?

One thing to make sure that the DLL is linked correctly is to put
the line printf( “%p\n”, &AbContext ); in the executable and in

the DLL. They should print out different addresses.

The values of AbContext are non-NULL and different in base and DLL.

What function is the main application calling this from --is it an
initialisation function? The setup function of the base window?
Other?

The main app has a toolbar with a button whose Activate callback
summons a window. In that window is a PtList with tab-separated
entries in rows 1 and beyond and a series of column-heading buttons
in row-0. When the column-2 button is pressed, the callback is
responsible for the dlopen(), dlsym() and invocation of the
init_DLL(). The latter has two arguments and, after doing the
ApAddContext() and ApCreateModule(), it makes two calls to
PtSetResource to set values in the newly-created window.

The displayed DLL window shows the new values and, as mentioned
before, will close nicely using the little red X in upper rt. hand
corner.

Thanks again for listening. Have a good weekend all.

rlb wrote:

Just to make sure: are you linking your DLL with the -Bsymbolic
linker
option (-Wl,-Bsymbolic qcc option)?

Yes. By the way, I didn’t have to run the addvariant script to get a
subdirectory like ~/x86/dll. Clicking on the DLL’s Properties and
selecting the Library tab, there are a number of radio-style buttons.
The bottom one is “Choose shared library without export (xx.dll)” and
this causes a ~/dll directory to be created. It is also apparently
the reason the -W1 and -Bsymbol link options are present. Perhaps
this is a feature of SP1?

I’m not sure if it was new in SP1, but it’s a feature of the IDE that
deserves to be mentioned in Photon Programmer’s Guide…

One thing to make sure that the DLL is linked correctly is to put

the line printf( “%p\n”, &AbContext ); in the executable and in
the DLL. They should print out different addresses.

The values of AbContext are non-NULL and different in base and DLL.

OK, since you’re using the “dll” variant, this is not surprising…

What function is the main application calling this from --is it an
initialisation function? The setup function of the base window?

Other?

The main app has a toolbar with a button whose Activate callback

OK, so the toolbar is in the main app’s base window, and the base window
stays open all the time, correct?

summons a window. In that window is a PtList with tab-separated
entries in rows 1 and beyond and a series of column-heading buttons
in row-0. When the column-2 button is pressed, the callback is
responsible for the dlopen(), dlsym() and invocation of the
init_DLL(). The latter has two arguments and, after doing the
ApAddContext() and ApCreateModule(), it makes two calls to
PtSetResource to set values in the newly-created window.

The displayed DLL window shows the new values and, as mentioned
before, will close nicely using the little red X in upper rt. hand
corner.

Could you run you application in the debugger, set a breakpoint on
exit(), click on the button with the Done callback, and post a stack
trace here?

Continuing the story:

What function is the main application calling this from --is it an
initialisation function? The setup function of the base window?
Other?

The main app has a toolbar with a button whose Activate callback…

OK, so the toolbar is in the main app’s base window, and the base

window
stays open all the time, correct?[/quote:535cb2497c]

The main app’s base window stays open while the DLL window pops up
with the values revised by the init_DLL() function called up by
dlopen/dlsym in base window. When the DLL window’s “Done” button is
pressed, all windows close and I’m back at Momentics.

Could you run you application in the debugger, set a breakpoint on
exit(), click on the button with the Done callback, and post a
stack
trace here?

Darn it, now I have to show my depth of ignorance. I don’t see or use
an exit() anywhere. Where should the
breakpoint be placed?
In main app’s abmain? (at the PtExit() statement just after
PtMainLoop()?)

Other functions use “return (Pt_Continue);” Specifically:

  • the main app callback that summons the init_DLL()
  • the init_DLL() itself, right after doing the 2 PtSetResources()
    calls.

<insert another grateful “Thanks” here.>

“rlb” <robert.bottemiller@fmcti-dot-com.no-spam.invalid> wrote in message
news:d8kh0h$3rl$1@inn.qnx.com

Continuing the story:
What function is the main application calling this from --is it an
initialisation function? The setup function of the base window?
Other?

The main app has a toolbar with a button whose Activate callback…

OK, so the toolbar is in the main app’s base window, and the base
window
stays open all the time, correct?[/quote:535cb2497c]

The main app’s base window stays open while the DLL window pops up
with the values revised by the init_DLL() function called up by
dlopen/dlsym in base window. When the DLL window’s “Done” button is
pressed, all windows close and I’m back at Momentics.

But up to that point, the base window stays open, and you don’t want it to
be closed by the DLL window’s Done button, right?

Could you run you application in the debugger, set a breakpoint on
exit(), click on the button with the Done callback, and post a
stack
trace here?

Darn it, now I have to show my depth of ignorance. I don’t see or use
an exit() anywhere. Where should the
breakpoint be placed?
In main app’s abmain? (at the PtExit() statement just after
PtMainLoop()?)

Not on any particular call to exit(), but on the function itself… To show
my depth of ignorance: there is a way in the IDE to enter gdb commands by
hand, isn’t there? The command “break exit” should do it. If the IDE
doesn’t allow you to do that, perhaps you could run gdb from a pterm?..

Hey, here’s another idea: register a function using atexit(), and put a
breakpoint somewhere in it.

But up to that point, the base window stays open, and you don’t want
it to be closed by the DLL window’s Done button, right?

Right. The DLL pop-up window is an editor for an object of which
several instances will be listed in the base/main application. Its
function is to allow the user to change control parameters for an
underlying calculation then go away. (The point of using a DLL is so
we can download new versions of the editor, or other modules so
distributed, via a small DLL instead of the whole main app.)


To show my depth of ignorance: there is a way in the IDE to enter
gdb commands by hand, isn’t there? The command “break exit” should do

it. If the IDE doesn’t allow you to do that, perhaps you could run gdb
from a pterm?..

Hey, here’s another idea: register a function using atexit(), and
put a
breakpoint somewhere in it.

I’ll follow up on those ideas – it’s time I started learning the
debug and diagnostic tools.
Thanks again.

I haven’t got the debugger running in a useful form, but…
I did run the application in a pterm and when I clicked on my big
close button, the pterm presented a “Memory fault (core dumped)”
message. I don’t know how to do more than run coreinfo with the core
dump file as input. The result is this:

splash1_g.core:
processor=X86 num_cpus=1
cpu 1 cpu=1586 name=AMD ?86 F15M5S10 speed=2205
flags=0xc0003fff FPU MMU CPUID RDTSC INVLPG WP BSWAP MMX CMOV PSE
PGE MTRR SEP SIMD FXSR
cyc/sec=2200774500 tod_adj=1118757014000000000 nsec=10604923198462
inc=999847
boot=1118757014 epoch=1970 intr=0
rate=838095345 scale=-15 load=1193
MACHINE=“x86pc” HOSTNAME=“localhost”
pid=4706338 parent=4689943 child=0 pgrp=4706338 sid=4689943
flags=0x002000 umask=02 base_addr=0x8048000 init_stack=0x804781c
ruid=100 euid=100 suid=100 rgid=0 egid=0 sgid=0
ign=0000000000040000 queue=ff00000000000000 pending=0000000000000000
fds=6 threads=1 timers=0 chans=4
thread 1 SIGNALLED-SIGSEGV code=1 MAPERR refaddr=b83396b0 fltno=11
ip=0xb82051d1 sp=0x8047288 stkbase=0x7fc7000 stksize=528384
state=STOPPED flags=0 last_cpu=1 timeout=00000000
pri=10 realpri=10 policy=RR

One oddity is that the real HOSTNAME isn’t “localhost” but maybe
that’s a formalism of the core dump. Also the DLL window has context
b83397a0 which is kind of close to the above “MAPERR refaddr” of
b83396b0. I can’t get any more out of this mass of data.
Can anyone else?

rlb wrote:

I haven’t got the debugger running in a useful form, but…

Well, having a working debugger is often helpful when you’re trying to
debug a program…

I did run the application in a pterm and when I clicked on my big
close button, the pterm presented a “Memory fault (core dumped)”
message. I don’t know how to do more than run coreinfo with the core
dump file as input. The result is this:

splash1_g.core:

One oddity is that the real HOSTNAME isn’t “localhost” but maybe
that’s a formalism of the core dump. Also the DLL window has context
b83397a0 which is kind of close to the above “MAPERR refaddr” of

By “context”, do you mean AbContext? Those two addresses are on the
same page – is there a chance that you’re trying to access some data in
the DLL after calling dlclose(), perhaps by doing something to the
widgets that causes the library to try to invoke a PhAB-registered
callback?

b83396b0. I can’t get any more out of this mass of data.
Can anyone else?

You can load the core file into gdb:

gdb program program.core

But for an easily reproducible case like this, running and crashing the
program under gdb is just as simple.

The Momentics-driven debugger has a non-trivial learning curve –
especially with the terse online documentation.

Some addresses of interest:

Calling PhAB AbContext: 804c580
dlsym() return ptr to init_DLL: b8337fbc
DLL window AbContext: b8339800
DLL window module link (ABM_MyWindow): b8339698
DLL window has PtLabel (ABW_…): 805fdb0
and deadly Done PbButton (ABW.): 8061158

The gbd advice is well-taken. Thanks yet again for a concrete lead to
follow.

Diagnosis for premature total window closure:
My main Photon app. called the DLL init function then immediately
called dlclose(handle). I presume dlclose() was invoked right after
the init_DLL function returned, but the pop-up, DLL-based window was
still alive – I could manipulate a PtNumericFloat widget there.
Only when I clicked on my custom “Done” button did the problem
arise: an apparent access into libAp.so with an invalid address due
to the now-closed DLL.

I’m wondering two things:

  1. What’s the safe and proper way to delete the DLL AbContext and do a
    dlclose().
  2. What Photon object was still dealing with a now-defunct DLL and
    why?

At least the memory fault is now explained.
Signing off…

rlb wrote:

Diagnosis for premature total window closure:
My main Photon app. called the DLL init function then immediately
called dlclose(handle). I presume dlclose() was invoked right after
the init_DLL function returned, but the pop-up, DLL-based window was
still alive – I could manipulate a PtNumericFloat widget there.

Right. The widgets generally don’t rely on the DLL being still there,
except when a PhAB-related callback wants to run some code in the DLL or
access some data in the DLL.

Only when I clicked on my custom “Done” button did the problem
arise: an apparent access into libAp.so with an invalid address due
to the now-closed DLL.

I’m wondering two things:

  1. What’s the safe and proper way to delete the DLL AbContext and do a
    dlclose().

The “Unloading your DLL” section in the docs lists things you need to do
before unloading the DLL – the main one is that you have to destroy any
widgets that were created using the DLL’s PhAB modules. You should not
unload the DLL without making sure that all such widgets have been
destroyed first.

  1. What Photon object was still dealing with a now-defunct DLL and
    why?

Your Done callback.

PhAB library uses the same function for all your callbacks; the “data”
argument to the function is set up to point to a small structure that
tells the library what type of a callback it is (Dialog, Code, Done,
etc.) and what function in the application to call, if any. Unloading
the DLL turns this data structure into empty address space that makes
you crash when you try to read from it.

(PhAB library also attaches some other callbacks to your widgets – for
instance, any Dialog window has a DESTROYED callback attached to it that
resets the dialog’s ABW variable to NULL. And guess what: if the ABW
variable has been unloaded, trying to reset it makes you crash, too.
Or, even worse, sticks a NULL into something that happens to have
recycled that area of address space.)