[comp.windows.x] cleaning up from exit

jcarson@MONIZ.BCM.TMC.EDU (Janet L. Carson) (03/03/90)

With regards to the the "cleaning up before exit" problem
recently discussed on xpert, I would like to propose the
following addition to the Xt Intrinsics:

XtAddCleanUpProc(routine, client_data)
XtRemoveCleanUpProc(routine, client_data)

These would add or remove a routine from a list of routines
to be called when the application exits.

To exit an application, the programmer would call:

XtExit(value)

which would call all of the clean up procedures and then
call exit(value).

--Janet

Janet L. Carson                               internet: jcarson@bcm.tmc.edu
Baylor College of Medicine              uucp: {rutgers,mailrus}!bcm!jcarson

erik@srava.sra.co.jp (Erik M. van der Poel) (03/04/90)

In article <9003022256.AA07109@moniz.bcm.tmc.edu> Janet L. Carson writes:

>With regards to the the "cleaning up before exit" problem
>recently discussed on xpert, I would like to propose the
>following addition to the Xt Intrinsics:
>
>XtAddCleanUpProc(routine, client_data)
>XtRemoveCleanUpProc(routine, client_data)
>
>These would add or remove a routine from a list of routines
>to be called when the application exits.
>
>To exit an application, the programmer would call:
>
>XtExit(value)
>
>which would call all of the clean up procedures and then
>call exit(value).


I think these are good ideas, but there is a problem: this scheme
would not be backward-compatible. New applications that use XtExit()
would break existing widgets that expect their destroy procedures to
get called in order to remove temporary files, etc.


However, I *do* think that registering clean-up procs is a good idea,
and should probably be possible for general purposes, but not for
those things that widget destroy procs are used for.


I think that the application programmer should explicitly call
XtDestroyWidget() for widgets whose documentation clearly states that
destruction is necessary. Then the application should call XtExit(),
which tells Xt to exit when it is safe to do so, that is, after
destroy phase 2. This way the app programmer does not have to set a
global flag to break out of the main loop.


There should probably also be an XtAppExit(), which would terminate
only the given application. This would only be implemented in systems
where it is possible to have multiple applications in one address
space. Similarly, we need XtAppAddCleanUpProc() and
XtAppRemoveCleanUpProc().


The default error handler should not call exit() directly. It should
call XtExit().


Also, it would be nice if widgets would be able to express an interest
in having themselves destroyed before exiting, just in case the app
programmer does call XtExit() but forgets to call XtDestroyWidget().
Of course, if the app programmer calls exit() you're hosed, but the
current situation is already like that anyway.


Another issue is the distinction between a normal exit and a crash. A
widget may want to know whether its destroy proc is being called by Xt
or by the app programmer. If it is being called by Xt, it might assume
that there was an error, and therefore refrain from unlinking its
temporary file. The widget might also like to give the app some
control over this, by having a resource like XtNremoveTempFile.


As far as XtDestroyApplicationContext() is concerned, I think that it
should destroy all widgets associated with the app context. Otherwise,
XtWidgetToApplicationContext() would not be meaningful. Similarly,
XtCloseDisplay() should destroy all associated widgets.
-
-- 
Erik M. van der Poel                  erik@sra.co.jp             (Japan)
Software Research Associates, Inc.    erik%sra.co.jp@uunet.uu.net  (USA)
Tokyo, Japan    TEL +81-3-234-2692    erik%sra.co.jp@mcsun.uucp (Europe)

jcarson@WILKINS.BCM.TMC.EDU (Janet L. Carson) (03/06/90)

[Me: Scheme for exit: XtAddCleanUpProc, XtExit, etc.]

>I think these are good ideas, but there is a problem: this scheme
>would not be backward-compatible. New applications that use XtExit()
>would break existing widgets that expect their destroy procedures to
>get called in order to remove temporary files, etc.

It is backward compatible in this sense: if the application and the 
widget set go on doing the same things they were always doing, the 
same thing that happened before will continue to happen.  I agree
that if you only change 1/2 of the system, the other half will not
change automatically, and that could present problems in a few cases.

The problem that got the whole thing started was that the destroy
procedure isn't always called, unless the application programmer
is careful about it.  If both the widget and the application are
changed to clean-up procs, they won't have to be so careful in 
the future.


>I think that the application programmer should explicitly call
>XtDestroyWidget() for widgets whose documentation clearly states that
>destruction is necessary. 

Hopefully clean up procs would reduce the number of widgets for which
this is necessary.  It's too much of a hassle for the programmer, and
it limits the widget writer:  I can't change my widget to create a temp 
file because all of the existing applications would have to go back 
and change their code to make sure it was destroyed explicitly.

