Skip to content

Commit 7fc8725

Browse files
fix(driver): allow different signal masks between darwin and Linux
1 parent 45b2276 commit 7fc8725

6 files changed

Lines changed: 148 additions & 49 deletions

File tree

libs/pyTermTk/TermTk/TTkCore/TTkTerm/term_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def escTitle(txt = "") -> str:
152152
# those methods are supposed to be overwritten with the
153153
# compatible one in "term_unix.py" or "term_pyodide.py"
154154
setSigmask = lambda *args: None
155+
getSigmask = lambda *args: 0x00
155156
push = lambda *args: None
156157
flush = lambda *args: None
157158
setEcho = lambda *args: None

libs/pyTermTk/TermTk/TTkCore/drivers/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@
1010

1111
if os.environ.get("TERMTK_GPM",False):
1212
from .unix_gpm import *
13-
from .term_unix import *
13+
# from .term_unix import *
14+
from .term_unix_linux import *
1415
else:
1516
from .unix import *
1617
if os.environ.get("TERMTK_FORCESERIAL",False):
1718
from .term_unix_serial import *
1819
else:
19-
from .term_unix import *
20+
# from .term_unix import *
21+
from .term_unix_linux import *
2022

2123
elif platform.system() == 'Darwin':
2224
from .unix import *
23-
from .term_unix import *
25+
# from .term_unix import *
26+
from .term_unix_darwin import *
2427

2528
elif platform.system() == 'Windows':
2629
from .windows import *

libs/pyTermTk/TermTk/TTkCore/drivers/term_unix.py renamed to libs/pyTermTk/TermTk/TTkCore/drivers/term_unix_common.py

Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222

23-
__all__ = ['TTkTerm']
23+
__all__ = ['_TTkTerm']
2424

2525
import sys, os, signal
2626
from threading import Thread, Lock
@@ -33,7 +33,7 @@
3333
from ..TTkTerm.term_base import TTkTermBase
3434
from TermTk.TTkCore.log import TTkLog
3535

36-
class TTkTerm(TTkTermBase):
36+
class _TTkTerm(TTkTermBase):
3737
_sigWinChCb = None
3838

3939
# Save treminal attributes during the initialization in order to
@@ -47,46 +47,20 @@ class TTkTerm(TTkTermBase):
4747
_termAttrBk = []
4848
@staticmethod
4949
def saveTermAttr():
50-
TTkTerm._termAttrBk.append(termios.tcgetattr(sys.stdin))
50+
_TTkTerm._termAttrBk.append(termios.tcgetattr(sys.stdin))
5151

5252
@staticmethod
5353
def restoreTermAttr():
54-
if TTkTerm._termAttrBk:
55-
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, TTkTerm._termAttrBk.pop())
56-
elif TTkTerm._termAttr:
57-
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, TTkTerm._termAttr)
58-
59-
@staticmethod
60-
def _setSigmask(mask, value=True):
61-
attr = termios.tcgetattr(sys.stdin)
62-
if mask & TTkTerm.Sigmask.CTRL_C:
63-
attr[6][termios.VINTR]= b'\x03' if value else 0
64-
if mask & TTkTerm.Sigmask.CTRL_S:
65-
attr[6][termios.VSTOP]= b'\x13' if value else 0
66-
if mask & TTkTerm.Sigmask.CTRL_Z:
67-
attr[6][termios.VSUSP]= b'\x1a' if value else 0
68-
if mask & TTkTerm.Sigmask.CTRL_Q:
69-
attr[6][termios.VSTART]= b'\x11' if value else 0
70-
if mask & TTkTerm.Sigmask.CTRL_Y:
71-
attr[6][termios.VDSUSP]= b'\x19' if value else 0
72-
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, attr)
73-
TTkTermBase.setSigmask = _setSigmask
74-
75-
@staticmethod
76-
def getSigmask():
77-
mask = 0x00
78-
attr = termios.tcgetattr(sys.stdin)
79-
mask |= TTkTerm.Sigmask.CTRL_C if attr[6][termios.VINTR] else 0
80-
mask |= TTkTerm.Sigmask.CTRL_S if attr[6][termios.VSTOP] else 0
81-
mask |= TTkTerm.Sigmask.CTRL_Z if attr[6][termios.VSUSP] else 0
82-
mask |= TTkTerm.Sigmask.CTRL_Q if attr[6][termios.VSTART] else 0
83-
return mask
54+
if _TTkTerm._termAttrBk:
55+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, _TTkTerm._termAttrBk.pop())
56+
elif _TTkTerm._termAttr:
57+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, _TTkTerm._termAttr)
8458

8559
@staticmethod
8660
def exit():
8761
TTkTermBase.exit()
88-
if TTkTerm._termAttr:
89-
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, TTkTerm._termAttr)
62+
if _TTkTerm._termAttr:
63+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, _TTkTerm._termAttr)
9064

9165
@staticmethod
9266
def _push(*args):
@@ -136,21 +110,21 @@ def _getTerminalSize():
136110

137111
@staticmethod
138112
def _sigWinChThreaded():
139-
if not TTkTerm._sigWinChMutex.acquire(blocking=False): return
140-
while (TTkTerm.width, TTkTerm.height) != (wh:=TTkTerm.getTerminalSize()):
141-
TTkTerm.width, TTkTerm.height = wh
142-
if TTkTerm._sigWinChCb is not None:
143-
TTkTerm._sigWinChCb(TTkTerm.width, TTkTerm.height)
144-
TTkTerm._sigWinChMutex.release()
113+
if not _TTkTerm._sigWinChMutex.acquire(blocking=False): return
114+
while (_TTkTerm.width, _TTkTerm.height) != (wh:=_TTkTerm.getTerminalSize()):
115+
_TTkTerm.width, _TTkTerm.height = wh
116+
if _TTkTerm._sigWinChCb is not None:
117+
_TTkTerm._sigWinChCb(_TTkTerm.width, _TTkTerm.height)
118+
_TTkTerm._sigWinChMutex.release()
145119

