Add an :option:launch --watcher option that allows defining callbacks that are called for various events in the window's life-cycle

Fixes #2440
This commit is contained in:
Kovid Goyal
2020-03-28 12:13:42 +05:30
parent 8c23f9e526
commit 747ac85e7c
6 changed files with 104 additions and 11 deletions

View File

@@ -6,14 +6,15 @@
from functools import lru_cache
from typing import Any, Dict, List, Optional, Sequence, Tuple
from .boss import Boss
from .child import Child
from .cli import parse_args
from .cli_stub import LaunchCLIOptions
from .constants import resolve_custom_file
from .fast_data_types import set_clipboard_string
from .utils import set_primary_selection
from .window import Window
from .boss import Boss
from .tabs import Tab
from .utils import set_primary_selection
from .window import Watchers, Window
try:
from typing import TypedDict
@@ -148,6 +149,14 @@ defaults to :code:`kitty`.
--os-window-name
Set the WM_NAME property on X11 for the newly created OS Window when using
:option:`launch --type`=os-window. Defaults to :option:`launch --os-window-class`.
--watcher -w
type=list
Path to a python file. Appropriately named functions in this file will be called
for various events, such as when the window is resized or closed. See the section
on watchers in the launch command documentation :doc:`launch`. Relative paths are
resolved relative to the kitty config directory.
'''
@@ -192,6 +201,23 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Optional[Tab]
return tab
def load_watch_modules(opts: LaunchCLIOptions) -> Optional[Watchers]:
if not opts.watcher:
return None
import runpy
ans = Watchers()
for path in opts.watcher:
path = resolve_custom_file(path)
m = runpy.run_path(path, run_name='__kitty_watcher__')
w = m.get('on_close')
if callable(w):
ans.on_close.append(w)
w = m.get('on_resize')
if callable(w):
ans.on_resize.append(w)
return ans
class LaunchKwds(TypedDict):
allow_remote_control: bool
@@ -274,7 +300,8 @@ def launch(boss: Boss, opts: LaunchCLIOptions, args: List[str], target_tab: Opti
else:
tab = tab_for_window(boss, opts, target_tab)
if tab is not None:
new_window: Window = tab.new_window(env=env or None, **kw)
watchers = load_watch_modules(opts)
new_window: Window = tab.new_window(env=env or None, watchers=watchers or None, **kw)
if opts.keep_focus and active:
boss.set_active_window(active, switch_os_window_if_needed=True)
return new_window