From f6f8d6d50b7823266684807eb4cad1db3e74c0d9 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Fri, 9 Dec 2016 11:54:25 +0100 Subject: push the refresh logic into the Terminal class One advantage of doing so is that the main function becomes simpler. Another advantage is that the Terminal class has better knowledge of when refreshes are actually needed. It also means that one more refresh call can be coalesced into the logic. The major downside is that it requires annotating all screen operations. --- tcvt.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/tcvt.py b/tcvt.py index edb102f..3831a83 100755 --- a/tcvt.py +++ b/tcvt.py @@ -315,13 +315,14 @@ class Terminal: self.lastchar = ord(b' ') self.columns = columns self.reverse = reverse + self.need_refresh = None def switchmode(self): if isinstance(self.screen, Columns): self.screen = Simple(self.realscreen) else: self.screen = Columns(self.realscreen, self.columns) - self.screen.refresh() + self.request_refresh() def resized(self): # The refresh call causes curses to notice the new dimensions. @@ -332,15 +333,32 @@ class Terminal: reverse=self.reverse) except BadWidth: self.screen = Simple(self.realscreen) + self.request_refresh() def resizepty(self, ptyfd): ym, xm = self.screen.getmaxyx() fcntl.ioctl(ptyfd, termios.TIOCSWINSZ, struct.pack("HHHH", ym, xm, 0, 0)) + def refresh_needed(self): + return self.need_refresh is not None + + def request_refresh(self): + if self.need_refresh is None: + self.need_refresh = time.time() + + def refresh(self, minwait=0): + if self.need_refresh is None: + return + if minwait > 0 and self.need_refresh + minwait > time.time(): + return + self.screen.refresh() + self.need_refresh = None + def addch(self, char): self.lastchar = char self.screen.addch(char) + self.request_refresh() def __enter__(self): self.realscreen = curses.initscr() @@ -371,27 +389,32 @@ class Terminal: def do_cr(self): self.screen.relmove(0, -9999) + self.request_refresh() def do_cub(self, n): self.screen.relmove(0, -n) + self.request_refresh() def do_cub1(self): self.do_cub(1) def do_cud(self, n): self.screen.relmove(n, 0) + self.request_refresh() def do_cud1(self): self.do_cud(1) def do_cuf(self, n): self.screen.relmove(0, n) + self.request_refresh() def do_cuf1(self): self.do_cuf(1) def do_cuu(self, n): self.screen.relmove(-n, 0) + self.request_refresh() def do_cuu1(self): self.do_cuu(1) @@ -399,6 +422,7 @@ class Terminal: def do_dch(self, n): for _ in range(n): self.screen.delch() + self.request_refresh() def do_dch1(self): self.do_dch(1) @@ -406,6 +430,7 @@ class Terminal: def do_dl(self, n): for _ in range(n): self.screen.deleteln() + self.request_refresh() def do_dl1(self): self.do_dl(1) @@ -413,39 +438,49 @@ class Terminal: def do_ech(self, n): for _ in range(n): self.screen.addch(ord(b' ')) + self.request_refresh() def do_ed(self): self.screen.clrtobot() + self.request_refresh() def do_el(self): self.screen.clrtoeol() + self.request_refresh() def do_el1(self): y, x = self.screen.getyx() - self.screen.move(y, 0) - for _ in range(x): - self.screen.addch(ord(b' ')) + if x > 0: + self.screen.move(y, 0) + for _ in range(x): + self.screen.addch(ord(b' ')) + self.request_refresh() def do_home(self): self.screen.move(0, 0) + self.request_refresh() def do_hpa(self, n): y, _ = self.screen.getyx() self.screen.move(y, n) + self.request_refresh() def do_ht(self): y, x = self.screen.getyx() _, xm = self.screen.getmaxyx() x = min(x + 8 - x % 8, xm - 1) self.screen.move(y, x) + self.request_refresh() def do_ich(self, n): for _ in range(n): self.screen.insch(ord(b' ')) + self.request_refresh() def do_il(self, n): for _ in range(n): self.screen.insertln() + self.request_refresh() def do_il1(self): self.do_il(1) @@ -458,6 +493,7 @@ class Terminal: self.screen.move(y, 0) else: self.screen.move(y+1, 0) + self.request_refresh() def do_invis(self): self.screen.attron(curses.A_INVIS) @@ -468,6 +504,7 @@ class Terminal: def do_vpa(self, n): _, x = self.screen.getyx() self.screen.move(n, x) + self.request_refresh() def feed_reset(self): if self.graphics_font: @@ -595,14 +632,17 @@ class Terminal: if len(parts) != 2: raise ValueError("feed esc [ %r H" % parts) self.screen.move(*map((-1).__add__, map(int, parts))) + self.request_refresh() elif prev == bytearray(b'2') and char == ord(b'J'): self.screen.move(0, 0) self.screen.clrtobot() + self.request_refresh() elif char == ord(b'd') and prev.isdigit(): self.do_vpa(int(prev) - 1) elif char == ord(b'b') and prev.isdigit(): for _ in range(int(prev)): self.screen.addch(self.lastchar) + self.request_refresh() elif char == ord(b'G') and prev.isdigit(): self.do_hpa(int(prev) - 1) elif char == ord(b'K') and prev == b'1': @@ -705,11 +745,10 @@ def main(): with process as masterfd: with Terminal(acsc, options.columns, reverse=options.reverse) as t: t.resizepty(masterfd) - refreshpending = None while True: + timeout = 0 if t.refresh_needed() else None try: - res, _, _ = select.select([0, masterfd], [], [], - refreshpending and 0) + res = select.select([0, masterfd], [], [], timeout)[0] except select.error as err: if err.args[0] == errno.EINTR: t.resized() @@ -731,6 +770,7 @@ def main(): else: if "TCVT_DEVEL" in os.environ: raise ValueError("getch returned %d" % key) + t.refresh(0.1) elif masterfd in res: try: data = os.read(masterfd, 1024) @@ -746,15 +786,9 @@ def main(): t.feed(char) except ValueError: t.feed_reset() - if refreshpending is None: - refreshpending = time.time() + 0.1 - elif refreshpending is not None: - t.screen.refresh() - refreshpending = None - if refreshpending is not None and \ - refreshpending < time.time(): - t.screen.refresh() - refreshpending = None + t.refresh(0.1) + else: + t.refresh() except ExecutionError as err: print(str(err)) sys.exit(255) -- cgit v1.2.3