Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IDLE on macOS will close without warning when there are open unsaved files #112898

Open
ronaldoussoren opened this issue Dec 9, 2023 · 19 comments
Labels
OS-mac topic-IDLE topic-tkinter type-bug An unexpected behavior, bug, or error

Comments

@ronaldoussoren
Copy link
Contributor

ronaldoussoren commented Dec 9, 2023

Bug report

Bug description:

To reproduce:

  • Start IDLE by launching the IDLE.app included with our installers
  • Create a new file or open an existing file
  • Modify that file by typing into it
  • Quit IDLE

Expected behaviour:

  • IDLE warns about unsaved open files before quitting

Actual behaviour:

  • IDLE quits without warning, losing work

CPython versions tested on:

3.11, 3.12, 3.13

Operating systems tested on:

macOS

Linked PRs

@terryjreedy
Copy link
Member

terryjreedy commented Dec 10, 2023

Is "launching IDLE.app" what I do when I click the an icon in either Finder or the dock? Either way, I have no the same issue on my MacBook Air Catalina. On Windows, I see a Save On Close box with, for instance, "Do you want to save this untitled file before closing?".

The box is a tkinter.message.askyesnocancel box called in idlelib.iomenu.IOBinding.maybesave, which is called in editor.EditorWindow.maybesave. Tkinter.message calls code in other tkinter dialog submodules.

EDIT: Change no to the same as I must have only tested closing the window and not IDLE completely. Adjust other text.

@chrstphrchvz
Copy link
Contributor

I observe this when using “Quit” from the app menu and the dock icon menu, and using Command-Q. I suspect this has always been the case on Tk Aqua and does not have to do with the macOS or Tcl/Tk version. Apparently the way to prevent this is to override the Tcl proc ::tk::mac::Quit.

@ronaldoussoren
Copy link
Contributor Author

Is "launching IDLE.app" what I do when I click the an icon in either Finder or the dock?

I double clicked on the IDLE.app in the finder to start IDLE.

@ronaldoussoren
Copy link
Contributor Author

I observe this when using “Quit” from the app menu and the dock icon menu, and using Command-Q. I suspect this has always been the case on Tk Aqua and does not have to do with the macOS or Tcl/Tk version. Apparently the way to prevent this is to override the Tcl proc ::tk::mac::Quit.

I'll see if implementing this for IDLE helps here.

@chrstphrchvz
Copy link
Contributor

I think this is the spot where IDLE already tries to prevent Tk Aqua from closing:

if flist:
root.bind('<<close-all-windows>>', flist.close_all_callback)
# The binding above doesn't reliably work on all versions of Tk
# on macOS. Adding command definition below does seem to do the
# right thing for now.
root.createcommand('exit', flist.close_all_callback)

Replacing exit with ::tk::mac::Quit seems to work as expected. Even in wish, redefining the exit proc does not prevent Tk Aqua from closing.

@chrstphrchvz
Copy link
Contributor

I suspect this has always been the case on Tk Aqua and does not have to do with the macOS or Tcl/Tk version.

I was wrong. This behavior was introduced in Tk 8.6.11 (late 2020) by this change: https://core.tcl-lang.org/tk/info/a055a4fa5c68
…which was part of the attempted fix for https://core.tcl-lang.org/tk/info/c2483bfe4b

ronaldoussoren added a commit to ronaldoussoren/cpython that referenced this issue Dec 10, 2023
Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE.
@ronaldoussoren
Copy link
Contributor Author

ronaldoussoren commented Dec 10, 2023

I think this is the spot where IDLE already tries to prevent Tk Aqua from closing:

if flist:
root.bind('<<close-all-windows>>', flist.close_all_callback)
# The binding above doesn't reliably work on all versions of Tk
# on macOS. Adding command definition below does seem to do the
# right thing for now.
root.createcommand('exit', flist.close_all_callback)

Replacing exit with ::tk::mac::Quit seems to work as expected. Even in wish, redefining the exit proc does not prevent Tk Aqua from closing.

Thanks, that's a better fix that I had initially.

UPDATE: I've added you as a co-author to the PR I created earlier.

@serhiy-storchaka
Copy link
Member