What I envisioned was that a widget which created a temp file would
call XtAddCleanUpProc from it's Initialize routine, and 
XtRemoveCleanUpProc from it's Destroy routine, passing the widget pointer 
as the client_data.  This creates an "ensured destroy" without changing 
the core widget structure, or bothering the 99% of widgets that don't
absolutely need their destroy procedure called.


>Another issue is the distinction between a normal exit and a crash.

How about if the callback has the following arguments:

CleanUpProc(client_data, exit_value)

Where exit_value is the value passed to XtExit().  If this is non-zero,
the clean-up proc. knows that the application is not exiting normally.


>As far as XtDestroyApplicationContext() is concerned, I think that it
>should destroy all widgets associated with the app context. Otherwise,
>XtWidgetToApplicationContext() would not be meaningful. Similarly,
>XtCloseDisplay() should destroy all associated widgets.

Whether or not all these widgets want or need their destroy procedure
called?  Wouldn't this be a waste of time?  The widget destroy proc was 
envisioned to free up Pixmaps, GCs and things from X which would not 
have to be freed explicitly if the connection to the X server were 
closing.  (Otherwise, wouldn't they have called all of the destroy procs 
in the current Intrinsics implementation?)



>Erik M. van der Poel                  erik@sra.co.jp             (Japan)
>Software Research Associates, Inc.    erik%sra.co.jp@uunet.uu.net  (USA)
>Tokyo, Japan    TEL +81-3-234-2692    erik%sra.co.jp@mcsun.uucp (Europe)

--Janet

Janet L. Carson                               internet: jcarson@bcm.tmc.edu 
Baylor College of Medicine              uucp: {rutgers,mailrus}!bcm!jcarson

kit@EXPO.LCS.MIT.EDU (Chris D. Peterson) (03/06/90)

> With regards to the the "cleaning up before exit" problem
> recently discussed on xpert, I would like to propose the
> following addition to the Xt Intrinsics:

> XtAddCleanUpProc(routine, client_data)
> XtRemoveCleanUpProc(routine, client_data)

> These would add or remove a routine from a list of routines
> to be called when the application exits.

> To exit an application, the programmer would call:

> XtExit(value)

> which would call all of the clean up procedures and then
> call exit(value).

This is a good idea.  I will bring this before the internal Xt Consortium
working group for discussion.  

						Chris D. Peterson     
						MIT X Consortium 

Net:	 kit@expo.lcs.mit.edu
Phone:   (617) 253 - 9608	
Address: MIT - Room NE43-213

erik@srava.sra.co.jp (Erik M. van der Poel) (03/06/90)

> >I think that the application programmer should explicitly call
> >XtDestroyWidget() for widgets whose documentation clearly states that
> >destruction is necessary. 
> 
> Hopefully clean up procs would reduce the number of widgets for which
> this is necessary.

Even if you have clean-up procs or some other way for widgets to tell
Xt that they crave destruction, the author of such a widget should
probably warn app programmers that they should call XtExit() and not
exit(). But, yes, I agree that it would be better for us to migrate to
a situation where calling XtDestroyWidget() is unnecessary.

Of course, all this wouldn't be necessary if everyone had the ANSI C
atexit() (to register clean-up procs), but even then you can't protect
yourself against a programmer that suddenly and gleefully calls
execl(). (Well, not easily, anyway.) Or does ANSI C support that now
too? Perhaps it should.


> >As far as XtDestroyApplicationContext() is concerned, I think that it
> >should destroy all widgets associated with the app context. Otherwise,
> >XtWidgetToApplicationContext() would not be meaningful. Similarly,
> >XtCloseDisplay() should destroy all associated widgets.
> 
> Whether or not all these widgets want or need their destroy procedure
> called?  Wouldn't this be a waste of time?  The widget destroy proc was 
> envisioned to free up Pixmaps, GCs and things from X which would not 
> have to be freed explicitly if the connection to the X server were 
> closing.

I said that XtDestroyApplicationContext() should destroy all
associated widgets. I did *not* say that apps should call
XtDestroyApplicationContext(). Most apps should probably just call
exit() oops I mean XtExit().

As Paul said, destroy procs are really meant for applications that
wish to continue processing after destroying some widgets. Destroying
the app context is analogous to destroying widgets.

However, it probably is a waste of time to explicitly ask the X server
to free resources when they will be freed automatically and quickly
when the connection is closed. So XtCloseDisplay() should probably
tell the widgets not to bother freeing server resources.


