#1058626 pulsemixer: signal handler invokes curses.endwin()

#1058626#5
Date:
2023-12-13 18:53:41 UTC
From:
To:
Sending SIGINT to pulsemixer (e.g. by pressing Ctrl-C) prints a
traceback on stdout:

,----
| Traceback (most recent call last):
|   File "/usr/lib/python3.11/curses/__init__.py", line 94, in wrapper
|     return func(stdscr, *args, **kwds)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/usr/bin/pulsemixer", line 1275, in run
|     c = self.getch()
|         ^^^^^^^^^^^^
|   File "/usr/bin/pulsemixer", line 1103, in getch
|     self.ev.wait()
|   File "/usr/lib/python3.11/threading.py", line 629, in wait
|     signaled = self._cond.wait(timeout)
|                ^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/usr/lib/python3.11/threading.py", line 327, in wait
|     waiter.acquire()
|   File "/usr/bin/pulsemixer", line 1243, in <lambda>
|     signal.signal(signal.SIGINT, lambda s, f: self.terminate())
|                                               ^^^^^^^^^^^^^^^^
|   File "/usr/bin/pulsemixer", line 1228, in terminate
|     sys.exit()
| SystemExit
|
| During handling of the above exception, another exception occurred:
|
| Traceback (most recent call last):
|   File "/usr/bin/pulsemixer", line 2054, in <module>
|     main()
|   File "/usr/bin/pulsemixer", line 1948, in main
|     curses.wrapper(Screen(CFG.ui.color, CFG.ui.mouse).run)
|   File "/usr/lib/python3.11/curses/__init__.py", line 101, in wrapper
|     endwin()
| _curses.error: endwin() returned ERR
`----

The reason is that curses.endwin() is run twice, by the signal handler
pulsemixer sets up and by curses.wrapper.  In ncurses patchlevel
20231111 and later, calling endwin() twice in a row is considered an
error.  See bug #1058041 for more information.

This is the signal handler which pulsemixer sets up:

,----
|     def terminate(self):
|         # if ^C pressed while sleeping in reconnect wrapper.restore won't be called
|         # so have to restore it manually here
|         self.screen.keypad(0)
|         curses.echo()
|         curses.nocbreak()
|         curses.endwin()
|         sys.exit()
`----

I don't know if the comment is actually true, this should best be
discussed with upstream.  Unfortunately they have been inactive for the
last 3.5 years. :-(

#1058626#10
Date:
2026-08-22 10:07:08 UTC
From:
To:
Control: forwarded -1 https://github.com/GeorgeFilipkin/pulsemixer/issues/86

Somebody else also discovered the problem and reported it upstream, but
did not receive a reply so far.

Cheers,
       Sven