146120
@staticmethod
147121
def _sigWinCh(signum, frame):
148-
Thread(target=TTkTerm._sigWinChThreaded).start()
122+
Thread(target=_TTkTerm._sigWinChThreaded).start()
149123

150124
@staticmethod
151125
def _registerResizeCb(callback):
152-
TTkTerm._sigWinChCb = callback
126+
_TTkTerm._sigWinChCb = callback
153127
# Dummy call to retrieve the terminal size
154-
TTkTerm._sigWinCh(signal.SIGWINCH, None)
155-
signal.signal(signal.SIGWINCH, TTkTerm._sigWinCh)
128+
_TTkTerm._sigWinCh(signal.SIGWINCH, None)
129+
signal.signal(signal.SIGWINCH, _TTkTerm._sigWinCh)
156130
TTkTermBase.registerResizeCb = _registerResizeCb
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2025 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
__all__ = ['TTkTerm']
24+
25+
import sys
26+
27+
try: import termios
28+
except Exception as e:
29+
print(f'ERROR: {e}')
30+
exit(1)
31+
32+
from ..TTkTerm.term_base import TTkTermBase
33+
from .term_unix_common import _TTkTerm
34+
35+
class TTkTerm(_TTkTerm):
36+
@staticmethod
37+
def _setSigmask(mask, value=True):
38+
attr = termios.tcgetattr(sys.stdin)
39+
if mask & TTkTerm.Sigmask.CTRL_C:
40+
attr[6][termios.VINTR]= b'\x03' if value else 0
41+
if mask & TTkTerm.Sigmask.CTRL_S:
42+
attr[6][termios.VSTOP]= b'\x13' if value else 0
43+
if mask & TTkTerm.Sigmask.CTRL_Z:
44+
attr[6][termios.VSUSP]= b'\x1a' if value else 0
45+
if mask & TTkTerm.Sigmask.CTRL_Q:
46+
attr[6][termios.VSTART]= b'\x11' if value else 0
47+
if mask & TTkTerm.Sigmask.CTRL_Y:
48+
attr[6][termios.VDSUSP]= b'\x19' if value else 0
49+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, attr)
50+
TTkTermBase.setSigmask = _setSigmask
51+
52+
@staticmethod
53+
def _getSigmask():
54+
mask = 0x00
55+
attr = termios.tcgetattr(sys.stdin)
56+
mask |= TTkTerm.Sigmask.CTRL_C if attr[6][termios.VINTR] else 0
57+
mask |= TTkTerm.Sigmask.CTRL_S if attr[6][termios.VSTOP] else 0
58+
mask |= TTkTerm.Sigmask.CTRL_Z if attr[6][termios.VSUSP] else 0
59+
mask |= TTkTerm.Sigmask.CTRL_Q if attr[6][termios.VSTART] else 0
60+
mask |= TTkTerm.Sigmask.CTRL_Y if attr[6][termios.VDSUSP] else 0
61+
return mask
62+
TTkTermBase.getSigmask = _getSigmask
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2025 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
__all__ = ['TTkTerm']
24+
25+
import sys
26+
27+
try: import termios
28+
except Exception as e:
29+
print(f'ERROR: {e}')
30+
exit(1)
31+
32+
from ..TTkTerm.term_base import TTkTermBase
33+
from .term_unix_common import _TTkTerm
34+
35+
class TTkTerm(_TTkTerm):
36+
@staticmethod
37+
def _setSigmask(mask, value=True):
38+
attr = termios.tcgetattr(sys.stdin)
39+
if mask & TTkTerm.Sigmask.CTRL_C:
40+
attr[6][termios.VINTR]= b'\x03' if value else 0
41+
if mask & TTkTerm.Sigmask.CTRL_S:
42+
attr[6][termios.VSTOP]= b'\x13' if value else 0
43+
if mask & TTkTerm.Sigmask.CTRL_Z:
44+
attr[6][termios.VSUSP]= b'\x1a' if value else 0
45+
if mask & TTkTerm.Sigmask.CTRL_Q:
46+
attr[6][termios.VSTART]= b'\x11' if value else 0
47+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, attr)
48+
TTkTermBase.setSigmask = _setSigmask
49+
50+
@staticmethod
51+
def _getSigmask():
52+
mask = 0x00
53+
attr = termios.tcgetattr(sys.stdin)
54+
mask |= TTkTerm.Sigmask.CTRL_C if attr[6][termios.VINTR] else 0
55+
mask |= TTkTerm.Sigmask.CTRL_S if attr[6][termios.VSTOP] else 0
56+
mask |= TTkTerm.Sigmask.CTRL_Z if attr[6][termios.VSUSP] else 0
57+
mask |= TTkTerm.Sigmask.CTRL_Q if attr[6][termios.VSTART] else 0
58+
return mask
59+
TTkTermBase.getSigmask = _getSigmask

libs/pyTermTk/TermTk/TTkCore/drivers/term_unix_serial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
__all__ = ['TTkTerm']
2424

2525
from ..TTkTerm.term_base import TTkTermBase
26-
from .term_unix import *
26+
from .term_unix_linux import *
2727

2828
class _TTkTermSerial():
2929
@staticmethod

0 commit comments

Comments
 (0)