From cf613708c4e35498a582132ee1f24cfbd98e2055 Mon Sep 17 00:00:00 2001 From: Leroy Hopson Date: Sun, 26 Jun 2022 21:01:11 +0700 Subject: [PATCH] Fix resume after yield error Fixes error that would sometimes occur when closing the Terminal after calling write() but before the VisualServer had finished drawing the current frame. --- CHANGELOG.md | 3 +++ addons/godot_xterm/terminal.gd | 21 ++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6a1fe1..be38e3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 closing terminals in the Terminal panel of the editor plugin. - Fixed leaked instances that would occur when PTY exited but child process was still running. +- Fixed "Resumed function after yield, but class instance is gone" error that would + sometimes occur when closing a Terminal after calling write() but before VisualServer + had finished drawing the current frame. ## [v2.0.0](https://github.com/lihop/godot-xterm/compare/v1.2.1...v2.0.0) - 2021-07-25 diff --git a/addons/godot_xterm/terminal.gd b/addons/godot_xterm/terminal.gd index 2d05313..49503ae 100644 --- a/addons/godot_xterm/terminal.gd +++ b/addons/godot_xterm/terminal.gd @@ -61,6 +61,8 @@ var buffer := StreamPeerBuffer.new() var times = 0 +var _buffer := [] + func set_update_mode(value): update_mode = value @@ -78,12 +80,15 @@ func get_cols() -> int: func write(data) -> void: assert(data is String or data is PoolByteArray) - # FIXME: This will occasionally cause a "Resumed function after yield, but class instance is gone" error after freeing the Terminal instance. - # However, this yield is necessary to ensure the terminal state machines framebuffer is up to date when we make all the draw_* calls. - yield(VisualServer, "frame_pre_draw") + # Will be cleared when _flush() is called after VisualServer emits the "frame_pre_draw" signal. + _buffer.push_back(data) - _native_terminal.write(data if data is String else data.get_string_from_utf8()) - _native_terminal.update() + +func _flush(): + for data in _buffer: + _native_terminal.write(data if data is String else data.get_string_from_utf8()) + _native_terminal.update() + _buffer.clear() func clear() -> void: @@ -128,6 +133,12 @@ func _ready(): _refresh() + # Ensure the terminal state machine's framebuffer is up to date before + # we make all the draw_* calls caused by writing. We need to use signals + # here rather than yield otherwise we will sometimes get a "Resumed + # function after yield but class instance is gone" error. + VisualServer.connect("frame_pre_draw", self, "_flush") + func _update_theme(): # Themes are not propagated through the Viewport, so in order for theme