pytermgui icon indicating copy to clipboard operation
pytermgui copied to clipboard

[BUG] SIGINT exits leave terminal in dirty state

Open anthonyjmartinez opened this issue 3 years ago • 16 comments

Describe the bug When sending SIGINT (ctrl-c) to exit ptg the terminal continues to capture mouse input until the reset command is issued.

To Reproduce

  1. Install pytermgui
  2. Run ptg
  3. Exit with ctrl-c
  4. Push mouse buttons

Expected behavior Mouse events are not captured.

Screenshots ASCII cast here

System information

$ ptg --version
PyTermGUI v1.1.0
Python: 3.9.2
Platform: Linux-5.10.0-10-amd64-x86_64-with-glibc2.31
Git commit: 47bed90

anthonyjmartinez avatar Jan 15 '22 16:01 anthonyjmartinez

That actually seems to showcase another issue as well, in the window going out of the terminal screen on initial open. I'll look into this early next month when I have a Linux machine on hand, as I'm currently working out of my MacBook.

bczsalba avatar Jan 15 '22 20:01 bczsalba

@bczsalba I think you can close this now. The behavior doesn't exist with v4.0.0.

anthonyjmartinez avatar Mar 12 '22 17:03 anthonyjmartinez

Well I'm certainly glad to hear that! I have no idea what the issue was, what fixed it or when it was fixed but I'm glad it was!

Thank you for the report!

bczsalba avatar Mar 12 '22 18:03 bczsalba

Appears to have resurfaced with the latest release. Even a clean exit keeps capturing mouse clicks.

anthonyjmartinez avatar Apr 04 '22 22:04 anthonyjmartinez

I am beyond weirded out by this issue, happens without a clear reason, disappears the same way and then comes back again. The code that is most likely responsible here (WindowManager.__exit__) is part of a major refactor of its module over at compositor branch, so it might just get randomly fixed again :D.

Will look into it further, just in case.

bczsalba avatar Apr 05 '22 09:04 bczsalba

I've checked on my machine, which is running some variation of Ubuntu with i3 and the kitty terminal and couldn't reproduce this error on the new branch, though I didn't try it on master.

Could you check that out?

bczsalba avatar Apr 07 '22 06:04 bczsalba

It may take a few days before I'm able to take a look. I should note that I saw this even when WindowManager and the overall application exits with a clean status.

I'll look at the __exit__ handlers as well and let you know if I see anything that jumps out at me.

anthonyjmartinez avatar Apr 07 '22 20:04 anthonyjmartinez

That's alright! I think what's happening is the with mouse_handler context isn't being properly exited, but I have no clue why.

bczsalba avatar Apr 08 '22 22:04 bczsalba

Hey!

Have you been able to find anything? The compositor branch is now part of the latest release.

bczsalba avatar Apr 21 '22 09:04 bczsalba

Sorry for the delay. I've tried with the 5.0.0 release and launching ptg followed by killing it with ctrl-c still results in my terminal needing to be reset lest mouse actions be captured.

(venv) amartinez@scandium:~/Projects/learning/tui$ ptg --version
fatal: Needed a single revision
PyTermGUI v5.0.0

Python: 3.9.2
Platform: Linux-5.10.0-13-amd64-x86_64-with-glibc2.31

anthonyjmartinez avatar Apr 26 '22 23:04 anthonyjmartinez

This issue continues to bug me a lot, knowing nothing of its background. I think I've asked before but I'll do it again since it might have been in a different issue, which terminal is this behaviour exhibited on? There have been some issue with st and other minimal/modern terminals, as they didn't support the full xterm standard.

bczsalba avatar Apr 27 '22 14:04 bczsalba

This is in GNOME Terminal:

amartinez@scandium:~$ gnome-terminal --version
# GNOME Terminal 3.38.3 using VTE 0.66.1 +BIDI +GNUTLS +ICU +SYSTEMD

It doesn't happen in xterm or kitty so I guess one could elect to ignore whatever the root is, but I'll leave that to you. Probably worth an upstream bug report to zero in on the issue.