There is other problem here. close_all_callback() allows the user to cancel closing. But ::tk::mac::Quit doe not support cancelling. If the user choses the "Cancel" option they can lose their changes not only in the asked file, but in other not asked files.

ronaldoussoren added a commit that referenced this issue Dec 11, 2023
)

* gh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE. 

Co-authored-by: Christopher Chavez chrischavez@gmx.us
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Dec 11, 2023
…pythonGH-112939)

* pythongh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE.

(cherry picked from commit 3251ba8)

Co-authored-by: Ronald Oussoren <ronaldoussoren@mac.com>
Co-authored-by: Christopher Chavez chrischavez@gmx.us
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Dec 11, 2023
…pythonGH-112939)

* pythongh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE.

(cherry picked from commit 3251ba8)

Co-authored-by: Ronald Oussoren <ronaldoussoren@mac.com>
Co-authored-by: Christopher Chavez chrischavez@gmx.us
@ronaldoussoren
Copy link
Contributor Author

There is other problem here. close_all_callback() allows the user to cancel closing. But ::tk::mac::Quit doe not support cancelling. If the user choses the "Cancel" option they can lose their changes not only in the asked file, but in other not asked files.

I don't understand why, but... If I choose "cancel" in the dialog that asks about saving IDLE keeps running, IDLE only quits when I choose Yes or No.

Could this be because EditorWindow._close is never called when the user chooses "cancel"?

I'm not really a Tkinter user, all my changes are done by emulation surrounding code without deep knowledge about Tk/Tkinter.

@ronaldoussoren
Copy link
Contributor Author

Clicked "comment" too soon... One think I did notice when testing what happens when I choose "cancel": the dialog gets shown a second time.

