diff --git a/kitty/child.c b/kitty/child.c index 88366bc98..6d479a9dd 100644 --- a/kitty/child.c +++ b/kitty/child.c @@ -47,35 +47,22 @@ write_to_stderr(const char *text) { #define exit_on_err(m) { write_to_stderr(m); write_to_stderr(": "); write_to_stderr(strerror(errno)); exit(EXIT_FAILURE); } -static sig_atomic_t sigwinch_arrived; - -void handle_sigwinch(int signal) { - if (signal == SIGWINCH) sigwinch_arrived = 1; -} - static inline void -wait_for_sigwinch() { - sigwinch_arrived = 0; - sigset_t mask, oldmask; - struct sigaction sa; - sa.sa_handler = handle_sigwinch; - sa.sa_flags = SA_RESTART; - if (sigaction(SIGWINCH, &sa, NULL) == -1) { - exit_on_err("Failed to set the SIGWINCH signal handler"); +wait_for_terminal_ready(int fd) { + char data; + while(1) { + int ret = read(fd, &data, 1); + if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue; + break; } - sigemptyset(&mask); - sigaddset(&mask, SIGWINCH); - sigprocmask(SIG_BLOCK, &mask, &oldmask); - while(!sigwinch_arrived) sigsuspend(&oldmask); - sigprocmask(SIG_UNBLOCK, &mask, NULL); } static PyObject* spawn(PyObject *self UNUSED, PyObject *args) { PyObject *argv_p, *env_p; - int master, slave, stdin_read_fd, stdin_write_fd; + int master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd; char *cwd, *exe; - if (!PyArg_ParseTuple(args, "ssO!O!iiii", &exe, &cwd, &PyTuple_Type, &argv_p, &PyTuple_Type, &env_p, &master, &slave, &stdin_read_fd, &stdin_write_fd)) return NULL; + if (!PyArg_ParseTuple(args, "ssO!O!iiiiii", &exe, &cwd, &PyTuple_Type, &argv_p, &PyTuple_Type, &env_p, &master, &slave, &stdin_read_fd, &stdin_write_fd, &ready_read_fd, &ready_write_fd)) return NULL; char name[2048] = {0}; if (ttyname_r(slave, name, sizeof(name) - 1) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } char **argv = serialize_string_tuple(argv_p); @@ -98,8 +85,10 @@ spawn(PyObject *self UNUSED, PyObject *args) { #endif close(tfd); - // Wait for SIGWINCH which indicates kitty has setup the screen object - wait_for_sigwinch(); + // Wait for READY_SIGNAL which indicates kitty has setup the screen object + close(ready_write_fd); + wait_for_terminal_ready(ready_read_fd); + close(ready_read_fd); // Redirect stdin/stdout/stderr to the pty if (dup2(slave, 1) == -1) exit_on_err("dup2() failed for fd number 1"); diff --git a/kitty/child.py b/kitty/child.py index b417c842e..33469fe53 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -101,6 +101,8 @@ def fork(self): remove_cloexec(slave) fast_data_types.set_iutf8(master, True) stdin, self.stdin = self.stdin, None + ready_read_fd, ready_write_fd = os.pipe() + remove_cloexec(ready_read_fd) if stdin is not None: stdin_read_fd, stdin_write_fd = os.pipe() remove_cloexec(stdin_read_fd) @@ -119,16 +121,22 @@ def fork(self): # Some macOS machines need the shell to have argv[0] prefixed by # hyphen, see https://github.com/kovidgoyal/kitty/issues/247 argv[0] = ('-' + exe.split('/')[-1]) - pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd) + pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd) os.close(slave) self.pid = pid self.child_fd = master if stdin is not None: os.close(stdin_read_fd) fast_data_types.thread_write(stdin_write_fd, stdin) + os.close(ready_read_fd) + self.terminal_ready_fd = ready_write_fd fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK) return pid + def mark_terminal_ready(self): + os.close(self.terminal_ready_fd) + self.terminal_ready_fd = -1 + @property def cmdline(self): try: diff --git a/kitty/window.py b/kitty/window.py index 3a5c92556..fa7f2346e 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -16,13 +16,12 @@ ) from .fast_data_types import ( BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM, - CELL_SPECIAL_PROGRAM, CSI, DCS, DECORATION, DIM, - GRAPHICS_PREMULT_PROGRAM, GRAPHICS_PROGRAM, OSC, REVERSE, SCROLL_FULL, - SCROLL_LINE, SCROLL_PAGE, STRIKETHROUGH, Screen, add_window, - cell_size_for_window, compile_program, get_clipboard_string, - glfw_post_empty_event, init_cell_program, set_clipboard_string, - set_titlebar_color, set_window_render_data, update_window_title, - update_window_visibility, viewport_for_window + CELL_SPECIAL_PROGRAM, CSI, DCS, DECORATION, DIM, GRAPHICS_PREMULT_PROGRAM, + GRAPHICS_PROGRAM, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, + STRIKETHROUGH, Screen, add_window, cell_size_for_window, compile_program, + get_clipboard_string, glfw_post_empty_event, init_cell_program, + set_clipboard_string, set_titlebar_color, set_window_render_data, + update_window_title, update_window_visibility, viewport_for_window ) from .keys import keyboard_mode_name from .rgb import to_color @@ -104,6 +103,7 @@ class Window: def __init__(self, tab, child, opts, args, override_title=None): self.action_on_close = None self.layout_data = None + self.pty_resized_once = False self.needs_attention = False self.override_title = override_title self.overlay_window_id = None @@ -200,6 +200,9 @@ def set_geometry(self, window_idx, new_geometry): sg = self.update_position(new_geometry) self.needs_layout = False boss.child_monitor.resize_pty(self.id, *current_pty_size) + if not self.pty_resized_once: + self.pty_resized_once = True + self.child.mark_terminal_ready() else: sg = self.update_position(new_geometry) self.geometry = g = new_geometry