anthonyjmartinez avatar May 03 '22 23:05 anthonyjmartinez

Do other VTE-based emulators, such as Termite, have the same problem?

bczsalba avatar May 04 '22 08:05 bczsalba

It sure does. Able to reproduce in Termite.

anthonyjmartinez avatar May 06 '22 17:05 anthonyjmartinez

I guess it might be a VTE issue then! Probably could be worked around on my side, but not quite sure if I can as long as I don't understand the problem.

Would an upstream (towards VTE) issue be worth it, what do you think?

bczsalba avatar May 06 '22 18:05 bczsalba

I think it would be a good thing to ask about in an issue/question to the VTE maintainers. The bug should be fixed wherever the bug actually exists, but I don't know that it's possible to determine that without asking all sides.

anthonyjmartinez avatar May 06 '22 18:05 anthonyjmartinez

I am experiencing similar issue, but terminal prints symbols on mouse movement

nikolaevigor avatar Oct 13 '22 19:10 nikolaevigor

Just checking in, is this still an issue? I tried to see if the problem still happens but I couldn't figure out a way to get any VTE based terminals working on my current system.

bczsalba avatar Apr 20 '23 10:04 bczsalba

We are able to reproduce this relatively consistently across most machines in our company. Standard setups: Ubuntu 20.04, gnome terminal.

What always fixes this for us is ensuring our scripts run print("\x1b[?1002;1006l", flush=True) before exiting (i.e. functionally the equivalent of report_mouse(press_hold, decimal_xterm in pytermgui.ansi_interface).

That says to me the issue is definitely report_mouse() not being called to cleanup. Without digging to deeply, tracing the WindowManager.stop() codepath and __exit__() fns, I can't see where report_mouse() is expected to be being called?

But what does seem to be apparent is the CTRL-C exit path doesn't work by default (some weird capturing of that signal seems to be done on the manager side where it's not processed until ENTER is pressed?).

btalb avatar May 09 '23 04:05 btalb

