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.
This commit is contained in:
Kovid Goyal 2017-08-03 22:35:47 +05:30
parent 9d62d087e0
commit ed50595aca
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 36 additions and 2 deletions

View File

@ -31,6 +31,17 @@ change_wcwidth_wrap(PyObject UNUSED *self, PyObject *use9) {
Py_RETURN_NONE; 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[] = { static PyMethodDef module_methods[] = {
GL_METHODS GL_METHODS
{"drain_read", (PyCFunction)drain_read, METH_O, ""}, {"drain_read", (PyCFunction)drain_read, METH_O, ""},
@ -38,6 +49,7 @@ static PyMethodDef module_methods[] = {
{"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""}, {"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""},
{"read_bytes", (PyCFunction)read_bytes, METH_VARARGS, ""}, {"read_bytes", (PyCFunction)read_bytes, METH_VARARGS, ""},
{"read_bytes_dump", (PyCFunction)read_bytes_dump, 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, ""}, {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
{"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""}, {"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""},
#ifndef __APPLE__ #ifndef __APPLE__

View File

@ -33,7 +33,7 @@ except ImportError:
GLFW_X11_WM_CLASS_NAME = GLFW_X11_WM_CLASS_CLASS = None GLFW_X11_WM_CLASS_NAME = GLFW_X11_WM_CLASS_CLASS = None
from .layout import all_layouts from .layout import all_layouts
from .shaders import GL_VERSION from .shaders import GL_VERSION
from .utils import safe_print from .utils import safe_print, detach
defconf = os.path.join(config_dir, 'kitty.conf') defconf = os.path.join(config_dir, 'kitty.conf')
@ -99,6 +99,13 @@ def option_parser():
default=False, default=False,
help=_('Output commands received from child process to stdout') 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( a(
'--replay-commands', '--replay-commands',
default=None, default=None,
@ -265,7 +272,11 @@ def main():
if os.environ.pop('KITTY_LAUNCHED_BY_LAUNCH_SERVICES', if os.environ.pop('KITTY_LAUNCHED_BY_LAUNCH_SERVICES',
None) == '1' and getattr(sys, 'frozen', True): None) == '1' and getattr(sys, 'frozen', True):
os.chdir(os.path.expanduser('~')) os.chdir(os.path.expanduser('~'))
if not os.path.isdir(os.getcwd()):
os.chdir(os.path.expanduser('~'))
args = option_parser().parse_args() args = option_parser().parse_args()
if getattr(args, 'detach', False):
detach()
if args.cmd: if args.cmd:
exec(args.cmd) exec(args.cmd)
return return

View File

@ -14,7 +14,7 @@ from functools import lru_cache
from time import monotonic from time import monotonic
from .constants import isosx 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 from .rgb import Color, to_color
@ -215,3 +215,14 @@ def open_url(url, program='default'):
cmd = shlex.split(program) cmd = shlex.split(program)
cmd.append(url) cmd.append(url)
subprocess.Popen(cmd).wait() 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)