chiark / gitweb /
Fix resizing the window smaller.
authorSimon Tatham <anakin@pobox.com>
Sat, 9 Dec 2023 12:22:23 +0000 (12:22 +0000)
committerSimon Tatham <anakin@pobox.com>
Sat, 9 Dec 2023 12:22:23 +0000 (12:22 +0000)
Some weird sequence of events was triggering an attempted redraw at
the old size, before properly noticing the change and redrawing at the
new size. When going from smaller to bigger this just caused a display
flicker (in fact not even a perceptible one), but bigger to smaller
caused an exception when we tried to draw a big screen in a small
window and curses caught us printing outside the screen area.

Now seems to work better.

cursesclient.py

index 3a8479f127d20076bd2a68659c254c4a7b3aeddb..d068ed9350e4a58da16a7d6e554580845e02fc6c 100644 (file)
@@ -19,6 +19,7 @@ class CursesUI(client.Client):
     def __init__(self):
         super().__init__()
         self.selfpipes = []
+        self.resized = False
 
     def curses_setup(self):
         self.scr = curses.initscr()
@@ -121,9 +122,13 @@ class CursesUI(client.Client):
             rfds_in.append(sp.rfd)
         rfds_out, _, _ = select.select(rfds_in, [], [])
         rfds_out = set(rfds_out)
+        resized = False
         for (sp, handler, _) in self.selfpipes:
             if sp.rfd in rfds_out and sp.check():
-                handler()
+                if handler():
+                    resized = True
+        if resized:
+            return None
         if 0 in rfds_out:
             return self.get_wch()
         else:
@@ -147,10 +152,19 @@ class CursesUI(client.Client):
         def handler():
             size = os.get_terminal_size()
             curses.resizeterm(size.lines, size.columns)
-            # This is the same way standard curses will do it, which
-            # is as good a way as any to signal to the main loop that
-            # we need to do something
-            curses.unget_wch(curses.KEY_RESIZE)
+            # Signal to the main loop that we've been resized. If
+            # curses were doing this itself, we'd see KEY_RESIZE in
+            # our input stream, but apparently passing that to
+            # curses.unget_wch does the wrong thing, and instead we
+            # receive U+019A from get_wch. (0x19A is the numerical
+            # value of curses.KEY_RESIZE, so it seems reasonably
+            # obvious what manner of confusion has happened there.)
+            #
+            # So instead, we set a flag of our own and return True,
+            # which causes get_input() to return None, which causes
+            # the main loop to check the resize flag.
+            self.resized = True
+            return True
         self.selfpipes.append((sp, handler, None))
 
     def get_composer(self):
@@ -215,7 +229,14 @@ class CursesUI(client.Client):
                 self.clear()
                 self.activity_stack[-1].render()
                 self.scr.refresh()
-                ch = self.get_input()
+                while True:
+                    ch = self.get_input()
+                    if ch is not None:
+                        break
+                    if self.resized:
+                        self.resized = False
+                        ch = curses.KEY_RESIZE
+                        break
                 if ch == ctrl('['):
                     if self.activity_stack[-1] is not self.escape_menu:
                         self.activity_stack.append(self.escape_menu)