You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1076 lines
30 KiB
1076 lines
30 KiB
"""Reimplementation of the standard extension module '_curses' using cffi."""
|
|
|
|
import sys
|
|
from functools import wraps
|
|
|
|
from _curses_cffi import ffi, lib
|
|
|
|
|
|
def _copy_to_globals(name):
|
|
globals()[name] = getattr(lib, name)
|
|
|
|
|
|
def _setup():
|
|
for name in ['ERR', 'OK', 'KEY_MIN', 'KEY_MAX',
|
|
'A_ATTRIBUTES', 'A_NORMAL', 'A_STANDOUT', 'A_UNDERLINE',
|
|
'A_REVERSE', 'A_BLINK', 'A_DIM', 'A_BOLD', 'A_ALTCHARSET',
|
|
'A_PROTECT', 'A_CHARTEXT', 'A_COLOR',
|
|
'COLOR_BLACK', 'COLOR_RED', 'COLOR_GREEN', 'COLOR_YELLOW',
|
|
'COLOR_BLUE', 'COLOR_MAGENTA', 'COLOR_CYAN', 'COLOR_WHITE',
|
|
]:
|
|
_copy_to_globals(name)
|
|
|
|
if not lib._m_NetBSD:
|
|
_copy_to_globals('A_INVIS')
|
|
|
|
for name in ['A_HORIZONTAL', 'A_LEFT', 'A_LOW', 'A_RIGHT', 'A_TOP',
|
|
'A_VERTICAL',
|
|
]:
|
|
if hasattr(lib, name):
|
|
_copy_to_globals(name)
|
|
|
|
if lib._m_NCURSES_MOUSE_VERSION:
|
|
for name in ["BUTTON1_PRESSED", "BUTTON1_RELEASED", "BUTTON1_CLICKED",
|
|
"BUTTON1_DOUBLE_CLICKED", "BUTTON1_TRIPLE_CLICKED",
|
|
"BUTTON2_PRESSED", "BUTTON2_RELEASED", "BUTTON2_CLICKED",
|
|
"BUTTON2_DOUBLE_CLICKED", "BUTTON2_TRIPLE_CLICKED",
|
|
"BUTTON3_PRESSED", "BUTTON3_RELEASED", "BUTTON3_CLICKED",
|
|
"BUTTON3_DOUBLE_CLICKED", "BUTTON3_TRIPLE_CLICKED",
|
|
"BUTTON4_PRESSED", "BUTTON4_RELEASED", "BUTTON4_CLICKED",
|
|
"BUTTON4_DOUBLE_CLICKED", "BUTTON4_TRIPLE_CLICKED",
|
|
"BUTTON_SHIFT", "BUTTON_CTRL", "BUTTON_ALT",
|
|
"ALL_MOUSE_EVENTS", "REPORT_MOUSE_POSITION",
|
|
]:
|
|
_copy_to_globals(name)
|
|
|
|
if not lib._m_NetBSD:
|
|
for key in range(lib.KEY_MIN, lib.KEY_MAX):
|
|
key_n = lib.keyname(key)
|
|
if key_n == ffi.NULL:
|
|
continue
|
|
key_n = ffi.string(key_n)
|
|
if key_n == b"UNKNOWN KEY":
|
|
continue
|
|
if not isinstance(key_n, str): # python 3
|
|
key_n = key_n.decode()
|
|
key_n = key_n.replace('(', '').replace(')', '')
|
|
globals()[key_n] = key
|
|
|
|
_setup()
|
|
|
|
# Do we want this?
|
|
# version = "2.2"
|
|
# __version__ = "2.2"
|
|
|
|
|
|
# ____________________________________________________________
|
|
|
|
|
|
_initialised_setupterm = False
|
|
_initialised = False
|
|
_initialised_color = False
|
|
|
|
|
|
def _ensure_initialised_setupterm():
|
|
if not _initialised_setupterm:
|
|
raise error("must call (at least) setupterm() first")
|
|
|
|
|
|
def _ensure_initialised():
|
|
if not _initialised:
|
|
raise error("must call initscr() first")
|
|
|
|
|
|
def _ensure_initialised_color():
|
|
if not _initialised and _initialised_color:
|
|
raise error("must call start_color() first")
|
|
|
|
|
|
def _check_ERR(code, fname):
|
|
if code != lib.ERR:
|
|
return None
|
|
elif fname is None:
|
|
raise error("curses function returned ERR")
|
|
else:
|
|
raise error("%s() returned ERR" % (fname,))
|
|
|
|
|
|
def _check_NULL(rval):
|
|
if rval == ffi.NULL:
|
|
raise error("curses function returned NULL")
|
|
return rval
|
|
|
|
|
|
def _call_lib(method_name, *args):
|
|
return getattr(lib, method_name)(*args)
|
|
|
|
|
|
def _call_lib_check_ERR(method_name, *args):
|
|
return _check_ERR(_call_lib(method_name, *args), method_name)
|
|
|
|
|
|
def _mk_no_return(method_name):
|
|
def _execute():
|
|
_ensure_initialised()
|
|
return _call_lib_check_ERR(method_name)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _mk_flag_func(method_name):
|
|
# This is in the CPython implementation, but not documented anywhere.
|
|
# We have to support it, though, even if it make me sad.
|
|
def _execute(flag=True):
|
|
_ensure_initialised()
|
|
if flag:
|
|
return _call_lib_check_ERR(method_name)
|
|
else:
|
|
return _call_lib_check_ERR('no' + method_name)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _mk_return_val(method_name):
|
|
def _execute():
|
|
return _call_lib(method_name)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _mk_w_getyx(method_name):
|
|
def _execute(self):
|
|
y = _call_lib(method_name + 'y', self._win)
|
|
x = _call_lib(method_name + 'x', self._win)
|
|
return (y, x)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _mk_w_no_return(method_name):
|
|
def _execute(self, *args):
|
|
return _call_lib_check_ERR(method_name, self._win, *args)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _mk_w_return_val(method_name):
|
|
def _execute(self, *args):
|
|
return _call_lib(method_name, self._win, *args)
|
|
_execute.__name__ = method_name
|
|
return _execute
|
|
|
|
|
|
def _chtype(ch):
|
|
return int(ffi.cast("chtype", ch))
|
|
|
|
def _texttype(text):
|
|
if isinstance(text, str):
|
|
return text
|
|
elif isinstance(text, unicode):
|
|
return str(text) # default encoding
|
|
else:
|
|
raise TypeError("str or unicode expected, got a '%s' object"
|
|
% (type(text).__name__,))
|
|
|
|
|
|
def _extract_yx(args):
|
|
if len(args) >= 2:
|
|
return (args[0], args[1], args[2:])
|
|
return (None, None, args)
|
|
|
|
|
|
def _process_args(funcname, args, count, optcount, frontopt=0):
|
|
outargs = []
|
|
if frontopt:
|
|
if len(args) > count + optcount:
|
|
# We have the front optional args here.
|
|
outargs.extend(args[:frontopt])
|
|
args = args[frontopt:]
|
|
else:
|
|
# No front optional args, so make them None.
|
|
outargs.extend([None] * frontopt)
|
|
if (len(args) < count) or (len(args) > count + optcount):
|
|
raise error("%s requires %s to %s arguments" % (
|
|
funcname, count, count + optcount + frontopt))
|
|
outargs.extend(args)
|
|
return outargs
|
|
|
|
|
|
def _argspec(count, optcount=0, frontopt=0):
|
|
def _argspec_deco(func):
|
|
@wraps(func)
|
|
def _wrapped(self, *args):
|
|
outargs = _process_args(
|
|
func.__name__, args, count, optcount, frontopt)
|
|
return func(self, *outargs)
|
|
return _wrapped
|
|
return _argspec_deco
|
|
|
|
|
|
# ____________________________________________________________
|
|
|
|
|
|
class error(Exception):
|
|
pass
|
|
|
|
|
|
class Window(object):
|
|
def __init__(self, window):
|
|
self._win = window
|
|
|
|
def __del__(self):
|
|
if self._win != lib.stdscr:
|
|
lib.delwin(self._win)
|
|
|
|
untouchwin = _mk_w_no_return("untouchwin")
|
|
touchwin = _mk_w_no_return("touchwin")
|
|
redrawwin = _mk_w_no_return("redrawwin")
|
|
insertln = _mk_w_no_return("winsertln")
|
|
erase = _mk_w_no_return("werase")
|
|
deleteln = _mk_w_no_return("wdeleteln")
|
|
|
|
is_wintouched = _mk_w_return_val("is_wintouched")
|
|
|
|
syncdown = _mk_w_return_val("wsyncdown")
|
|
syncup = _mk_w_return_val("wsyncup")
|
|
standend = _mk_w_return_val("wstandend")
|
|
standout = _mk_w_return_val("wstandout")
|
|
cursyncup = _mk_w_return_val("wcursyncup")
|
|
clrtoeol = _mk_w_return_val("wclrtoeol")
|
|
clrtobot = _mk_w_return_val("wclrtobot")
|
|
clear = _mk_w_return_val("wclear")
|
|
|
|
idcok = _mk_w_no_return("idcok")
|
|
immedok = _mk_w_no_return("immedok")
|
|
timeout = _mk_w_no_return("wtimeout")
|
|
|
|
getyx = _mk_w_getyx("getcur")
|
|
getbegyx = _mk_w_getyx("getbeg")
|
|
getmaxyx = _mk_w_getyx("getmax")
|
|
getparyx = _mk_w_getyx("getpar")
|
|
|
|
clearok = _mk_w_no_return("clearok")
|
|
idlok = _mk_w_no_return("idlok")
|
|
leaveok = _mk_w_no_return("leaveok")
|
|
notimeout = _mk_w_no_return("notimeout")
|
|
scrollok = _mk_w_no_return("scrollok")
|
|
insdelln = _mk_w_no_return("winsdelln")
|
|
syncok = _mk_w_no_return("syncok")
|
|
|
|
mvwin = _mk_w_no_return("mvwin")
|
|
mvderwin = _mk_w_no_return("mvderwin")
|
|
move = _mk_w_no_return("wmove")
|
|
|
|
if not lib._m_STRICT_SYSV_CURSES:
|
|
resize = _mk_w_no_return("wresize")
|
|
|
|
if lib._m_NetBSD:
|
|
keypad = _mk_w_return_val("keypad")
|
|
nodelay = _mk_w_return_val("nodelay")
|
|
else:
|
|
keypad = _mk_w_no_return("keypad")
|
|
nodelay = _mk_w_no_return("nodelay")
|
|
|
|
@_argspec(1, 1, 2)
|
|
def addch(self, y, x, ch, attr=None):
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
ch = _chtype(ch)
|
|
|
|
if y is not None:
|
|
code = lib.mvwaddch(self._win, y, x, ch | attr)
|
|
else:
|
|
code = lib.waddch(self._win, ch | attr)
|
|
return _check_ERR(code, "addch")
|
|
|
|
@_argspec(1, 1, 2)
|
|
def addstr(self, y, x, text, attr=None):
|
|
text = _texttype(text)
|
|
if attr is not None:
|
|
attr_old = lib.getattrs(self._win)
|
|
lib.wattrset(self._win, attr)
|
|
if y is not None:
|
|
code = lib.mvwaddstr(self._win, y, x, text)
|
|
else:
|
|
code = lib.waddstr(self._win, text)
|
|
if attr is not None:
|
|
lib.wattrset(self._win, attr_old)
|
|
return _check_ERR(code, "addstr")
|
|
|
|
@_argspec(2, 1, 2)
|
|
def addnstr(self, y, x, text, n, attr=None):
|
|
text = _texttype(text)
|
|
if attr is not None:
|
|
attr_old = lib.getattrs(self._win)
|
|
lib.wattrset(self._win, attr)
|
|
if y is not None:
|
|
code = lib.mvwaddnstr(self._win, y, x, text, n)
|
|
else:
|
|
code = lib.waddnstr(self._win, text, n)
|
|
if attr is not None:
|
|
lib.wattrset(self._win, attr_old)
|
|
return _check_ERR(code, "addnstr")
|
|
|
|
def bkgd(self, ch, attr=None):
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
return _check_ERR(lib.wbkgd(self._win, _chtype(ch) | attr), "bkgd")
|
|
|
|
attroff = _mk_w_no_return("wattroff")
|
|
attron = _mk_w_no_return("wattron")
|
|
attrset = _mk_w_no_return("wattrset")
|
|
|
|
def bkgdset(self, ch, attr=None):
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
lib.wbkgdset(self._win, _chtype(ch) | attr)
|
|
return None
|
|
|
|
def border(self, ls=0, rs=0, ts=0, bs=0, tl=0, tr=0, bl=0, br=0):
|
|
lib.wborder(self._win,
|
|
_chtype(ls), _chtype(rs), _chtype(ts), _chtype(bs),
|
|
_chtype(tl), _chtype(tr), _chtype(bl), _chtype(br))
|
|
return None
|
|
|
|
def box(self, vertint=0, horint=0):
|
|
lib.box(self._win, vertint, horint)
|
|
return None
|
|
|
|
@_argspec(1, 1, 2)
|
|
def chgat(self, y, x, num, attr=None):
|
|
# These optional args are in a weird order.
|
|
if attr is None:
|
|
attr = num
|
|
num = -1
|
|
|
|
color = ((attr >> 8) & 0xff)
|
|
attr = attr - (color << 8)
|
|
|
|
if y is not None:
|
|
code = lib.mvwchgat(self._win, y, x, num, attr, color, ffi.NULL)
|
|
lib.touchline(self._win, y, 1)
|
|
else:
|
|
yy, _ = self.getyx()
|
|
code = lib.wchgat(self._win, num, attr, color, ffi.NULL)
|
|
lib.touchline(self._win, yy, 1)
|
|
return _check_ERR(code, "chgat")
|
|
|
|
def delch(self, *args):
|
|
if len(args) == 0:
|
|
code = lib.wdelch(self._win)
|
|
elif len(args) == 2:
|
|
code = lib.mvwdelch(self._win, *args)
|
|
else:
|
|
raise error("delch requires 0 or 2 arguments")
|
|
return _check_ERR(code, "[mv]wdelch")
|
|
|
|
def derwin(self, *args):
|
|
nlines = 0
|
|
ncols = 0
|
|
if len(args) == 2:
|
|
begin_y, begin_x = args
|
|
elif len(args) == 4:
|
|
nlines, ncols, begin_y, begin_x = args
|
|
else:
|
|
raise error("derwin requires 2 or 4 arguments")
|
|
|
|
win = lib.derwin(self._win, nlines, ncols, begin_y, begin_x)
|
|
return Window(_check_NULL(win))
|
|
|
|
def echochar(self, ch, attr=None):
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
ch = _chtype(ch)
|
|
|
|
if lib._m_ispad(self._win):
|
|
code = lib.pechochar(self._win, ch | attr)
|
|
else:
|
|
code = lib.wechochar(self._win, ch | attr)
|
|
return _check_ERR(code, "echochar")
|
|
|
|
if lib._m_NCURSES_MOUSE_VERSION:
|
|
enclose = _mk_w_return_val("wenclose")
|
|
|
|
getbkgd = _mk_w_return_val("getbkgd")
|
|
|
|
def getch(self, *args):
|
|
if len(args) == 0:
|
|
val = lib.wgetch(self._win)
|
|
elif len(args) == 2:
|
|
val = lib.mvwgetch(self._win, *args)
|
|
else:
|
|
raise error("getch requires 0 or 2 arguments")
|
|
return val
|
|
|
|
def getkey(self, *args):
|
|
if len(args) == 0:
|
|
val = lib.wgetch(self._win)
|
|
elif len(args) == 2:
|
|
val = lib.mvwgetch(self._win, *args)
|
|
else:
|
|
raise error("getkey requires 0 or 2 arguments")
|
|
|
|
if val == lib.ERR:
|
|
raise error("no input")
|
|
elif val <= 255:
|
|
return chr(val)
|
|
else:
|
|
# XXX: The following line is different if `__NetBSD__` is defined.
|
|
val = lib.keyname(val)
|
|
if val == ffi.NULL:
|
|
return ""
|
|
return ffi.string(val)
|
|
|
|
@_argspec(0, 1, 2)
|
|
def getstr(self, y, x, n=1023):
|
|
n = min(n, 1023)
|
|
buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */
|
|
|
|
if y is None:
|
|
val = lib.wgetnstr(self._win, buf, n)
|
|
else:
|
|
val = lib.mvwgetnstr(self._win, y, x, buf, n)
|
|
|
|
if val == lib.ERR:
|
|
return ""
|
|
return ffi.string(buf)
|
|
|
|
@_argspec(2, 1, 2)
|
|
def hline(self, y, x, ch, n, attr=None):
|
|
ch = _chtype(ch)
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
if y is not None:
|
|
_check_ERR(lib.wmove(self._win, y, x), "wmove")
|
|
return _check_ERR(lib.whline(self._win, ch | attr, n), "hline")
|
|
|
|
@_argspec(1, 1, 2)
|
|
def insch(self, y, x, ch, attr=None):
|
|
ch = _chtype(ch)
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
if y is not None:
|
|
code = lib.mvwinsch(self._win, y, x, ch | attr)
|
|
else:
|
|
code = lib.winsch(self._win, ch | attr)
|
|
return _check_ERR(code, "insch")
|
|
|
|
def inch(self, *args):
|
|
if len(args) == 0:
|
|
return lib.winch(self._win)
|
|
elif len(args) == 2:
|
|
return lib.mvwinch(self._win, *args)
|
|
else:
|
|
raise error("inch requires 0 or 2 arguments")
|
|
|
|
@_argspec(0, 1, 2)
|
|
def instr(self, y, x, n=1023):
|
|
n = min(n, 1023)
|
|
buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */
|
|
if y is None:
|
|
code = lib.winnstr(self._win, buf, n)
|
|
else:
|
|
code = lib.mvwinnstr(self._win, y, x, buf, n)
|
|
|
|
if code == lib.ERR:
|
|
return ""
|
|
return ffi.string(buf)
|
|
|
|
@_argspec(1, 1, 2)
|
|
def insstr(self, y, x, text, attr=None):
|
|
text = _texttype(text)
|
|
if attr is not None:
|
|
attr_old = lib.getattrs(self._win)
|
|
lib.wattrset(self._win, attr)
|
|
if y is not None:
|
|
code = lib.mvwinsstr(self._win, y, x, text)
|
|
else:
|
|
code = lib.winsstr(self._win, text)
|
|
if attr is not None:
|
|
lib.wattrset(self._win, attr_old)
|
|
return _check_ERR(code, "insstr")
|
|
|
|
@_argspec(2, 1, 2)
|
|
def insnstr(self, y, x, text, n, attr=None):
|
|
text = _texttype(text)
|
|
if attr is not None:
|
|
attr_old = lib.getattrs(self._win)
|
|
lib.wattrset(self._win, attr)
|
|
if y is not None:
|
|
code = lib.mvwinsnstr(self._win, y, x, text, n)
|
|
else:
|
|
code = lib.winsnstr(self._win, text, n)
|
|
if attr is not None:
|
|
lib.wattrset(self._win, attr_old)
|
|
return _check_ERR(code, "insnstr")
|
|
|
|
def is_linetouched(self, line):
|
|
code = lib.is_linetouched(self._win, line)
|
|
if code == lib.ERR:
|
|
raise error("is_linetouched: line number outside of boundaries")
|
|
if code == lib.FALSE:
|
|
return False
|
|
return True
|
|
|
|
def noutrefresh(self, *args):
|
|
if lib._m_ispad(self._win):
|
|
if len(args) != 6:
|
|
raise error(
|
|
"noutrefresh() called for a pad requires 6 arguments")
|
|
return _check_ERR(lib.pnoutrefresh(self._win, *args),
|
|
"pnoutrefresh")
|
|
else:
|
|
# XXX: Better args check here? We need zero args.
|
|
return _check_ERR(lib.wnoutrefresh(self._win, *args),
|
|
"wnoutrefresh")
|
|
|
|
nooutrefresh = noutrefresh # "to be removed in 2.3", but in 2.7, 3.x.
|
|
|
|
def _copywin(self, dstwin, overlay,
|
|
sminr, sminc, dminr, dminc, dmaxr, dmaxc):
|
|
return _check_ERR(lib.copywin(self._win, dstwin._win,
|
|
sminr, sminc, dminr, dminc, dmaxr, dmaxc,
|
|
overlay), "copywin")
|
|
|
|
def overlay(self, dstwin, *args):
|
|
if len(args) == 6:
|
|
return self._copywin(dstwin, True, *args)
|
|
elif len(args) == 0:
|
|
return _check_ERR(lib.overlay(self._win, dstwin._win), "overlay")
|
|
else:
|
|
raise error("overlay requires one or seven arguments")
|
|
|
|
def overwrite(self, dstwin, *args):
|
|
if len(args) == 6:
|
|
return self._copywin(dstwin, False, *args)
|
|
elif len(args) == 0:
|
|
return _check_ERR(lib.overwrite(self._win, dstwin._win),
|
|
"overwrite")
|
|
else:
|
|
raise error("overwrite requires one or seven arguments")
|
|
|
|
def putwin(self, filep):
|
|
# filestar = ffi.new("FILE *", filep)
|
|
return _check_ERR(lib.putwin(self._win, filep), "putwin")
|
|
|
|
def redrawln(self, beg, num):
|
|
return _check_ERR(lib.wredrawln(self._win, beg, num), "redrawln")
|
|
|
|
def refresh(self, *args):
|
|
if lib._m_ispad(self._win):
|
|
if len(args) != 6:
|
|
raise error(
|
|
"noutrefresh() called for a pad requires 6 arguments")
|
|
return _check_ERR(lib.prefresh(self._win, *args), "prefresh")
|
|
else:
|
|
# XXX: Better args check here? We need zero args.
|
|
return _check_ERR(lib.wrefresh(self._win, *args), "wrefresh")
|
|
|
|
def setscrreg(self, y, x):
|
|
return _check_ERR(lib.wsetscrreg(self._win, y, x), "wsetscrreg")
|
|
|
|
def subwin(self, *args):
|
|
nlines = 0
|
|
ncols = 0
|
|
if len(args) == 2:
|
|
begin_y, begin_x = args
|
|
elif len(args) == 4:
|
|
nlines, ncols, begin_y, begin_x = args
|
|
else:
|
|
raise error("subwin requires 2 or 4 arguments")
|
|
|
|
if lib._m_ispad(self._win):
|
|
win = lib.subpad(self._win, nlines, ncols, begin_y, begin_x)
|
|
else:
|
|
win = lib.subwin(self._win, nlines, ncols, begin_y, begin_x)
|
|
return Window(_check_NULL(win))
|
|
|
|
def scroll(self, nlines=None):
|
|
if nlines is None:
|
|
return _check_ERR(lib.scroll(self._win), "scroll")
|
|
else:
|
|
return _check_ERR(lib.wscrl(self._win, nlines), "scroll")
|
|
|
|
def touchline(self, st, cnt, val=None):
|
|
if val is None:
|
|
return _check_ERR(lib.touchline(self._win, st, cnt), "touchline")
|
|
else:
|
|
return _check_ERR(lib.wtouchln(self._win, st, cnt, val),
|
|
"touchline")
|
|
|
|
@_argspec(2, 1, 2)
|
|
def vline(self, y, x, ch, n, attr=None):
|
|
ch = _chtype(ch)
|
|
if attr is None:
|
|
attr = lib.A_NORMAL
|
|
if y is not None:
|
|
_check_ERR(lib.wmove(self._win, y, x), "wmove")
|
|
return _check_ERR(lib.wvline(self._win, ch | attr, n), "vline")
|
|
|
|
|
|
beep = _mk_no_return("beep")
|
|
def_prog_mode = _mk_no_return("def_prog_mode")
|
|
def_shell_mode = _mk_no_return("def_shell_mode")
|
|
doupdate = _mk_no_return("doupdate")
|
|
endwin = _mk_no_return("endwin")
|
|
flash = _mk_no_return("flash")
|
|
nocbreak = _mk_no_return("nocbreak")
|
|
noecho = _mk_no_return("noecho")
|
|
nonl = _mk_no_return("nonl")
|
|
noraw = _mk_no_return("noraw")
|
|
reset_prog_mode = _mk_no_return("reset_prog_mode")
|
|
reset_shell_mode = _mk_no_return("reset_shell_mode")
|
|
resetty = _mk_no_return("resetty")
|
|
savetty = _mk_no_return("savetty")
|
|
|
|
cbreak = _mk_flag_func("cbreak")
|
|
echo = _mk_flag_func("echo")
|
|
nl = _mk_flag_func("nl")
|
|
raw = _mk_flag_func("raw")
|
|
|
|
baudrate = _mk_return_val("baudrate")
|
|
termattrs = _mk_return_val("termattrs")
|
|
|
|
termname = _mk_return_val("termname")
|
|
longname = _mk_return_val("longname")
|
|
|
|
can_change_color = _mk_return_val("can_change_color")
|
|
has_colors = _mk_return_val("has_colors")
|
|
has_ic = _mk_return_val("has_ic")
|
|
has_il = _mk_return_val("has_il")
|
|
isendwin = _mk_return_val("isendwin")
|
|
flushinp = _mk_return_val("flushinp")
|
|
noqiflush = _mk_return_val("noqiflush")
|
|
|
|
|
|
def filter():
|
|
lib.filter()
|
|
return None
|
|
|
|
|
|
def color_content(color):
|
|
_ensure_initialised_color()
|
|
r, g, b = ffi.new("short *"), ffi.new("short *"), ffi.new("short *")
|
|
if lib.color_content(color, r, g, b) == lib.ERR:
|
|
raise error("Argument 1 was out of range. Check value of COLORS.")
|
|
return (r[0], g[0], b[0])
|
|
|
|
|
|
def color_pair(n):
|
|
_ensure_initialised_color()
|
|
return (n << 8)
|
|
|
|
|
|
def curs_set(vis):
|
|
_ensure_initialised()
|
|
val = lib.curs_set(vis)
|
|
_check_ERR(val, "curs_set")
|
|
return val
|
|
|
|
|
|
def delay_output(ms):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.delay_output(ms), "delay_output")
|
|
|
|
|
|
def erasechar():
|
|
_ensure_initialised()
|
|
return lib.erasechar()
|
|
|
|
|
|
def getsyx():
|
|
_ensure_initialised()
|
|
yx = ffi.new("int[2]")
|
|
lib._m_getsyx(yx)
|
|
return (yx[0], yx[1])
|
|
|
|
|
|
if lib._m_NCURSES_MOUSE_VERSION:
|
|
|
|
def getmouse():
|
|
_ensure_initialised()
|
|
mevent = ffi.new("MEVENT *")
|
|
_check_ERR(lib.getmouse(mevent), "getmouse")
|
|
return (mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate)
|
|
|
|
def ungetmouse(id, x, y, z, bstate):
|
|
_ensure_initialised()
|
|
mevent = ffi.new("MEVENT *")
|
|
mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate = (
|
|
id, x, y, z, bstate)
|
|
return _check_ERR(lib.ungetmouse(mevent), "ungetmouse")
|
|
|
|
|
|
def getwin(filep):
|
|
return Window(_check_NULL(lib.getwin(filep)))
|
|
|
|
|
|
def halfdelay(tenths):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.halfdelay(tenths), "halfdelay")
|
|
|
|
|
|
if not lib._m_STRICT_SYSV_CURSES:
|
|
def has_key(ch):
|
|
_ensure_initialised()
|
|
return lib.has_key(ch)
|
|
|
|
|
|
def init_color(color, r, g, b):
|
|
_ensure_initialised_color()
|
|
return _check_ERR(lib.init_color(color, r, g, b), "init_color")
|
|
|
|
|
|
def init_pair(pair, f, b):
|
|
_ensure_initialised_color()
|
|
return _check_ERR(lib.init_pair(pair, f, b), "init_pair")
|
|
|
|
|
|
def _mk_acs(name, ichar):
|
|
if len(ichar) == 1:
|
|
globals()[name] = lib.acs_map[ord(ichar)]
|
|
else:
|
|
globals()[name] = globals()[ichar]
|
|
|
|
|
|
def _map_acs():
|
|
_mk_acs("ACS_ULCORNER", 'l')
|
|
_mk_acs("ACS_LLCORNER", 'm')
|
|
_mk_acs("ACS_URCORNER", 'k')
|
|
_mk_acs("ACS_LRCORNER", 'j')
|
|
_mk_acs("ACS_LTEE", 't')
|
|
_mk_acs("ACS_RTEE", 'u')
|
|
_mk_acs("ACS_BTEE", 'v')
|
|
_mk_acs("ACS_TTEE", 'w')
|
|
_mk_acs("ACS_HLINE", 'q')
|
|
_mk_acs("ACS_VLINE", 'x')
|
|
_mk_acs("ACS_PLUS", 'n')
|
|
_mk_acs("ACS_S1", 'o')
|
|
_mk_acs("ACS_S9", 's')
|
|
_mk_acs("ACS_DIAMOND", '`')
|
|
_mk_acs("ACS_CKBOARD", 'a')
|
|
_mk_acs("ACS_DEGREE", 'f')
|
|
_mk_acs("ACS_PLMINUS", 'g')
|
|
_mk_acs("ACS_BULLET", '~')
|
|
_mk_acs("ACS_LARROW", ',')
|
|
_mk_acs("ACS_RARROW", '+')
|
|
_mk_acs("ACS_DARROW", '.')
|
|
_mk_acs("ACS_UARROW", '-')
|
|
_mk_acs("ACS_BOARD", 'h')
|
|
_mk_acs("ACS_LANTERN", 'i')
|
|
_mk_acs("ACS_BLOCK", '0')
|
|
_mk_acs("ACS_S3", 'p')
|
|
_mk_acs("ACS_S7", 'r')
|
|
_mk_acs("ACS_LEQUAL", 'y')
|
|
_mk_acs("ACS_GEQUAL", 'z')
|
|
_mk_acs("ACS_PI", '{')
|
|
_mk_acs("ACS_NEQUAL", '|')
|
|
_mk_acs("ACS_STERLING", '}')
|
|
_mk_acs("ACS_BSSB", "ACS_ULCORNER")
|
|
_mk_acs("ACS_SSBB", "ACS_LLCORNER")
|
|
_mk_acs("ACS_BBSS", "ACS_URCORNER")
|
|
_mk_acs("ACS_SBBS", "ACS_LRCORNER")
|
|
_mk_acs("ACS_SBSS", "ACS_RTEE")
|
|
_mk_acs("ACS_SSSB", "ACS_LTEE")
|
|
_mk_acs("ACS_SSBS", "ACS_BTEE")
|
|
_mk_acs("ACS_BSSS", "ACS_TTEE")
|
|
_mk_acs("ACS_BSBS", "ACS_HLINE")
|
|
_mk_acs("ACS_SBSB", "ACS_VLINE")
|
|
_mk_acs("ACS_SSSS", "ACS_PLUS")
|
|
|
|
|
|
def initscr():
|
|
if _initialised:
|
|
lib.wrefresh(lib.stdscr)
|
|
return Window(lib.stdscr)
|
|
|
|
win = _check_NULL(lib.initscr())
|
|
globals()['_initialised_setupterm'] = True
|
|
globals()['_initialised'] = True
|
|
|
|
_map_acs()
|
|
|
|
globals()["LINES"] = lib.LINES
|
|
globals()["COLS"] = lib.COLS
|
|
|
|
return Window(win)
|
|
|
|
|
|
def setupterm(term=None, fd=-1):
|
|
if fd == -1:
|
|
# XXX: Check for missing stdout here?
|
|
fd = sys.stdout.fileno()
|
|
|
|
if _initialised_setupterm:
|
|
return None
|
|
|
|
if term is None:
|
|
term = ffi.NULL
|
|
err = ffi.new("int *")
|
|
if lib.setupterm(term, fd, err) == lib.ERR:
|
|
err = err[0]
|
|
if err == 0:
|
|
raise error("setupterm: could not find terminal")
|
|
elif err == -1:
|
|
raise error("setupterm: could not find terminfo database")
|
|
else:
|
|
raise error("setupterm: unknown error")
|
|
|
|
globals()["_initialised_setupterm"] = True
|
|
return None
|
|
|
|
|
|
def intrflush(ch):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.intrflush(ffi.NULL, ch), "intrflush")
|
|
|
|
|
|
# XXX: #ifdef HAVE_CURSES_IS_TERM_RESIZED
|
|
def is_term_resized(lines, columns):
|
|
_ensure_initialised()
|
|
return lib.is_term_resized(lines, columns)
|
|
|
|
|
|
if not lib._m_NetBSD:
|
|
def keyname(ch):
|
|
_ensure_initialised()
|
|
if ch < 0:
|
|
raise error("invalid key number")
|
|
knp = lib.keyname(ch)
|
|
if knp == ffi.NULL:
|
|
return ""
|
|
return ffi.string(knp)
|
|
|
|
|
|
def killchar():
|
|
return lib.killchar()
|
|
|
|
|
|
def meta(ch):
|
|
return _check_ERR(lib.meta(lib.stdscr, ch), "meta")
|
|
|
|
|
|
if lib._m_NCURSES_MOUSE_VERSION:
|
|
|
|
def mouseinterval(interval):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.mouseinterval(interval), "mouseinterval")
|
|
|
|
def mousemask(newmask):
|
|
_ensure_initialised()
|
|
oldmask = ffi.new("mmask_t *")
|
|
availmask = lib.mousemask(newmask, oldmask)
|
|
return (availmask, oldmask)
|
|
|
|
|
|
def napms(ms):
|
|
_ensure_initialised()
|
|
return lib.napms(ms)
|
|
|
|
|
|
def newpad(nlines, ncols):
|
|
_ensure_initialised()
|
|
return Window(_check_NULL(lib.newpad(nlines, ncols)))
|
|
|
|
|
|
def newwin(nlines, ncols, begin_y=None, begin_x=None):
|
|
_ensure_initialised()
|
|
if begin_x is None:
|
|
if begin_y is not None:
|
|
raise error("newwin requires 2 or 4 arguments")
|
|
begin_y = begin_x = 0
|
|
|
|
return Window(_check_NULL(lib.newwin(nlines, ncols, begin_y, begin_x)))
|
|
|
|
|
|
def pair_content(pair):
|
|
_ensure_initialised_color()
|
|
f = ffi.new("short *")
|
|
b = ffi.new("short *")
|
|
if lib.pair_content(pair, f, b) == lib.ERR:
|
|
raise error("Argument 1 was out of range. (1..COLOR_PAIRS-1)")
|
|
return (f, b)
|
|
|
|
|
|
def pair_number(pairvalue):
|
|
_ensure_initialised_color()
|
|
return (pairvalue & lib.A_COLOR) >> 8
|
|
|
|
|
|
def putp(text):
|
|
text = _texttype(text)
|
|
return _check_ERR(lib.putp(text), "putp")
|
|
|
|
|
|
def qiflush(flag=True):
|
|
_ensure_initialised()
|
|
if flag:
|
|
lib.qiflush()
|
|
else:
|
|
lib.noqiflush()
|
|
return None
|
|
|
|
|
|
# XXX: Do something about the following?
|
|
# /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES
|
|
# * and _curses.COLS */
|
|
# #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM)
|
|
# static int
|
|
# update_lines_cols(void)
|
|
# {
|
|
# PyObject *o;
|
|
# PyObject *m = PyImport_ImportModuleNoBlock("curses");
|
|
|
|
# if (!m)
|
|
# return 0;
|
|
|
|
# o = PyInt_FromLong(LINES);
|
|
# if (!o) {
|
|
# Py_DECREF(m);
|
|
# return 0;
|
|
# }
|
|
# if (PyObject_SetAttrString(m, "LINES", o)) {
|
|
# Py_DECREF(m);
|
|
# Py_DECREF(o);
|
|
# return 0;
|
|
# }
|
|
# if (PyDict_SetItemString(ModDict, "LINES", o)) {
|
|
# Py_DECREF(m);
|
|
# Py_DECREF(o);
|
|
# return 0;
|
|
# }
|
|
# Py_DECREF(o);
|
|
# o = PyInt_FromLong(COLS);
|
|
# if (!o) {
|
|
# Py_DECREF(m);
|
|
# return 0;
|
|
# }
|
|
# if (PyObject_SetAttrString(m, "COLS", o)) {
|
|
# Py_DECREF(m);
|
|
# Py_DECREF(o);
|
|
# return 0;
|
|
# }
|
|
# if (PyDict_SetItemString(ModDict, "COLS", o)) {
|
|
# Py_DECREF(m);
|
|
# Py_DECREF(o);
|
|
# return 0;
|
|
# }
|
|
# Py_DECREF(o);
|
|
# Py_DECREF(m);
|
|
# return 1;
|
|
# }
|
|
# #endif
|
|
|
|
# #ifdef HAVE_CURSES_RESIZETERM
|
|
# static PyObject *
|
|
# PyCurses_ResizeTerm(PyObject *self, PyObject *args)
|
|
# {
|
|
# int lines;
|
|
# int columns;
|
|
# PyObject *result;
|
|
|
|
# PyCursesInitialised;
|
|
|
|
# if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns))
|
|
# return NULL;
|
|
|
|
# result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm");
|
|
# if (!result)
|
|
# return NULL;
|
|
# if (!update_lines_cols())
|
|
# return NULL;
|
|
# return result;
|
|
# }
|
|
|
|
# #endif
|
|
|
|
# #ifdef HAVE_CURSES_RESIZE_TERM
|
|
# static PyObject *
|
|
# PyCurses_Resize_Term(PyObject *self, PyObject *args)
|
|
# {
|
|
# int lines;
|
|
# int columns;
|
|
|
|
# PyObject *result;
|
|
|
|
# PyCursesInitialised;
|
|
|
|
# if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns))
|
|
# return NULL;
|
|
|
|
# result = PyCursesCheckERR(resize_term(lines, columns), "resize_term");
|
|
# if (!result)
|
|
# return NULL;
|
|
# if (!update_lines_cols())
|
|
# return NULL;
|
|
# return result;
|
|
# }
|
|
# #endif /* HAVE_CURSES_RESIZE_TERM */
|
|
|
|
|
|
def setsyx(y, x):
|
|
_ensure_initialised()
|
|
lib.setsyx(y, x)
|
|
return None
|
|
|
|
|
|
def start_color():
|
|
_check_ERR(lib.start_color(), "start_color")
|
|
globals()["COLORS"] = lib.COLORS
|
|
globals()["COLOR_PAIRS"] = lib.COLOR_PAIRS
|
|
globals()["_initialised_color"] = True
|
|
return None
|
|
|
|
|
|
def tigetflag(capname):
|
|
_ensure_initialised_setupterm()
|
|
return lib.tigetflag(capname)
|
|
|
|
|
|
def tigetnum(capname):
|
|
_ensure_initialised_setupterm()
|
|
return lib.tigetnum(capname)
|
|
|
|
|
|
def tigetstr(capname):
|
|
_ensure_initialised_setupterm()
|
|
val = lib.tigetstr(capname)
|
|
if int(ffi.cast("intptr_t", val)) in (0, -1):
|
|
return None
|
|
return ffi.string(val)
|
|
|
|
|
|
def tparm(fmt, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0):
|
|
args = [ffi.cast("int", i) for i in (i1, i2, i3, i4, i5, i6, i7, i8, i9)]
|
|
result = lib.tparm(fmt, *args)
|
|
if result == ffi.NULL:
|
|
raise error("tparm() returned NULL")
|
|
return ffi.string(result)
|
|
|
|
|
|
def typeahead(fd):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.typeahead(fd), "typeahead")
|
|
|
|
|
|
def unctrl(ch):
|
|
_ensure_initialised()
|
|
return lib.unctrl(_chtype(ch))
|
|
|
|
|
|
def ungetch(ch):
|
|
_ensure_initialised()
|
|
return _check_ERR(lib.ungetch(_chtype(ch)), "ungetch")
|
|
|
|
|
|
def use_env(flag):
|
|
lib.use_env(flag)
|
|
return None
|
|
|
|
|
|
if not lib._m_STRICT_SYSV_CURSES:
|
|
|
|
def use_default_colors():
|
|
_ensure_initialised_color()
|
|
return _check_ERR(lib.use_default_colors(), "use_default_colors")
|