From ed50595acab4db2b7366209414955d2f314ea7c9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 3 Aug 2017 22:35:47 +0530 Subject: [PATCH] Add a --detach option Allows kitty to detach itself from the controlling terminal. Useful when launching kitty from a GUI environment with broken stdout/stderr or when launching from a terminal that you want to close later without affecting the launched kitty instance. --- kitty/data-types.c | 12 ++++++++++++ kitty/main.py | 13 ++++++++++++- kitty/utils.py | 13 ++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index 0ebd8d7b3..0202dbda7 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -31,6 +31,17 @@ change_wcwidth_wrap(PyObject UNUSED *self, PyObject *use9) { Py_RETURN_NONE; } +static PyObject* +redirect_std_streams(PyObject UNUSED *self, PyObject *args) { + char *devnull = NULL; + if (!PyArg_ParseTuple(args, "s", &devnull)) return NULL; + if (freopen(devnull, "r", stdin) == NULL) return PyErr_SetFromErrno(PyExc_EnvironmentError); + if (freopen(devnull, "w", stdout) == NULL) return PyErr_SetFromErrno(PyExc_EnvironmentError); + if (freopen(devnull, "w", stderr) == NULL) return PyErr_SetFromErrno(PyExc_EnvironmentError); + Py_RETURN_NONE; +} + + static PyMethodDef module_methods[] = { GL_METHODS {"drain_read", (PyCFunction)drain_read, METH_O, ""}, @@ -38,6 +49,7 @@ static PyMethodDef module_methods[] = { {"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""}, {"read_bytes", (PyCFunction)read_bytes, METH_VARARGS, ""}, {"read_bytes_dump", (PyCFunction)read_bytes_dump, METH_VARARGS, ""}, + {"redirect_std_streams", (PyCFunction)redirect_std_streams, METH_VARARGS, ""}, {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""}, {"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""}, #ifndef __APPLE__ diff --git a/kitty/main.py b/kitty/main.py index f7912b1a4..3e9e0d870 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -33,7 +33,7 @@ except ImportError: GLFW_X11_WM_CLASS_NAME = GLFW_X11_WM_CLASS_CLASS = None from .layout import all_layouts from .shaders import GL_VERSION -from .utils import safe_print +from .utils import safe_print, detach defconf = os.path.join(config_dir, 'kitty.conf') @@ -99,6 +99,13 @@ def option_parser(): default=False, help=_('Output commands received from child process to stdout') ) + if not isosx: + a( + '--detach', + action='store_true', + default=False, + help=_('Detach from the controlling terminal, if any') + ) a( '--replay-commands', default=None, @@ -265,7 +272,11 @@ def main(): if os.environ.pop('KITTY_LAUNCHED_BY_LAUNCH_SERVICES', None) == '1' and getattr(sys, 'frozen', True): os.chdir(os.path.expanduser('~')) + if not os.path.isdir(os.getcwd()): + os.chdir(os.path.expanduser('~')) args = option_parser().parse_args() + if getattr(args, 'detach', False): + detach() if args.cmd: exec(args.cmd) return diff --git a/kitty/utils.py b/kitty/utils.py index ea70317a2..60ac335f4 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -14,7 +14,7 @@ from functools import lru_cache from time import monotonic from .constants import isosx -from .fast_data_types import glfw_get_physical_dpi, wcwidth as wcwidth_impl +from .fast_data_types import glfw_get_physical_dpi, wcwidth as wcwidth_impl, redirect_std_streams from .rgb import Color, to_color @@ -215,3 +215,14 @@ def open_url(url, program='default'): cmd = shlex.split(program) cmd.append(url) subprocess.Popen(cmd).wait() + + +def detach(fork=True, setsid=True, redirect=True): + if fork: + # Detach from the controlling process. + if os.fork() != 0: + raise SystemExit(0) + if setsid: + os.setsid() + if redirect: + redirect_std_streams(os.devnull)