Fix exceptions during shutdown
This commit is contained in:
parent
6e003b0901
commit
7cc39404c8
@ -6,6 +6,7 @@ import argparse
|
|||||||
import tempfile
|
import tempfile
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from queue import Empty
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
|
||||||
@ -73,6 +74,16 @@ def run_app(opts, args):
|
|||||||
tabs.render()
|
tabs.render()
|
||||||
window.swap_buffers()
|
window.swap_buffers()
|
||||||
glfw_wait_events()
|
glfw_wait_events()
|
||||||
|
try:
|
||||||
|
func, args = tabs.pending_ui_thread_calls.get_nowait()
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
func(*args)
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
tabs.destroy()
|
tabs.destroy()
|
||||||
del window
|
del window
|
||||||
|
|||||||
@ -9,11 +9,11 @@ import signal
|
|||||||
import struct
|
import struct
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Thread
|
from threading import Thread, current_thread
|
||||||
from queue import Queue, Empty
|
from queue import Queue, Empty
|
||||||
|
|
||||||
from .child import Child
|
from .child import Child
|
||||||
from .constants import viewport_size, shell_path, appname, set_tab_manager, tab_manager, wakeup, cell_size, MODIFIER_KEYS
|
from .constants import viewport_size, shell_path, appname, set_tab_manager, tab_manager, wakeup, cell_size, MODIFIER_KEYS, main_thread
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
glViewport, glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GLFW_PRESS,
|
glViewport, glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GLFW_PRESS,
|
||||||
GLFW_REPEAT, GLFW_MOUSE_BUTTON_1, glfw_post_empty_event
|
GLFW_REPEAT, GLFW_MOUSE_BUTTON_1, glfw_post_empty_event
|
||||||
@ -113,6 +113,7 @@ class TabManager(Thread):
|
|||||||
self.read_dispatch_map = {self.signal_fd: self.signal_received, self.read_wakeup_fd: self.on_wakeup}
|
self.read_dispatch_map = {self.signal_fd: self.signal_received, self.read_wakeup_fd: self.on_wakeup}
|
||||||
self.all_writers = []
|
self.all_writers = []
|
||||||
self.timers = Timers()
|
self.timers = Timers()
|
||||||
|
self.pending_ui_thread_calls = Queue()
|
||||||
self.write_dispatch_map = {}
|
self.write_dispatch_map = {}
|
||||||
set_tab_manager(self)
|
set_tab_manager(self)
|
||||||
cell_size.width, cell_size.height = set_font_family(opts.font_family, opts.font_size)
|
cell_size.width, cell_size.height = set_font_family(opts.font_family, opts.font_size)
|
||||||
@ -144,13 +145,9 @@ class TabManager(Thread):
|
|||||||
if data:
|
if data:
|
||||||
signals = struct.unpack('%uB' % len(data), data)
|
signals = struct.unpack('%uB' % len(data), data)
|
||||||
if signal.SIGINT in signals or signal.SIGTERM in signals:
|
if signal.SIGINT in signals or signal.SIGTERM in signals:
|
||||||
self.shutdown()
|
if not self.shutting_down:
|
||||||
|
self.glfw_window.set_should_close(True)
|
||||||
def shutdown(self):
|
glfw_post_empty_event()
|
||||||
if not self.shutting_down:
|
|
||||||
self.shutting_down = True
|
|
||||||
self.glfw_window.set_should_close(True)
|
|
||||||
glfw_post_empty_event()
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield from iter(self.tabs)
|
yield from iter(self.tabs)
|
||||||
@ -192,20 +189,18 @@ class TabManager(Thread):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def queue_ui_action(self, func, *args):
|
||||||
|
self.pending_ui_thread_calls.put((func, args))
|
||||||
|
glfw_post_empty_event()
|
||||||
|
|
||||||
def close_window(self, window):
|
def close_window(self, window):
|
||||||
self.remove_child_fd(window.child_fd)
|
' Can be called in either thread, will first kill the child (with SIGHUP), then remove the window from the gui '
|
||||||
for tab in self.tabs:
|
if current_thread() is main_thread:
|
||||||
if window in tab:
|
self.queue_action(self.close_window, window)
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
return
|
self.remove_child_fd(window.child_fd)
|
||||||
tab.remove_window(window)
|
window.destroy()
|
||||||
window.destroy()
|
self.queue_ui_action(self.gui_close_window, window)
|
||||||
if len(tab) == 0:
|
|
||||||
self.tabs.remove(tab)
|
|
||||||
tab.destroy()
|
|
||||||
if len(self.tabs) == 0:
|
|
||||||
self.shutdown()
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.args.profile:
|
if self.args.profile:
|
||||||
@ -338,6 +333,21 @@ class TabManager(Thread):
|
|||||||
with self.cursor_program:
|
with self.cursor_program:
|
||||||
active.char_grid.render_cursor(rd, self.cursor_program)
|
active.char_grid.render_cursor(rd, self.cursor_program)
|
||||||
|
|
||||||
|
def gui_close_window(self, window):
|
||||||
|
for tab in self.tabs:
|
||||||
|
if window in tab:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
tab.remove_window(window)
|
||||||
|
if len(tab) == 0:
|
||||||
|
self.tabs.remove(tab)
|
||||||
|
tab.destroy()
|
||||||
|
if len(self.tabs) == 0:
|
||||||
|
if not self.shutting_down:
|
||||||
|
self.glfw_window.set_should_close(True)
|
||||||
|
glfw_post_empty_event()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
# Must be called in the main thread as it manipulates signal handlers
|
# Must be called in the main thread as it manipulates signal handlers
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|||||||
@ -61,6 +61,9 @@ class Window:
|
|||||||
def destroy(self):
|
def destroy(self):
|
||||||
self.child.hangup()
|
self.child.hangup()
|
||||||
self.child.get_child_status() # Ensure child does not become zombie
|
self.child.get_child_status() # Ensure child does not become zombie
|
||||||
|
# At this point this window can still render to screen using its
|
||||||
|
# existing buffers in char_grid. The rest of the cleanup must be
|
||||||
|
# performed in the GUI thread.
|
||||||
|
|
||||||
def read_ready(self):
|
def read_ready(self):
|
||||||
if self.read_bytes(self.screen, self.child_fd) is False:
|
if self.read_bytes(self.screen, self.child_fd) is False:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user