Add function to get window as launch command for serialization

This commit is contained in:
Kovid Goyal 2025-08-11 21:20:55 +05:30
parent a3465d9998
commit 46e9223c05
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
6 changed files with 103 additions and 4 deletions

View file

@ -1527,6 +1527,9 @@ def set_window_logo(os_window_id: int, tab_id: int, window_id: int, path: str, p
pass
def get_window_logo_settings_if_not_default(os_window_id: int, tab_id: int, window_id: int) -> None | tuple[
str, float, tuple[float, float, float, float]]: ...
def apply_options_update() -> None:
pass

View file

@ -779,8 +779,13 @@ def _launch(
env=env or None, watchers=watchers or None, is_clone_launch=is_clone_launch, next_to=next_to, **kw)
if child_death_callback is not None:
boss.monitor_pid(new_window.child.pid or 0, child_death_callback)
if new_window.creation_spec and opts.watcher:
new_window.creation_spec = new_window.creation_spec._replace(watchers=tuple(opts.watcher))
if new_window.creation_spec:
if opts.watcher:
new_window.creation_spec = new_window.creation_spec._replace(watchers=tuple(opts.watcher))
if opts.spacing:
new_window.creation_spec = new_window.creation_spec._replace(spacing=tuple(opts.spacing))
if opts.color:
new_window.creation_spec = new_window.creation_spec._replace(colors=tuple(opts.color))
if spacing:
patch_window_edges(new_window, spacing)
tab.relayout()

View file

@ -1355,6 +1355,25 @@ pymouse_selection(PyObject *self UNUSED, PyObject *args) {
Py_RETURN_NONE;
}
PYWRAP1(get_window_logo_settings_if_not_default) {
id_type os_window_id, tab_id, window_id;
PA("KKK", &os_window_id, &tab_id, &window_id);
WITH_WINDOW(os_window_id, tab_id, window_id);
if (window->window_logo.instance != NULL && window->window_logo.id && !window->window_logo.using_default) {
WindowLogo *wl = find_window_logo(global_state.all_window_logos, window->window_logo.id);
if (wl != NULL && wl->load_from_disk_ok) {
const char *path = window_logo_path_for_id(global_state.all_window_logos, window->window_logo.id);
if (path) {
ImageAnchorPosition *p = &window->window_logo.position;
return Py_BuildValue("sfN", path, window->window_logo.alpha, Py_BuildValue(
"ffff", p->image_x, p->image_y, p->canvas_x, p->canvas_y));
}
}
}
END_WITH_WINDOW;
Py_RETURN_NONE;
}
PYWRAP1(set_window_logo) {
id_type os_window_id, tab_id, window_id;
const char *path; PyObject *position;
@ -1458,6 +1477,7 @@ static PyMethodDef module_methods[] = {
MW(redirect_mouse_handling, METH_O),
MW(mouse_selection, METH_VARARGS),
MW(set_window_logo, METH_VARARGS),
MW(get_window_logo_settings_if_not_default, METH_VARARGS),
MW(set_ignore_os_keyboard_processing, METH_O),
MW(handle_for_window_id, METH_VARARGS),
MW(update_ime_position_for_window, METH_VARARGS),

View file

@ -19,6 +19,7 @@
TYPE_CHECKING,
Any,
Deque,
Iterator,
Literal,
NamedTuple,
Optional,
@ -67,6 +68,7 @@
get_click_interval,
get_mouse_data_for_window,
get_options,
get_window_logo_settings_if_not_default,
is_css_pointer_name_valid,
is_modifier_key,
last_focused_os_window_id,
@ -369,6 +371,7 @@ class WindowCreationSpec(NamedTuple):
env: tuple[tuple[str, str], ...] | None = None
location: str | None = None
copy_colors_from: int | None = None
colors: tuple[str, ...] = ()
allow_remote_control: bool = False
marker: str | None = None
watchers: tuple[str, ...] = ()
@ -377,9 +380,8 @@ class WindowCreationSpec(NamedTuple):
remote_control_passwords: dict[str, Sequence[str]] | None = None
hold: bool = False
bias: float | None = None
pass_fds: tuple[int, ...] = ()
remote_control_fd: int = -1
hold_after_ssh: bool = False
spacing: tuple[str, ...] = ()
def pagerhist(screen: Screen, as_ansi: bool = False, add_wrap_markers: bool = True, upto_output_start: bool = False) -> str:
@ -605,6 +607,16 @@ def serialize(self) -> dict[str, float | None]:
def copy(self) -> 'EdgeWidths':
return EdgeWidths(self.serialize())
def as_launch_args(self, prefix: str = 'padding') -> Iterator[str]:
if self.left is not None:
yield f'--spacing={prefix}-left={self.left}'
if self.right is not None:
yield f'--spacing={prefix}-left={self.right}'
if self.top is not None:
yield f'--spacing={prefix}-left={self.top}'
if self.bottom is not None:
yield f'--spacing={prefix}-left={self.bottom}'
class GlobalWatchers:
@ -1931,6 +1943,54 @@ def current_mouse_position(self) -> Optional['MousePosition']:
' Return the last position at which a mouse event was received by this window '
return get_mouse_data_for_window(self.os_window_id, self.tab_id, self.id)
def as_launch_command(self) -> list[str]:
' Return a launch command that can be used to serialize this window. Empty list indicates not serializable. '
if self.actions_on_close or self.actions_on_focus_change or self.actions_on_removal:
# such windows are typically UI kittens. The actions are not
# serializable anyway, so skip.
return []
ans = ['launch']
cwd = self.get_cwd_of_child(oldest=False) or self.get_cwd_of_child(oldest=True)
if self.screen.last_reported_cwd and self.at_prompt and not self.child_is_remote:
cwd = path_from_osc7_url(self.screen.last_reported_cwd) or cwd
if cwd:
ans.append(f'--cwd={cwd}')
if self.creation_spec:
if self.creation_spec.env:
env = dict(self.creation_spec.env)
env.pop('KITTY_PIPE_DATA', None)
for k, v in env.items():
if k not in ('KITTY_PIPE_DATA',):
ans.append(f'--env={k}={v}')
for cs in self.creation_spec.colors:
ans.append(f'--color={cs}')
for k, v in self.user_vars.items():
ans.append(f'--var={k}={v}')
ans.extend(self.padding.as_launch_args())
ans.extend(self.margin.as_launch_args('margin'))
wl = get_window_logo_settings_if_not_default(self.os_window_id, self.tab_id, self.id)
if wl is not None:
logo_path, logo_alpha, logo_pos = wl
ans.extend((f'--logo={logo_path}', f'--logo-alpha={logo_alpha}'))
xpos = ypos = ''
if logo_pos[0] == logo_pos[2] != 0.5:
xpos = 'right' if logo_pos[0] else 'left'
if logo_pos[1] == logo_pos[3] != 0.5:
ypos = 'bottom' if logo_pos[1] else 'top'
lpos = 'center'
if xpos or ypos:
lpos = (f'{ypos}-{xpos}' if ypos else xpos) if xpos else ypos
ans.append(f'--logo-position={lpos}')
if self.overlay_parent is not None:
t = 'overlay-main' if self.overlay_type is OverlayType.main else 'overlay'
ans.append(f'--type={t}')
if self.creation_spec and self.creation_spec.cmd:
ans.extend(self.creation_spec.cmd)
return ans
# actions {{{
@ac('cp', 'Show scrollback in a pager like less')

View file

@ -68,6 +68,14 @@ set_on_gpu_state(WindowLogo *s, bool on_gpu) {
}
}
const char*
window_logo_path_for_id(WindowLogoTable *head, window_logo_id_t id) {
vt_create_for_loop(hash_by_path_itr, itr, &head->by_path) {
if (itr.data->val->id == id) return itr.data->key;
}
return NULL;
}
window_logo_id_t
find_or_create_window_logo(WindowLogoTable *head, const char *path, void *png_data, size_t png_data_size) {
hash_by_path_itr n = vt_get(&head->by_path, path);

View file

@ -28,6 +28,9 @@ find_or_create_window_logo(WindowLogoTable *table, const char *path, void *png_d
WindowLogo*
find_window_logo(WindowLogoTable *table, window_logo_id_t id);
const char*
window_logo_path_for_id(WindowLogoTable *head, window_logo_id_t id);
void
decref_window_logo(WindowLogoTable *table, window_logo_id_t id);