ronaldoussoren added a commit that referenced this issue Dec 11, 2023
GH-112939) (#112960)

gh-112898: warn about unsaved files when quitting IDLE on macOS (GH-112939)

* gh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE.

(cherry picked from commit 3251ba8)


Co-authored-by: Christopher Chavez chrischavez@gmx.us

Co-authored-by: Ronald Oussoren <ronaldoussoren@mac.com>
ronaldoussoren added a commit that referenced this issue Dec 11, 2023
GH-112939) (#112961)

gh-112898: warn about unsaved files when quitting IDLE on macOS (GH-112939)

* gh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE.

(cherry picked from commit 3251ba8)


Co-authored-by: Christopher Chavez chrischavez@gmx.us

Co-authored-by: Ronald Oussoren <ronaldoussoren@mac.com>
@ronaldoussoren
Copy link
Contributor Author

Leaving the issue open for now to further investigate the "cancel" issue mentioned by Serhiy.

@serhiy-storchaka
Copy link
Member

Try to comment out line root.bind('<<close-all-windows>>', flist.close_all_callback) above. Does it change anything? There is also line text.bind("<<close-all-windows>>", self.flist.close_all_callback) in editor.py, try to comment out it too.

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Dec 12, 2023
…se" dialog

On macOS, when it is asked just before quiting the application, the user
has no option to cancel quiting.
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Dec 12, 2023
…se" dialog

On macOS, when it is asked just before quiting the application, the user
has no option to cancel quiting.
@chrstphrchvz
Copy link
Contributor

chrstphrchvz commented Dec 12, 2023

There is other problem here. close_all_callback() allows the user to cancel closing. But ::tk::mac::Quit doe not support cancelling. If the user choses the "Cancel" option they can lose their changes not only in the asked file, but in other not asked files.

I have not tried #112994, but currently I either do not understand Serhiy’s concern, or I have not observed it.

Something I do observe is that when quitting IDLE (i.e. close_all_callback() invoked), it attempts to close files in order, such that if “Cancel” is pressed for an unsaved file, then some already saved files will have been closed while other already-saved files are still open, which seems possibly undesirable.

One think I did notice when testing what happens when I choose "cancel": the dialog gets shown a second time.

Ronald, are you referring to the duplicated dialog which occurs after pressing Command-Q and then canceling? That appears to be caused by this binding:

close-all-windows = <Command-Key-q>

Currently I would suggest removing this binding in favor of only relying on ::tk::mac::Quit to invoke close_all_callback(). But how does one assign nothing (not even a default fallback) to a binding in config-keys.def? (Edit: maybe try binding to a practically nonexistent key like F35, see #113513 (comment))

@ronaldoussoren
Copy link
Contributor Author

I'll look at this later this week.

@chrstphrchvz
Copy link
Contributor

Replacing exit with ::tk::mac::Quit seems to work as expected. Even in wish, redefining the exit proc does not prevent Tk Aqua from closing.

This behavior was introduced in Tk 8.6.11 (late 2020) by this change: https://core.tcl-lang.org/tk/info/a055a4fa5c68

Although defining ::tk::mac::Quit instead of exit could be more semantically appropriate for IDLE, the change in Tk Aqua 8.6.11 is still inconsistent with documentation, so I have opened an upstream ticket: https://core.tcl-lang.org/tk/info/8f92d112b0e4

ronaldoussoren added a commit to ronaldoussoren/cpython that referenced this issue Dec 27, 2023
…iles

Without this changeset I get two consecutive dialogs asking
if I want to save an unsafed file, when choosing "Cancel" in the
first one.
@ronaldoussoren
Copy link
Contributor Author

#113513 fixes the second dialog for me.

Sorry about the delay in looking into this.

@chrstphrchvz
Copy link
Contributor

As I point out in #113513 (comment):

In Tk Aqua, the first Tk interpreter (i.e. the first Tcl interpreter to load Tk) is the one that will receive Apple high-level events, such as quitting. …This means that defining ::tk::mac::Quit is only effective when done from the first created Tk interpreter.

This was true even before 8.6.11, but I would emphasize that if IDLE is going to rely on ::tk::mac::Quit, then IDLE must make sure it is responsible for creating the first tkinter.Tk() instance. Those who write Tk programs in Tcl syntax likely do not consider this a burden, because they typically only use the interpreter created for them by tclsh or wish (which is also why some Tcl/Tk issues, such as gh-71383 and gh-92603, tend to be encountered more easily from Tkinter than from pure Tcl).

@ronaldoussoren
Copy link
Contributor Author

As I point out in #113513 (comment):

In Tk Aqua, the first Tk interpreter (i.e. the first Tcl interpreter to load Tk) is the one that will receive Apple high-level events, such as quitting. …This means that defining ::tk::mac::Quit is only effective when done from the first created Tk interpreter.

This was true even before 8.6.11, but I would emphasize that if IDLE is going to rely on ::tk::mac::Quit, then IDLE must make sure it is responsible for creating the first tkinter.Tk() instance.

Is this also true for other high-level event commands, such as ::tk::mac::ShowPreferences, ::tk::mac::ShowHelp and ::tk::mac::OpenDocument (all of them in macosx.py)?

It might be possible to avoid creating multiple Tk instances, AFAIK macosx.py is currently the only file in IDLE that creates a throwaway instance of tkinter.Tk() and it should be possible to store the "real" tkinter.Tk() instance as a module variable for reuse by macosx._init_tk_type.

@chrstphrchvz
Copy link
Contributor

Is this also true for other high-level event commands, such as ::tk::mac::ShowPreferences, ::tk::mac::ShowHelp and ::tk::mac::OpenDocument (all of them in macosx.py)?

Yes.

ronaldoussoren added a commit to ronaldoussoren/cpython that referenced this issue Jan 9, 2024
terryjreedy added a commit to ronaldoussoren/cpython that referenced this issue Feb 4, 2024
ronaldoussoren added a commit to ronaldoussoren/cpython that referenced this issue Feb 10, 2024
aisk pushed a commit to aisk/cpython that referenced this issue Feb 11, 2024
…python#112939)

* pythongh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE. 

Co-authored-by: Christopher Chavez chrischavez@gmx.us
Glyphack pushed a commit to Glyphack/cpython that referenced this issue Sep 2, 2024
…python#112939)

* pythongh-112898: warn about unsaved files when quitting IDLE on macOS

Implement the TK function ``::tk::mac::Quit`` on macOS to
ensure that IDLE asks about saving unsaved files when
quitting IDLE. 

Co-authored-by: Christopher Chavez chrischavez@gmx.us
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS-mac topic-IDLE topic-tkinter type-bug An unexpected behavior, bug, or error
Projects
Status: No status
Development

No branches or pull requests

4 participants