Avoid flicker when starting kittens such as the hints kitten
Fixes #4674
This commit is contained in:
parent
1837168b0b
commit
6dc1617429
@ -57,6 +57,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- Wayland: Fix a regression that broke IME when changing windows/tabs (:iss:`4853`)
|
- Wayland: Fix a regression that broke IME when changing windows/tabs (:iss:`4853`)
|
||||||
|
|
||||||
|
- Avoid flicker when starting kittens such as the hints kitten (:iss:`4674`)
|
||||||
|
|
||||||
|
|
||||||
0.24.4 [2022-03-03]
|
0.24.4 [2022-03-03]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@ -159,6 +159,7 @@ class Hints(Handler):
|
|||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
self.init_terminal_state()
|
self.init_terminal_state()
|
||||||
self.draw_screen()
|
self.draw_screen()
|
||||||
|
self.cmd.overlay_ready()
|
||||||
|
|
||||||
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||||
changed = False
|
changed = False
|
||||||
@ -752,7 +753,7 @@ def linenum_handle_result(args: List[str], data: Dict[str, Any], target_window_i
|
|||||||
}[action])(*cmd)
|
}[action])(*cmd)
|
||||||
|
|
||||||
|
|
||||||
@result_handler(type_of_input='screen-ansi')
|
@result_handler(type_of_input='screen-ansi', has_ready_notification=True)
|
||||||
def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
||||||
if data['customize_processing']:
|
if data['customize_processing']:
|
||||||
m = load_custom_processor(data['customize_processing'])
|
m = load_custom_processor(data['customize_processing'])
|
||||||
|
|||||||
@ -69,6 +69,7 @@ def create_kitten_handler(kitten: str, orig_args: List[str]) -> Any:
|
|||||||
ans = partial(m['end'], [kitten] + orig_args)
|
ans = partial(m['end'], [kitten] + orig_args)
|
||||||
setattr(ans, 'type_of_input', getattr(m['end'], 'type_of_input', None))
|
setattr(ans, 'type_of_input', getattr(m['end'], 'type_of_input', None))
|
||||||
setattr(ans, 'no_ui', getattr(m['end'], 'no_ui', False))
|
setattr(ans, 'no_ui', getattr(m['end'], 'no_ui', False))
|
||||||
|
setattr(ans, 'has_ready_notification', getattr(m['end'], 'has_ready_notification', False))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -206,18 +206,23 @@ class HandleResult:
|
|||||||
type_of_input: Optional[str] = None
|
type_of_input: Optional[str] = None
|
||||||
no_ui: bool = False
|
no_ui: bool = False
|
||||||
|
|
||||||
def __init__(self, impl: Callable[..., Any], type_of_input: Optional[str], no_ui: bool):
|
def __init__(self, impl: Callable[..., Any], type_of_input: Optional[str], no_ui: bool, has_ready_notification: bool):
|
||||||
self.impl = impl
|
self.impl = impl
|
||||||
self.no_ui = no_ui
|
self.no_ui = no_ui
|
||||||
self.type_of_input = type_of_input
|
self.type_of_input = type_of_input
|
||||||
|
self.has_ready_notification = has_ready_notification
|
||||||
|
|
||||||
def __call__(self, args: Sequence[str], data: Any, target_window_id: int, boss: BossType) -> Any:
|
def __call__(self, args: Sequence[str], data: Any, target_window_id: int, boss: BossType) -> Any:
|
||||||
return self.impl(args, data, target_window_id, boss)
|
return self.impl(args, data, target_window_id, boss)
|
||||||
|
|
||||||
|
|
||||||
def result_handler(type_of_input: Optional[str] = None, no_ui: bool = False) -> Callable[[Callable[..., Any]], HandleResult]:
|
def result_handler(
|
||||||
|
type_of_input: Optional[str] = None,
|
||||||
|
no_ui: bool = False,
|
||||||
|
has_ready_notification: bool = False
|
||||||
|
) -> Callable[[Callable[..., Any]], HandleResult]:
|
||||||
|
|
||||||
def wrapper(impl: Callable[..., Any]) -> HandleResult:
|
def wrapper(impl: Callable[..., Any]) -> HandleResult:
|
||||||
return HandleResult(impl, type_of_input, no_ui)
|
return HandleResult(impl, type_of_input, no_ui, has_ready_notification)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
@ -413,6 +413,11 @@ def restore_colors() -> str:
|
|||||||
return '\x1b[#Q'
|
return '\x1b[#Q'
|
||||||
|
|
||||||
|
|
||||||
|
@cmd
|
||||||
|
def overlay_ready() -> str:
|
||||||
|
return '\x1bP@kitty-overlay-ready|\x1b\\'
|
||||||
|
|
||||||
|
|
||||||
@cmd
|
@cmd
|
||||||
def write_to_clipboard(data: Union[str, bytes], use_primary: bool = False) -> str:
|
def write_to_clipboard(data: Union[str, bytes], use_primary: bool = False) -> str:
|
||||||
from base64 import standard_b64encode
|
from base64 import standard_b64encode
|
||||||
|
|||||||
@ -377,6 +377,7 @@ class UnicodeInput(Handler):
|
|||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
self.init_terminal_state()
|
self.init_terminal_state()
|
||||||
self.draw_screen()
|
self.draw_screen()
|
||||||
|
self.cmd.overlay_ready()
|
||||||
|
|
||||||
def draw_title_bar(self) -> None:
|
def draw_title_bar(self) -> None:
|
||||||
entries = []
|
entries = []
|
||||||
@ -585,7 +586,7 @@ def main(args: List[str]) -> Optional[str]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@result_handler()
|
@result_handler(has_ready_notification=True)
|
||||||
def handle_result(args: List[str], current_char: str, target_window_id: int, boss: BossType) -> None:
|
def handle_result(args: List[str], current_char: str, target_window_id: int, boss: BossType) -> None:
|
||||||
w = boss.window_id_map.get(target_window_id)
|
w = boss.window_id_map.get(target_window_id)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
|
|||||||
@ -1427,7 +1427,8 @@ class Boss:
|
|||||||
'OVERLAID_WINDOW_COLS': str(w.screen.columns),
|
'OVERLAID_WINDOW_COLS': str(w.screen.columns),
|
||||||
},
|
},
|
||||||
cwd=w.cwd_of_child,
|
cwd=w.cwd_of_child,
|
||||||
overlay_for=w.id
|
overlay_for=w.id,
|
||||||
|
overlay_behind=end_kitten.has_ready_notification,
|
||||||
),
|
),
|
||||||
copy_colors_from=w
|
copy_colors_from=w
|
||||||
)
|
)
|
||||||
|
|||||||
@ -271,9 +271,12 @@ class Layout:
|
|||||||
def move_window_to_group(self, all_windows: WindowList, group: int) -> bool:
|
def move_window_to_group(self, all_windows: WindowList, group: int) -> bool:
|
||||||
return all_windows.move_window_group(to_group=group)
|
return all_windows.move_window_group(to_group=group)
|
||||||
|
|
||||||
def add_window(self, all_windows: WindowList, window: WindowType, location: Optional[str] = None, overlay_for: Optional[int] = None) -> None:
|
def add_window(
|
||||||
|
self, all_windows: WindowList, window: WindowType, location: Optional[str] = None,
|
||||||
|
overlay_for: Optional[int] = None, put_overlay_behind: bool = False
|
||||||
|
) -> None:
|
||||||
if overlay_for is not None and overlay_for in all_windows:
|
if overlay_for is not None and overlay_for in all_windows:
|
||||||
all_windows.add_window(window, group_of=overlay_for)
|
all_windows.add_window(window, group_of=overlay_for, head_of_group=put_overlay_behind)
|
||||||
return
|
return
|
||||||
if location == 'neighbor':
|
if location == 'neighbor':
|
||||||
location = 'after'
|
location = 'after'
|
||||||
|
|||||||
@ -1080,6 +1080,7 @@ dispatch_dcs(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
Py_DECREF(msg); \
|
Py_DECREF(msg); \
|
||||||
} else PyErr_Clear();
|
} else PyErr_Clear();
|
||||||
|
|
||||||
|
} else IF_SIMPLE_PREFIX("overlay-ready|", screen_handle_overlay_ready)
|
||||||
} else IF_SIMPLE_PREFIX("kitten-result|", screen_handle_kitten_result)
|
} else IF_SIMPLE_PREFIX("kitten-result|", screen_handle_kitten_result)
|
||||||
} else IF_SIMPLE_PREFIX("print|", screen_handle_print)
|
} else IF_SIMPLE_PREFIX("print|", screen_handle_print)
|
||||||
} else IF_SIMPLE_PREFIX("echo|", screen_handle_echo)
|
} else IF_SIMPLE_PREFIX("echo|", screen_handle_echo)
|
||||||
|
|||||||
@ -2134,6 +2134,11 @@ screen_handle_kitten_result(Screen *self, PyObject *msg) {
|
|||||||
CALLBACK("handle_kitten_result", "O", msg);
|
CALLBACK("handle_kitten_result", "O", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
screen_handle_overlay_ready(Screen *self, PyObject *msg) {
|
||||||
|
CALLBACK("handle_overlay_ready", "O", msg);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_request_capabilities(Screen *self, char c, PyObject *q) {
|
screen_request_capabilities(Screen *self, char c, PyObject *q) {
|
||||||
static char buf[128];
|
static char buf[128];
|
||||||
|
|||||||
@ -213,6 +213,7 @@ void screen_handle_echo(Screen *, PyObject *cmd);
|
|||||||
void screen_handle_ssh(Screen *, PyObject *cmd);
|
void screen_handle_ssh(Screen *, PyObject *cmd);
|
||||||
void screen_handle_askpass(Screen *, PyObject *cmd);
|
void screen_handle_askpass(Screen *, PyObject *cmd);
|
||||||
void screen_handle_kitten_result(Screen *, PyObject *cmd);
|
void screen_handle_kitten_result(Screen *, PyObject *cmd);
|
||||||
|
void screen_handle_overlay_ready(Screen *, PyObject *cmd);
|
||||||
void screen_designate_charset(Screen *, uint32_t which, uint32_t as);
|
void screen_designate_charset(Screen *, uint32_t which, uint32_t as);
|
||||||
void screen_use_latin1(Screen *, bool);
|
void screen_use_latin1(Screen *, bool);
|
||||||
void set_title(Screen *self, PyObject*);
|
void set_title(Screen *self, PyObject*);
|
||||||
|
|||||||
@ -63,6 +63,7 @@ class SpecialWindowInstance(NamedTuple):
|
|||||||
overlay_for: Optional[int]
|
overlay_for: Optional[int]
|
||||||
env: Optional[Dict[str, str]]
|
env: Optional[Dict[str, str]]
|
||||||
watchers: Optional[Watchers]
|
watchers: Optional[Watchers]
|
||||||
|
overlay_behind: bool
|
||||||
|
|
||||||
|
|
||||||
def SpecialWindow(
|
def SpecialWindow(
|
||||||
@ -73,9 +74,10 @@ def SpecialWindow(
|
|||||||
cwd: Optional[str] = None,
|
cwd: Optional[str] = None,
|
||||||
overlay_for: Optional[int] = None,
|
overlay_for: Optional[int] = None,
|
||||||
env: Optional[Dict[str, str]] = None,
|
env: Optional[Dict[str, str]] = None,
|
||||||
watchers: Optional[Watchers] = None
|
watchers: Optional[Watchers] = None,
|
||||||
|
overlay_behind: bool = False
|
||||||
) -> SpecialWindowInstance:
|
) -> SpecialWindowInstance:
|
||||||
return SpecialWindowInstance(cmd, stdin, override_title, cwd_from, cwd, overlay_for, env, watchers)
|
return SpecialWindowInstance(cmd, stdin, override_title, cwd_from, cwd, overlay_for, env, watchers, overlay_behind)
|
||||||
|
|
||||||
|
|
||||||
def add_active_id_to_history(items: Deque[int], item_id: int, maxlen: int = 64) -> None:
|
def add_active_id_to_history(items: Deque[int], item_id: int, maxlen: int = 64) -> None:
|
||||||
@ -403,8 +405,8 @@ class Tab: # {{{
|
|||||||
ans.fork()
|
ans.fork()
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def _add_window(self, window: Window, location: Optional[str] = None, overlay_for: Optional[int] = None) -> None:
|
def _add_window(self, window: Window, location: Optional[str] = None, overlay_for: Optional[int] = None, overlay_behind: bool = False) -> None:
|
||||||
self.current_layout.add_window(self.windows, window, location, overlay_for)
|
self.current_layout.add_window(self.windows, window, location, overlay_for, put_overlay_behind=overlay_behind)
|
||||||
self.mark_tab_bar_dirty()
|
self.mark_tab_bar_dirty()
|
||||||
self.relayout()
|
self.relayout()
|
||||||
|
|
||||||
@ -422,7 +424,8 @@ class Tab: # {{{
|
|||||||
copy_colors_from: Optional[Window] = None,
|
copy_colors_from: Optional[Window] = None,
|
||||||
allow_remote_control: bool = False,
|
allow_remote_control: bool = False,
|
||||||
marker: Optional[str] = None,
|
marker: Optional[str] = None,
|
||||||
watchers: Optional[Watchers] = None
|
watchers: Optional[Watchers] = None,
|
||||||
|
overlay_behind: bool = False
|
||||||
) -> Window:
|
) -> Window:
|
||||||
child = self.launch_child(
|
child = self.launch_child(
|
||||||
use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env, allow_remote_control=allow_remote_control)
|
use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env, allow_remote_control=allow_remote_control)
|
||||||
@ -432,7 +435,7 @@ class Tab: # {{{
|
|||||||
)
|
)
|
||||||
# Must add child before laying out so that resize_pty succeeds
|
# Must add child before laying out so that resize_pty succeeds
|
||||||
get_boss().add_child(window)
|
get_boss().add_child(window)
|
||||||
self._add_window(window, location=location, overlay_for=overlay_for)
|
self._add_window(window, location=location, overlay_for=overlay_for, overlay_behind=overlay_behind)
|
||||||
if marker:
|
if marker:
|
||||||
try:
|
try:
|
||||||
window.set_marker(marker)
|
window.set_marker(marker)
|
||||||
@ -453,7 +456,7 @@ class Tab: # {{{
|
|||||||
override_title=special_window.override_title,
|
override_title=special_window.override_title,
|
||||||
cwd_from=special_window.cwd_from, cwd=special_window.cwd, overlay_for=special_window.overlay_for,
|
cwd_from=special_window.cwd_from, cwd=special_window.cwd, overlay_for=special_window.overlay_for,
|
||||||
env=special_window.env, location=location, copy_colors_from=copy_colors_from,
|
env=special_window.env, location=location, copy_colors_from=copy_colors_from,
|
||||||
allow_remote_control=allow_remote_control, watchers=special_window.watchers
|
allow_remote_control=allow_remote_control, watchers=special_window.watchers, overlay_behind=special_window.overlay_behind
|
||||||
)
|
)
|
||||||
|
|
||||||
@ac('win', 'Close all windows in the tab other than the currently active window')
|
@ac('win', 'Close all windows in the tab other than the currently active window')
|
||||||
@ -464,6 +467,9 @@ class Tab: # {{{
|
|||||||
if window is not active_window:
|
if window is not active_window:
|
||||||
self.remove_window(window)
|
self.remove_window(window)
|
||||||
|
|
||||||
|
def move_window_to_top_of_group(self, window: Window) -> bool:
|
||||||
|
return self.windows.move_window_to_top_of_group(window)
|
||||||
|
|
||||||
def remove_window(self, window: Window, destroy: bool = True) -> None:
|
def remove_window(self, window: Window, destroy: bool = True) -> None:
|
||||||
self.windows.remove_window(window)
|
self.windows.remove_window(window)
|
||||||
if destroy:
|
if destroy:
|
||||||
|
|||||||
@ -940,6 +940,13 @@ class Window:
|
|||||||
import base64
|
import base64
|
||||||
self.kitten_result: Dict[str, Any] = json.loads(base64.b85decode(msg))
|
self.kitten_result: Dict[str, Any] = json.loads(base64.b85decode(msg))
|
||||||
|
|
||||||
|
def handle_overlay_ready(self, msg: str) -> None:
|
||||||
|
boss = get_boss()
|
||||||
|
tab = boss.tab_for_window(self)
|
||||||
|
if tab is None:
|
||||||
|
return
|
||||||
|
tab.move_window_to_top_of_group(self)
|
||||||
|
|
||||||
def handle_remote_askpass(self, msg: str) -> None:
|
def handle_remote_askpass(self, msg: str) -> None:
|
||||||
from .shm import SharedMemory
|
from .shm import SharedMemory
|
||||||
with SharedMemory(name=msg, readonly=True) as shm:
|
with SharedMemory(name=msg, readonly=True) as shm:
|
||||||
|
|||||||
@ -61,8 +61,23 @@ class WindowGroup:
|
|||||||
def active_window_id(self) -> int:
|
def active_window_id(self) -> int:
|
||||||
return self.windows[-1].id if self.windows else 0
|
return self.windows[-1].id if self.windows else 0
|
||||||
|
|
||||||
def add_window(self, window: WindowType) -> None:
|
def add_window(self, window: WindowType, head_of_group: bool = False) -> None:
|
||||||
|
if head_of_group:
|
||||||
|
self.windows.insert(0, window)
|
||||||
|
else:
|
||||||
|
self.windows.append(window)
|
||||||
|
|
||||||
|
def move_window_to_top_of_group(self, window: WindowType) -> bool:
|
||||||
|
id
|
||||||
|
try:
|
||||||
|
idx = self.windows.index(window)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
if idx == len(self.windows) - 1:
|
||||||
|
return False
|
||||||
|
del self.windows[idx]
|
||||||
self.windows.append(window)
|
self.windows.append(window)
|
||||||
|
return True
|
||||||
|
|
||||||
def remove_window(self, window: WindowType) -> None:
|
def remove_window(self, window: WindowType) -> None:
|
||||||
with suppress(ValueError):
|
with suppress(ValueError):
|
||||||
@ -252,6 +267,19 @@ class WindowList:
|
|||||||
return i
|
return i
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def move_window_to_top_of_group(self, window: WindowType) -> bool:
|
||||||
|
g = self.group_for_window(window)
|
||||||
|
if g is None:
|
||||||
|
return False
|
||||||
|
before = self.active_window
|
||||||
|
if not g.move_window_to_top_of_group(window):
|
||||||
|
return False
|
||||||
|
after = self.active_window
|
||||||
|
changed = before is not after
|
||||||
|
if changed:
|
||||||
|
self.notify_on_active_window_change(before, after)
|
||||||
|
return changed
|
||||||
|
|
||||||
def windows_in_group_of(self, x: WindowOrId) -> Iterator[WindowType]:
|
def windows_in_group_of(self, x: WindowOrId) -> Iterator[WindowType]:
|
||||||
g = self.group_for_window(x)
|
g = self.group_for_window(x)
|
||||||
if g is not None:
|
if g is not None:
|
||||||
@ -292,7 +320,8 @@ class WindowList:
|
|||||||
group_of: Optional[WindowOrId] = None,
|
group_of: Optional[WindowOrId] = None,
|
||||||
next_to: Optional[WindowOrId] = None,
|
next_to: Optional[WindowOrId] = None,
|
||||||
before: bool = False,
|
before: bool = False,
|
||||||
make_active: bool = True
|
make_active: bool = True,
|
||||||
|
head_of_group: bool = False,
|
||||||
) -> WindowGroup:
|
) -> WindowGroup:
|
||||||
self.all_windows.append(window)
|
self.all_windows.append(window)
|
||||||
self.id_map[window.id] = window
|
self.id_map[window.id] = window
|
||||||
@ -318,7 +347,7 @@ class WindowList:
|
|||||||
self.groups.append(target_group)
|
self.groups.append(target_group)
|
||||||
|
|
||||||
old_active_window = self.active_window
|
old_active_window = self.active_window
|
||||||
target_group.add_window(window)
|
target_group.add_window(window, head_of_group=head_of_group)
|
||||||
if make_active:
|
if make_active:
|
||||||
for i, g in enumerate(self.groups):
|
for i, g in enumerate(self.groups):
|
||||||
if g is target_group:
|
if g is target_group:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user