@btalb Thank you, this bit is super useful! The mouse_handler context manager should do the cleanup, but I guess there might be some edge-case where it doesn't. The more confusing part is that it doesn't occur on a lot of systems (anything that isn't vte-based AFAIK), so I don't know if it's Python-side.

Specifically, the relevant code would be:

https://github.com/bczsalba/pytermgui/blob/b287562d65a31dd4a6105cb684abaec61377f820/pytermgui/context_managers.py#L147-L149

Could you maybe try inserting something error-raising (like 1/0) to line 148 (so it only executes if the report_mouse line also does)? I've confirmed that it works on my machine.

bczsalba avatar May 09 '23 11:05 bczsalba

Well I don't think these results help clear up anything :stuck_out_tongue: , but this is what I found:

  1. Add an exception after report_mouse() cleanup is run:
    finally:
        if event is not None:
            report_mouse(event, method=method, stop=True)
+           raise Exception("I've cleaned up after myself")
  1. Run our application
  2. Exit with CTRL-C, and see the exception reported:
  File "/usr/local/lib/python3.8/dist-packages/pytermgui/window_manager/manager.py", line 115, in __exit__
    self.run()
  File "/usr/local/lib/python3.8/dist-packages/pytermgui/window_manager/manager.py", line 195, in run
    self._run_input_loop()
  File "/usr/lib/python3.8/contextlib.py", line 131, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/local/lib/python3.8/dist-packages/pytermgui/context_managers.py", line 150, in mouse_handler
    raise Exception("I've cleaned up after myself")
Exception: I've cleaned up after myself
  1. Terminal is not in a good state

btalb avatar May 12 '23 04:05 btalb

Hmm, I don't really see what the issue could be then. It's even more annoying that it's terminal specific! What happens if you insert the line terminal.flush() above the report mouse call? Maybe it has a problem with partial sequences.

bczsalba avatar May 17 '23 13:05 bczsalba

I was also encountering this bug on the latest release (7.4.0). I noticed that it only occurs when I install the library from PyPI, and not when I install the library from Github. I diffed the files to see if there was anything obvious and found this in context_managers.py

From PyPI:

@contextmanager
def mouse_handler(
    events: list[str], method: str = "decimal_xterm"
) -> Generator[MouseTranslator, None, None]:

    event = None
    try:
        for event in events:
            report_mouse(event, method=method)

        yield lambda code: translate_mouse(code, method=method)

    finally:
        input(event)
        if event is not None:
            report_mouse(event, method=method, stop=True)

From Github:

@contextmanager
def mouse_handler(
    events: list[str], method: str = "decimal_xterm"
) -> Generator[MouseTranslator, None, None]:

    event = None
    try:
        for event in events:
            report_mouse(event, method=method)

        yield lambda code: translate_mouse(code, method=method)

    finally:
        if event is not None:
            report_mouse(event, method=method, stop=True)

The code is blocking on the input(event) call, and if you Ctrl+C here, then the cleanup code below will not run, leaving the terminal dirty, but any other keypress will exit normally.

stewartad avatar Jun 22 '23 22:06 stewartad

@stewartad Now that's fascinating! Just to confirm, the PyPi version exhibits the issue for you, but the GitHub one doesn't? Out of curiosity, which terminal emulator do you use?

bczsalba avatar Jun 23 '23 22:06 bczsalba

@bczsalba yes that's correct. This was using Alacritty

stewartad avatar Jun 23 '23 22:06 stewartad

@bczsalba I noticed that, in the report_mouse function, the hover event corresponds to control code 1003. According to the XTerm documentation, this enables both hover and button press tracking, while 1002 (press_hold) enables just button press tracking.

However, by default, WindowManager.run enables both press_hold and hover events. Enabling/disabling both of these at the same time seems to cause the dirty terminal state in my case, as when I call run myself only specifying ["hover"] for the mouse_events argument, the issue doesn't appear anymore.

This issue was happening independently of the one @stewartad described-- even when removing the blocking input(event), button presses were still being printed as seen in OP's case, requiring the above to fix.

All of this was in GNOME Terminal 3.44.0.

treamology avatar Jun 29 '23 21:06 treamology

So it seems to be a VTE-specific issue where disabling both events at the same time causes only one of them to fully disable? Now that I look at it both 1002 and 1003 does seem overkill, though I think the docs I saw mentioned 1002 as press/hold and 1003 as hover only. If that's wrong this might be a simple fix.

bczsalba avatar Jun 29 '23 23:06 bczsalba

@treamology Could you test out the latest commit? Using just 1003 seems to work fine, though I've never been able to recreate the issue so can't comment on that.

bczsalba avatar Jun 29 '23 23:06 bczsalba

Actually, looking at context_managers.py:148, it seems like the actual problem is that it's referencing the event variable without being inside a for loop. event remains set to the last value in the previous loop ('hover'), which causes press_hold to remain enabled. This seems to be what has the VTE-specific behavior.

Also, I'm not sure where the previous input(event) line came from, as not only does it not make sense for event to be passed to it in that way, it also doesn't seem to be present in any previous commits? Unless I'm just using GitHub's interface wrong...

treamology avatar Jun 29 '23 23:06 treamology

Actually, looking at context_managers.py:148, it seems like the actual problem is that it's referencing the event variable without being inside a for loop. event remains set to the last value in the previous loop ('hover'), which causes press_hold to remain enabled. This seems to be what has the VTE-specific behavior.

Oh my god, I think you've found it! That definitely seems like it would be the culprit. From what I can tell 1003 is enough as a single report setting already, so this problem never should have existed in the first place.

About the input(event), no clue either. Could have been something I accidentally slipped in while testing, could be a user-side change as well (though unlikely). The point is that it shouldn't have ever been there :)

I'll try to patch it out then, and come back with something that could work.

bczsalba avatar Jun 29 '23 23:06 bczsalba