> (Otherwise, wouldn't they have called all of the destroy procs in the
> current Intrinsics implementation?)

Even the X Consortium occasionally makes mistakes. But I hasten to add
that, on the whole, they have done and are doing a great job, and that
is why I am interested in the first place.
-
-- 
Erik M. van der Poel                  erik@sra.co.jp             (Japan)
Software Research Associates, Inc.    erik%sra.co.jp@uunet.uu.net  (USA)
Tokyo, Japan    TEL +81-3-234-2692    erik%sra.co.jp@mcsun.uucp (Europe)

hvr@kimba.Sun.COM (Heather Rose) (03/08/90)

In article <9003052005.AA24152@expo.lcs.mit.edu> kit@EXPO.LCS.MIT.EDU (Chris D. Peterson) writes:
>
>> With regards to the the "cleaning up before exit" problem
>> recently discussed on xpert, I would like to propose the
>> following addition to the Xt Intrinsics:
>
>> XtAddCleanUpProc(routine, client_data)
>> XtRemoveCleanUpProc(routine, client_data)
>
>> These would add or remove a routine from a list of routines
>> to be called when the application exits.
>
>> To exit an application, the programmer would call:
>
>> XtExit(value)
>
>> which would call all of the clean up procedures and then
>> call exit(value).
>
>This is a good idea.  I will bring this before the internal Xt Consortium
>working group for discussion.  

You might want to make this a more general solution.  Add the notion of
interposition to the Xt intrinsics as XView does.  Then you just interpose
on the default clean up procedure to do application specific things.

The concept of "putting this callback before this other one" in the event
stream is a very powerful tool.  It makes a slight change of behavior very
easy to accomplish.

For example, in XView if I want to add to the behavior of the default
exiting procedure, I do this:
	...
	frame = (Frame)xv_create(NULL, FRAME, NULL);
	notify_interpose_destroy_func(frame, my_destroy_func);
	...

	/* This is called before the frame's destroy func (ie. I've interposed in
	 * front of it.
	 */
	Notify_func
	my_destroy_func(frame, status)
	Frame           frame;
	Destroy_status  status;
	{
	    if (status == DESTROY_PROCESS_DEATH || status == DESTROY_CLEANUP) {
		/* 
		 * do something for the application like save a file 
		 */
	    }
	    /* Now call the frame's default destroy func. */
	    notify_next_destroy_func(frame, status);
	}

If I want to change the behavior, I omit the last line:

	"notify_next_destroy_func(frame, status);"

which passes on the destroy event to the next callback.  

The concept of interposition applies to any callback in the XView toolkit.
It's a very clean solution...and would not break backwards compatibility
since it would be additional functionality.

Regards,

Heather

jimf%saber@HARVARD.HARVARD.EDU (03/09/90)

|>> XtAddCleanUpProc(routine, client_data)
|>> XtRemoveCleanUpProc(routine, client_data)

|You might want to make this a more general solution.  Add the notion of
|interposition to the Xt intrinsics as XView does.

He's right, interposition is a much more general solution.  I suggest,
however, *NOT* having an interposition call for each of the events
that you want to interpose on.  The SunView/XView method, which has
generic event interposers, destroy interposers, and others (five or
six in all, I can never remember and the manuals are junk) is
overcomplex.  It would have been better to have a single interposer
and key off event types (which you have to do ANYWAY) instead of five
or six of them.

Happy hacking,

jim frost
saber software
jimf@saber.com

hvr@kimba.Sun.COM (Heather Rose) (03/11/90)

In article <9003091424.AA26239@armory> jimf%saber@HARVARD.HARVARD.EDU writes:
>|>> XtAddCleanUpProc(routine, client_data)
>|>> XtRemoveCleanUpProc(routine, client_data)
>
>|You might want to make this a more general solution.  Add the notion of
>|interposition to the Xt intrinsics as XView does.
>
>He's right, interposition is a much more general solution.  I suggest,
>however, *NOT* having an interposition call for each of the events
>that you want to interpose on.  The SunView/XView method, which has
>generic event interposers, destroy interposers, and others (five or
>six in all, I can never remember and the manuals are junk) is
>overcomplex.  It would have been better to have a single interposer
>and key off event types (which you have to do ANYWAY) instead of five
>or six of them.

Actually, interposition works on Notify Clients not Events.  Each notify
client has an event mask which specifies when it should be called.  The
interposer on the notify client will only be called when an event for
the interposee matches it's event mask.  Each callback supplied is a 
notify client.

I agree that the API for interposition could be simplified.  It's one
interface leftover from SunView that has not yet been changed for XView.
For example, window_create(), panel_create(), etc... have been collapsed
into xv_create().

