|
41 | 41 | from prompt_toolkit.buffer import Buffer
|
42 | 42 | from prompt_toolkit.cache import SimpleCache
|
43 | 43 | from prompt_toolkit.clipboard import Clipboard, InMemoryClipboard
|
| 44 | +from prompt_toolkit.data_structures import Size |
44 | 45 | from prompt_toolkit.enums import EditingMode
|
45 | 46 | from prompt_toolkit.eventloop import (
|
46 | 47 | get_traceback_from_context,
|
@@ -147,6 +148,10 @@ class Application(Generic[_AppResult]):
|
147 | 148 | seconds. When `None` (the default), only invalidate when `invalidate`
|
148 | 149 | has been called.
|
149 | 150 |
|
| 151 | + :param terminal_size_polling_interval: Poll the terminal size every so many |
| 152 | + seconds. Useful if the applications runs in a thread other then then |
| 153 | + main thread where SIGWINCH can't be handled, or on Windows. |
| 154 | +
|
150 | 155 | Filters:
|
151 | 156 |
|
152 | 157 | :param mouse_support: (:class:`~prompt_toolkit.filters.Filter` or
|
@@ -211,14 +216,15 @@ def __init__(
|
211 | 216 | min_redraw_interval: Union[float, int, None] = None,
|
212 | 217 | max_render_postpone_time: Union[float, int, None] = 0.01,
|
213 | 218 | refresh_interval: Optional[float] = None,
|
| 219 | + terminal_size_polling_interval: Optional[float] = 0.5, |
214 | 220 | on_reset: Optional[ApplicationEventHandler] = None,
|
215 | 221 | on_invalidate: Optional[ApplicationEventHandler] = None,
|
216 | 222 | before_render: Optional[ApplicationEventHandler] = None,
|
217 | 223 | after_render: Optional[ApplicationEventHandler] = None,
|
218 | 224 | # I/O.
|
219 | 225 | input: Optional[Input] = None,
|
220 | 226 | output: Optional[Output] = None,
|
221 |
| - ): |
| 227 | + ) -> None: |
222 | 228 |
|
223 | 229 | # If `enable_page_navigation_bindings` is not specified, enable it in
|
224 | 230 | # case of full screen applications only. This can be overridden by the user.
|
@@ -259,6 +265,7 @@ def __init__(
|
259 | 265 | self.min_redraw_interval = min_redraw_interval
|
260 | 266 | self.max_render_postpone_time = max_render_postpone_time
|
261 | 267 | self.refresh_interval = refresh_interval
|
| 268 | + self.terminal_size_polling_interval = terminal_size_polling_interval |
262 | 269 |
|
263 | 270 | # Events.
|
264 | 271 | self.on_invalidate = Event(self, on_invalidate)
|
@@ -696,6 +703,8 @@ def flush_input() -> None:
|
696 | 703 | with self.input.raw_mode(), self.input.attach(
|
697 | 704 | read_from_input
|
698 | 705 | ), attach_winch_signal_handler(self._on_resize):
|
| 706 | + self.create_background_task(self._poll_output_size()) |
| 707 | + |
699 | 708 | # Draw UI.
|
700 | 709 | self._request_absolute_cursor_position()
|
701 | 710 | self._redraw()
|
@@ -873,6 +882,28 @@ async def cancel_and_wait_for_background_tasks(self) -> None:
|
873 | 882 | except CancelledError:
|
874 | 883 | pass
|
875 | 884 |
|
| 885 | + async def _poll_output_size(self) -> None: |
| 886 | + """ |
| 887 | + Coroutine for polling the terminal dimensions. |
| 888 | +
|
| 889 | + Useful for situations where `attach_winch_signal_handler` is not sufficient: |
| 890 | + - If we are not running in the main thread. |
| 891 | + - On Windows. |
| 892 | + """ |
| 893 | + size: Optional[Size] = None |
| 894 | + interval = self.terminal_size_polling_interval |
| 895 | + |
| 896 | + if interval is None: |
| 897 | + return |
| 898 | + |
| 899 | + while True: |
| 900 | + await asyncio.sleep(interval) |
| 901 | + new_size = self.output.get_size() |
| 902 | + |
| 903 | + if size is not None and new_size != size: |
| 904 | + self._on_resize() |
| 905 | + size = new_size |
| 906 | + |
876 | 907 | def cpr_not_supported_callback(self) -> None:
|
877 | 908 | """
|
878 | 909 | Called when we don't receive the cursor position response in time.
|
|
0 commit comments