All,
I'm still concerned about cross platform compatibility and the lack of
control a programmer seems to have when the macOS specific Command-Q
keyboard shortcut is used as it is now. I have to admit that I didn't
find much documentation about Command-Q or what it should do. The "best"
;-) documentation I found was in "Mac keyboard shortcuts":
Command-Q Quit the app.
https://support.apple.com/en-us/HT201236
What does that mean? I think this should be an action comparable with
the application menu in many apps I'm used to: CTRL-Q = "Quit". Note
that it doesn't say "Abort the app" which would IMHO mean an emergency
exit. "Quit the app" seems more like a graceful exit.
Although a user often wouldn't mind I think the current behavior of
Command-Q is bad since the app programmer doesn't have control over the
behavior, particularly if the app has a menu that uses CTRL-Q to quit
the app which likely calls a menu callback function so the programmer
gets control _before_ any windows are closed. In this menu callback
(quit function) a programmer can check things like open documents, open
network connections, and ask the user if he wants to quit. Only if the
user confirms the application does its cleanup and quits.
The OP reported that global destructors were not called when he used
Command-Q. Is this really true? Besides the fact that the programmer has
no control over the quitting process (other than not to close the
windows when the window callbacks are called) this seems to be *really*
bad to me. It sounds as if _exit() or something similar to `kill -9' is
called to abort the program right away after the windows are closed. Not
running global destructors (of static objects) seems to be a bad
decision. Again, is this really true? Can anybody confirm this? I would
test it, but I don't have a Mac at hand. ;-)
Given this report of a "hard exit" or abort I have to ask: Manolo, did
you confirm with your posted hello program that the
void termination() {
printf("Run termination code here\n");
}
that is established with 'atexit(termination)' is really called when
Command-Q is used (and VERSION1 is defined as 1)? I assume you did, but
just for confirmation, to be absolutely sure. I'm asking because
functions registered with atexit() are usually not called when you call
_exit() as opposed to calling exit(). [3]
I don't know what macOS does internally after it receives the return
value NSTerminateNow, it may be something totally different.
That all said, I think that we should have a user (programmer) option to
modify the handling of Command-Q as Greg proposed and the OP confirmed.
A possible solution:
I believe the best we could do is to add a function to register a "Quit
Handler" [1] so the programmer gets control _before_ FLTK's internal
Command-Q processing sends FL_CLOSE events to all windows. This
registered handler function could return an int value to the internal
processing to tell what to do next, something like:
0: not handled - continue sending FL_CLOSE events as it is now (and in
FLTK 1.3.x), return NSTerminateNow (IMHO not recommended).
1: handled - send FL_CLOSE events to all windows, but don't return
NSTerminateNow (return NSTerminateCancel instead). This would close all
windows and return from Fl::run() or equivalent (Fl::wait()) and let the
programmer do the cleanup after Fl::run(). This would be compatible with
the normal rundown of an app when the user closes all windows. Hence
Command-Q would be a simple shortcut for closing all windows, but the
order of the windows getting FL_CLOSE events may be arbitrary.
-1 (or 2 or whatever): handled - abort the Command-Q processing
immediately, don't send FL_CLOSE events and return NSTerminateCancel.
This could be used for instance if there are open files and the user did
not confirm the question (popup window) to save the file(s) and exit,
maybe because he typed Command-Q accidentally. [2]
Of course there could be other options I didn't think of yet. The main
reason to have such a function is to give the application _programmer_
more control over quitting the app (at least if they decide to register
a handler). The current behavior to send FL_CLOSE events can also lead
to closing windows in a suboptimal order: for instance closing a main
window before closing another modal window that is related to the main
window or closing windows in any arbitrary order. If the programmer
would have taken care that a window is NOT closed by receiving the
FL_CLOSE event, i.e. in its window callback, then there would be a
chance that all the other windows have been closed before the last
window prevents closing of the app. This looks like asking for trouble...
I'm not sure what the best default value of the returned value of the
"Quit Handler" would be (i.e. the behavior of Command-Q in FLTK if no
handler was registered). I think I'd prefer the _modified_ behavior
(compared to FLTK 1.3.4 and 1.4-current) as if the handler returned 1 in
my proposal (above). This would give the application the best cross
platform behavior: close all windows as if the user closed them all
manually, but return from Fl::run() so the application can run cleanup
code after Fl::run() and exit normally which calls all global / static
destructors.
I'm open for comments and other suggestions. All comments are welcome.
Here is a simple example of a "Quit Handler":
// This is called only under macOS from the system menu Command-Q
int quit_handler( .. ) {
quit_cb(); // call my program's "quit" menu callback
// Note: quit_cb() would close all windows (or not if
// the user didn't confirm to quit for some reason)
return -1; // don't send FL_CLOSE, let me control the exit
}
-----
[1] I propose to make this a cross platform function and call it "Quit
Handler" so we can extend it to other platforms than macOS if necessary.
Documentation should explain that this handler is currently only used by
the macOS Command-Q processing. Maybe other platforms like IOS or
Android would also have such a Command-Q key?
[2] When I searched for Command-Q I found *lots* of questions from users
how to *disable* Command-Q, particularly in Safari when they wanted to
close a tab with Command-W but accidentally hit Command-Q where Safari
closes all tabs and quits. IMHO we should not add FLTK apps to this
typical user problem. ;-)
[3] From `man _exit' (Linux, if that matters):
"The function _exit() is like exit(3), but does not call any functions
registered with atexit(3) or on_exit(3)."