FYI:  SunView System Programmer's Guide is pretty good on this subject.
Also, there's a good white paper on the SunView notifier from USENIX
proceedings about 3 or 4 years ago.  Author, Steve Evans.  Most of the
issues still apply.

If the manuals are junk, please let us know what the specific problems 
are so we can do something about it. 

__________________________________________________________________
Heather Rose
Window Systems Group                      internet:  hrose@sun.com
Sun Microsystems, Inc.                        uucp:  ...!sun!hrose

asente@decwrl.dec.com (Paul Asente) (03/13/90)

In article <132650@sun.Eng.Sun.COM> hvr@sun.UUCP (Heather Rose) writes:
>You might want to make this a more general solution.  Add the notion of
>interposition to the Xt intrinsics as XView does.  Then you just interpose
>on the default clean up procedure to do application specific things.
>
>The concept of "putting this callback before this other one" in the event
>stream is a very powerful tool.  It makes a slight change of behavior very
>easy to accomplish.

It may well be a powerful tool, but it's also a horrible programmer trap.

The biggest problem is that it violates all the abstraction boundaries in
the system.  Think about event handlers, for example.  If you interpose an
event handler that decides not to continue the event handling, you have to
make sure you're not preempting some other event handler that some other,
possibly completely independent, code module has installed.  There are
plenty of cases in widget sets where a widget adds an event handler to its
parent, or to its children, or to some seemingly unrelated widget.  Doing
safe interposition requires an intimate knowledge of the implementations
of all the widget implementations and of the Intrinsics.  Worse, what is
safe today can become disasterous tomorrow as soon as someone modifies the
implementation of any component.

>It's a very clean solution...and would not break backwards compatibility
>since it would be additional functionality.

It's a horrible hack, and adding it breaks widget implementations
everywhere that count on their functions being called.

	-paul asente
	    asente@decwrl.dec.com	decwrl!asente

maslen@Neon.Stanford.EDU (Thomas Maslen) (03/13/90)

In article <2999@bacchus.dec.com> asente@decwrl.dec.com (Paul Asente) writes:
>It may well be a powerful tool, but it's also a horrible programmer trap.

Would that be "a horrible trap for programmers" or mayhap "a trap for
horrible programmers"?

Thomas						    maslen@neon.stanford.edu

marbru@auto-trol.UUCP (Martin Brunecky) (03/14/90)

In article <2999@bacchus.dec.com> asente@decwrl.dec.com (Paul Asente) writes:
> ...(text deleted) .....  There are
>plenty of cases in widget sets where a widget adds an event handler to its
>parent, or to its children, or to some seemingly unrelated widget.
>
     I am not quite sure, but is THIS a good practice ? XUI and Motif
     are full of instances where one widget munges another one, assuming 
     intimate knowledge of it's internals, rather than documented
     widget methods. This, however, makes any extension to such widget
     set extremely difficult. 
     Yes, it is more difficult to accomplish the required overall toolkit
     functionality without hacks, but I believe that our widget sets
     (be it XUI or Motif) must evolve - and any assumptions one widget
     makes about other widgets today may (and will) prevent any improvements
     tomorrow. 


-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                   marbru@auto-trol.COM
(303) 252-2499                    {...}ncar!ico!auto-trol!marbru
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404 

asente@decwrl.dec.com (Paul Asente) (03/14/90)

In article <774@auto-trol.UUCP> marbru@auto-trol.COM (Martin Brunecky) writes:
>In article <2999@bacchus.dec.com> asente@decwrl.dec.com (Paul Asente) writes:
>> ...(text deleted) .....  There are
>>plenty of cases in widget sets where a widget adds an event handler to its
>>parent, or to its children, or to some seemingly unrelated widget.
>>
>     I am not quite sure, but is THIS a good practice ? XUI and Motif
>     are full of instances where one widget munges another one, assuming 
>     intimate knowledge of it's internals, rather than documented
>     widget methods. This, however, makes any extension to such widget
>     set extremely difficult. 

Two good examples:

- A menu widget needs to deal with the implicit server grab on button
press and wants to pop down wherever the button release occurs.  It does
this by installing an event handler on its shell.

- A gadget wants to handle events, but it has no window.  It installs
event handlers on its parent to deal with the events.

In neither case does the widget make any assumptions about the internals
of other widgets; they just use the Intrinsics event handler semantics.  I
agree that having a widget implementation grub around in the internals of
another widget is lewd, crude, rude, and socially unacceptable, but this
is another thing entirely.

	-paul asente
	    asente@decwrl.dec.com	decwrl!asente