Back to Contents Previous Next
27. Managing the quit/shutdown **
In the tutorial material early in Section 2, when we took action to quit the application it was simple and the application ended without further ado. However, in many cases we need to manage the quit process in a bit more detail.
For instance, there are frequently the following aspects to consider:
a) we may wish to do some ‘good housekeeping’ tidying up before the actual application closure (e.g. close files and/or fonts etc,);
b) there may be some unsaved data to take care of and we would therefore wish to abort (or pause temporarily) the quit action to allow this do be done.
In addition, the quit action may have been started by the user selecting ‘Shutdown’ from the Task Manager iconbar menu, intending to quit all running applications and ending the computer session.
All these cases need to be accomodated in a wimp program and Dr Wimp caters for them in a straightforward way, using a combination of FNuser_quit(type%)
and PROCwimp_quit(type%)
. These functions work closely together and use the same parameter: if type%=0
it means that an ‘application quit’ is involved, and if type%=1
it means that a Wimp ‘shutdown’ is involved. (These terms are explained shortly.) The return from FNuser_quit()
is critical: a return of 1 means that the application has no objection to quitting and a return of 0 means that the application does not wish to quit.
In the following descriptions we will be referring to a window called ‘warn’. So it would help at this point to start with a fresh copy of the skeleton !MyApp and copy the file “Template7” from the Tutorials folder (Tutor3 sub-directory) into !MyApp and rename to “Templates”. Then load the window into your tutorial !RunImage, with the handle warn%
- in the same way as we have done before - and have a look at the window in your template editor. It looks like this:
(The ‘Discard’ button is icon number 0 and the ‘Save’ button is icon number 2.)
The ‘application quit’ process
Firstly, let’s look at the process of quitting just your application i.e. no other running application is intended to be affected. For simplicity in this text we will call this an ‘application quit’. An ‘application quit’ can be initiated in two ways:
i) by calling
PROCwimp_quit(type%)
- with
type%
set to 0 - at some point within the application, typically by selecting ‘Quit’ from the application’s iconbar menu and making the call within
PROCuser_menuselection()
(as was done in Section 2.2); or
ii) via the Task Display menu.
Either way, the result is that Dr Wimp causes FNuser_quit(type%)
to be called, with type%
set to 0 - the 0 meaning that an ‘application quit’ has been started, as opposed to a ‘shutdown’.
If you set the return from this call to be 1 (don’t confuse the return value with the type%
value!) then, without more ado, the application will quit. However, if the return is set to 0 the quit will not take place. It is as simple as that.
So, assuming we want to to stop an application quit if there is some unsaved data, we would need a structure something like this (Don’t alter your tutorial !RunImage yet):
DEF FNuser_quit(type%)
return%=1
IF type%=0 AND unsaved%=TRUE THEN
PROCwimp_menupopup
(warn%,2,0,0)
return%=0
ENDIF
=return%
Here we are assuming that the variable unsaved%
is a flag which is set to TRUE/FALSE
within the program according to whether or not unsaved data exists. If type%
is 0 then the above routine will stop the quit - by returning 0 - and open the (previously loaded) warning window called warn%
.
Action on the Discard/Save buttons in the warn%
window will take place - as usual - in PROCuser_mouseclick
, and might look like this:
DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
WHEN warn%
CASE icon% OF
WHEN 0:REM** Icon number of ‘Discard’ icon. **
unsaved%=FALSE
PROCwimp_closewindow(warn%)
PROCwimp_quit(0)
WHEN 2:REM** Icon number of ‘Save data’ icon. **
PROCwimp_closewindow(warn%)
ENDCASE
ENDCASE
ENDPROC
As you can see, clicking the ‘Discard’ button would set the unsaved%
flag to FALSE
and call PROCwimp_quit(0)
i.e. call for an ‘application quit’ again. This, in turn, would call the previous FNuser_quit()
routine again - but this time the result will be a return value of 0, because unsaved%
is now FALSE
.
If we had clicked on the ‘Save’ button, no action would occur - other than closing the window - and the application continues to run unchanged, allowing us to save the data (and subsequently initiating an ‘application quit’ again, if we wish).
If we wanted to add some ‘good housekeeping’ we would need to extend the above to something like:
DEF FNuser_quit(type%)
return%=1
IF type%=0 AND unsaved%=TRUE THEN
PROCwimp_menupopup
(warn%,2,0,0)
return%=0
ELSE
IF type%=0 THEN
PROCapp_housekeeping
ENDIF
ENDIF
=return%
This would ensure that the housekeeping only takes place if it is an ‘application quit’ and there is no unsaved data. The reason for this tight constraint will become clearer below.
(Note: The above are illustrative only and not intended to be used in the Tutorial !RunImage.)
Wimp ‘shutdown’
As was said earlier, quitting action can also be started by the user selecting ‘Shutdown’ from the Task Manager iconbar menu: thereby intending to quit all running applications and end the computer session. We will call this ‘shutdown’ to distinguish it from an ‘application quit’.
In this case, the Wimp needs to cater for all running applications and give them each a chance to halt the process. The Wimp has a standard routine for this and Dr Wimp manages this behind the scenes - but it will help to outline the procedure.
When a shutdown is initiated, the Wimp sends a ‘pre-quit’ message to each running application, asking them in turn if they have any objection to quitting. If an application is ready to quit (i.e. has no objection) then it simply ignores the message. However, if an application does not wish to quit then it returns a reply to the Wimp and the whole shutdown is aborted.
(Note that as the Wimp effectively asks each running application in turn, the shutdown is aborted by the first objection and there could well be other applications who would have objected subsequently if the ‘pre-quit’ message had reached them.)
The most common reason for not wanting to quit is that an application has some unsaved data, and the usual process then is for the application to send the Wimp its objection and then give the user a choice of saving the data or discarding it. If the user decides to discard it the approved Wimp procedure is for the application to then re-initiate the shutdown process itself - giving the remaining applications the opportunity to object. Please note that this is the only circumstance where a Dr Wimp application should (re-)initiate the wimp shutdown process.
Further, what happens if our application gets the ‘pre-quit’ message and ignores it (i.e. has no objection to quitting) but a subsequent application makes an objection and the shutdown is aborted? What should our application do in that case?
By and large, most users would probably want our application to continue as if nothing had happened (i.e. ‘good housekeeping’ actions and/or quitting would not be expected) - but note that there is no recommended practice here and certainly some well-known applications still quit in these circumstances.
How are these shutdown issues handled in the coding? The main point to note is that when the ‘pre-quit’ message is received by your application Dr Wimp arranges - as it did for the ‘application quit’ case above - for FNuser_quit(type%)
to be called. But this time with type%
set to 1, so you know that it is the start of a shutdown action.
If you have no objection to quitting then, as before, you set the return from this call to be 1 (again, don’t confuse the return value with the type%
value!). Alternatively, if you wish to stop the shutdown action you set the return to 0.
So far, therefore, the actions are the same as for an ‘application quit’ and the fundamental coding might look like this (again, for illustrative purposes only):
DEF FNuser_quit(type%)
return%=1
IF type%=1 AND unsaved%=TRUE THEN
PROCwimp_menupopup
(warn%,2,0,0)
return%=0
ENDIF
=return%
which is exactly as before except that the IF
line starts with IF type%=1 AND ....
The only difference happens behind the scenes. If you return 0 then Dr Wimp sends a special message to the Wimp notifying it of your objection.
However, we still need to take account of the point that - for the shutdown case only - if we offer the user the chance to save the unsaved data (as we do by opening the warn%
window above) then we need to re-start the shutdown process if the user decides to discard the unsaved data. We effect this by modifying the response to the warn%
window button click coding, as follows:
DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
WHEN warn%
CASE icon% OF
WHEN 0:REM** Icon number of ‘Discard’ icon. **
unsaved%=FALSE
PROCwimp_closewindow(warn%)
PROCwimp_quit(1)
WHEN 2:REM** Icon number of ‘Save data’ icon. **
PROCwimp_closewindow(warn%)
ENDCASE
ENDCASE
ENDPROC
The only change from the ‘application quit’ case being the calling of PROCwimp_quit(1)
rather than PROCwimp_quit(0)
. Thus, remembering that we have already halted a ‘shutdown’, this coding actually calls for the shutdown to be re-started if ‘Discard’ is chosen - and Dr Wimp duly takes the necessary action behind the scenes.
Practical coding
The above two subsections have sought to illustrate the ‘application quit’ and ‘shutdown’ processes separately, in order to aid understanding. However, in practice their coding needs to be combined because the application may be subject to either case at any time. Fortunately, as we have seen, the separate codings are almost the same so it is a very small matter to arrive at a typical practical coding.
So this time, make the following changes to !RunImage in your fresh copy of !MyApp:
a) Incorporate the Templates from ‘Template7’ as stated earlier in this Section.
b) also as stated earlier, add the line:
warn%=FNwimp_loadwindow(“<MyApp$Dir>.Templates”,“warn”,0)
to PROCuser_initialise
.
c) now add the line:
unsaved%=FALSE
to PROCuser_initialise
.
d) Make DEF FNuser_quit()
look like this:
DEF FNuser_quit(type%)
return%=1
IF unsaved%=TRUE THEN
PROCwimp_menupopup(warn%,2,0,0)
quittype%=type%
return%=0
ENDIF
=return%
e) Make DEF PROCuser_mouseclick()
look like this:
DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
IF window%=iconbar% THEN PROCwimp_openwindow(main%,1,-1)
IF window%=main% AND icon%=2 AND unsaved%=FALSE THEN
unsaved%=TRUE
title$=FNwimp_getwindowtitle(main%)
PROCwimp_putwindowtitle(main%,title$+“*”)
ENDIF
IF window%=warn% AND icon%=0 THEN
unsaved%=FALSE
PROCwimp_closewindow(warn%)
PROCwimp_quit(quittype%)
ENDIF
IF window%=warn% AND icon%=2 THEN PROCwimp_closewindow(warn%)
ENDPROC
Examination shows that we have amalgamated the separate cases neatly by merely introducing the new global variable quittype%
into FNuser_quit()
and using its value in PROCuser_mouseclick()
. This new variable only comes into play when the user wants to stop the quitting action - whether initiated as an ‘application quit’ or a ‘shutdown’. (You will also see that IF THEN
statements have been used instead of the previously shown CASE
statements. This is solely to keep the tutorial !RunImage coding consistent with what was already there - but it also demonstrates that Basic usually offers more than one way of achieving an end result .......)
[Your !RunImage listing should now look like listing RI_11 in Tutor3
(apart from the REM
lines, perhaps). This listing is not altered further - and there are no further tutorial listings.]
In order to inject a further element of realism, the above coding also arranges things so that clicking the ‘OK’ button of the main window will trigger the unsaved data status and show this in the main window title in the usual way - by adding an asterisk to it.
Now, run !MyApp, open the main window and click the ‘OK’ button. An asterisk should appear on the title bar.
Now try to quit the application by selecting ‘Quit’ from the iconbar menu. The warn%
window appears and allows the user to choose what happens next - as described earlier.
Check the similar action on selecting ‘Shutdown’ from the Task Manager iconbar menu.....
..... and there you have it.
Note that the above coding does not include refinements for:
i) removing the asterisk from the main window title if ‘Discard’ is chosen;
ii) incorporating the ‘good housekeping’ addition shown in the ‘application quit’ sub-section.
which you should be able to tackle without difficulty.
These refinements are also related to your decision as to whether or not your application is to quit if a shutdown is initiated and another application halts the shutdown after your application has said it is ready to quit. If, in that circumstance, you decide that your application should continue to function then you will not want to take the ‘good housekeeping’ steps.
Another user-friendly feature you might want to consider when the user opts to save some unsaved data, is to arrange for the appropriate ‘Save’ window to open, ready for the save action to take place.
Final points
The above descriptions are worth re-reading because, although the fundamentals are really fairly simple, the action flows very circularly between FNuser_quit()
and PROCwimp_quit()
and at first it is easy to mix up the value of the parameter type%
and the return value from FNuser_quit()
.
The only vital point to remember is to be very wary of using the call:
PROCwimp_quit(1)
i.e. as opposed to PROCwimp_quit(0)
because the only occasion that it has meaning is when your application needs to re-start a shutdown that it has just interrupted. If you attempt to use this call at any other time you will get a (non-fatal) error message.
(Please note that PROCwimp_quit(0) is actually designed to exit the main Wimp Poll process, so it should only be called from within a user-function structure - as is the case in the many instances in this Manual.)
Top of page Back to Contents Previous Next