Properly specify semantics of active and focused
active means active in parent. focused means actually has keyboard focus.
This commit is contained in:
parent
d1eb9340ac
commit
10ad56885e
@ -54,7 +54,7 @@ Detailed list of changes
|
||||
|
||||
- Wayland: Fix high CPU usage when using some input methods (:pull:`5369`)
|
||||
|
||||
- Remote control: When matching window by `state:focused` match the window belonging to the OS window that was last focused (:iss:`5602`)
|
||||
- Remote control: When matching window by `state:focused` and no window currently has keyboard focus, match the window belonging to the OS window that was last focused (:iss:`5602`)
|
||||
|
||||
0.26.4 [2022-10-17]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -12,8 +12,8 @@ from functools import partial
|
||||
from gettext import gettext as _
|
||||
from time import monotonic
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Container, Dict, Iterable, Iterator, List,
|
||||
Optional, Set, Tuple, Union
|
||||
TYPE_CHECKING, Any, Callable, Container, Dict, Iterable, Iterator, List, Optional,
|
||||
Set, Tuple, Union,
|
||||
)
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
@ -21,15 +21,15 @@ from .child import cached_process_data, default_env, set_default_env
|
||||
from .cli import create_opts, parse_args
|
||||
from .cli_stub import CLIOptions
|
||||
from .clipboard import (
|
||||
Clipboard, get_clipboard_string, get_primary_selection,
|
||||
set_clipboard_string, set_primary_selection
|
||||
Clipboard, get_clipboard_string, get_primary_selection, set_clipboard_string,
|
||||
set_primary_selection,
|
||||
)
|
||||
from .conf.utils import BadLine, KeyAction, to_cmdline
|
||||
from .config import common_opts_as_dict, prepare_config_file_for_editing
|
||||
from .constants import (
|
||||
RC_ENCRYPTION_PROTOCOL_VERSION, appname, cache_dir, clear_handled_signals,
|
||||
config_dir, handled_signals, is_macos, is_wayland, kitty_exe,
|
||||
logo_png_file, supports_primary_selection, website_url
|
||||
config_dir, handled_signals, is_macos, is_wayland, kitty_exe, logo_png_file,
|
||||
supports_primary_selection, website_url,
|
||||
)
|
||||
from .fast_data_types import (
|
||||
CLOSE_BEING_CONFIRMED, GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT,
|
||||
@ -37,15 +37,15 @@ from .fast_data_types import (
|
||||
IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED, ChildMonitor, Color,
|
||||
EllipticCurveKey, KeyEvent, SingleKey, add_timer, apply_options_update,
|
||||
background_opacity_of, change_background_opacity, change_os_window_state,
|
||||
cocoa_set_menubar_title, create_os_window, last_focused_os_window_id,
|
||||
current_application_quit_request, current_os_window, destroy_global_data,
|
||||
focus_os_window, get_boss, get_options, get_os_window_size,
|
||||
global_font_size, mark_os_window_for_close, os_window_font_size,
|
||||
patch_global_colors, redirect_mouse_handling, ring_bell,
|
||||
run_with_activation_token, safe_pipe, send_data_to_peer,
|
||||
set_application_quit_request, set_background_image, set_boss,
|
||||
set_in_sequence_mode, set_options, set_os_window_size, set_os_window_title,
|
||||
thread_write, toggle_fullscreen, toggle_maximized, toggle_secure_input
|
||||
cocoa_set_menubar_title, create_os_window, current_application_quit_request,
|
||||
current_focused_os_window_id, current_os_window, destroy_global_data,
|
||||
focus_os_window, get_boss, get_options, get_os_window_size, global_font_size,
|
||||
last_focused_os_window_id, mark_os_window_for_close, os_window_font_size,
|
||||
patch_global_colors, redirect_mouse_handling, ring_bell, run_with_activation_token,
|
||||
safe_pipe, send_data_to_peer, set_application_quit_request, set_background_image,
|
||||
set_boss, set_in_sequence_mode, set_options, set_os_window_size,
|
||||
set_os_window_title, thread_write, toggle_fullscreen, toggle_maximized,
|
||||
toggle_secure_input,
|
||||
)
|
||||
from .key_encoding import get_name_to_functional_number_map
|
||||
from .keys import get_shortcut, shortcut_matches
|
||||
@ -57,16 +57,14 @@ from .os_window_size import initial_window_size_func
|
||||
from .prewarm import PrewarmProcess
|
||||
from .rgb import color_from_int
|
||||
from .session import Session, create_sessions, get_os_window_sizing_data
|
||||
from .tabs import (
|
||||
SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
|
||||
)
|
||||
from .tabs import SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
|
||||
from .types import _T, AsyncResponse, WindowSystemMouseEvent, ac
|
||||
from .typing import PopenType, TypedDict
|
||||
from .utils import (
|
||||
cleanup_ssh_control_masters, func_name, get_editor, get_new_os_window_size,
|
||||
is_path_in_temp_dir, less_version, log_error, macos_version, open_url,
|
||||
parse_address_spec, parse_uri_list, platform_window_id, remove_socket_file,
|
||||
safe_print, single_instance, startup_notification_handler, which
|
||||
safe_print, single_instance, startup_notification_handler, which,
|
||||
)
|
||||
from .window import CommandOutput, CwdRequest, Window
|
||||
|
||||
@ -80,6 +78,8 @@ class OSWindowDict(TypedDict):
|
||||
id: int
|
||||
platform_window_id: Optional[int]
|
||||
is_focused: bool
|
||||
is_active: bool
|
||||
last_focused: bool
|
||||
tabs: List[TabDict]
|
||||
wm_class: str
|
||||
wm_name: str
|
||||
@ -287,9 +287,7 @@ class Boss:
|
||||
self.mouse_handler: Optional[Callable[[WindowSystemMouseEvent], None]] = None
|
||||
self.update_keymap()
|
||||
if is_macos:
|
||||
from .fast_data_types import (
|
||||
cocoa_set_notification_activated_callback
|
||||
)
|
||||
from .fast_data_types import cocoa_set_notification_activated_callback
|
||||
cocoa_set_notification_activated_callback(notification_activated)
|
||||
|
||||
def update_keymap(self) -> None:
|
||||
@ -351,7 +349,9 @@ class Boss:
|
||||
yield {
|
||||
'id': os_window_id,
|
||||
'platform_window_id': platform_window_id(os_window_id),
|
||||
'is_focused': tm is active_tab_manager and os_window_id == last_focused_os_window_id(),
|
||||
'is_active': tm is active_tab_manager,
|
||||
'is_focused': current_focused_os_window_id() == os_window_id,
|
||||
'last_focused': os_window_id == last_focused_os_window_id(),
|
||||
'tabs': list(tm.list_tabs(active_tab, active_window, self_window)),
|
||||
'wm_class': tm.wm_class,
|
||||
'wm_name': tm.wm_name
|
||||
@ -377,6 +377,10 @@ class Boss:
|
||||
return
|
||||
from .search_query_parser import search
|
||||
tab = self.active_tab
|
||||
if current_focused_os_window_id() <= 0:
|
||||
tm = self.os_window_map.get(last_focused_os_window_id())
|
||||
if tm is not None:
|
||||
tab = tm.active_tab
|
||||
|
||||
def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]:
|
||||
return {wid for wid in candidates if self.window_id_map[wid].matches_query(location, query, tab)}
|
||||
@ -398,6 +402,8 @@ class Boss:
|
||||
return self.all_tabs
|
||||
from .search_query_parser import search
|
||||
tm = self.active_tab_manager
|
||||
if current_focused_os_window_id() <= 0:
|
||||
tm = self.os_window_map.get(last_focused_os_window_id()) or tm
|
||||
tim = {t.id: t for t in self.all_tabs}
|
||||
|
||||
def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]:
|
||||
@ -534,9 +540,7 @@ class Boss:
|
||||
return True
|
||||
|
||||
def remote_cmd_permission_received(self, pcmd: Dict[str, Any], window_id: int, peer_id: int, choice: str) -> None:
|
||||
from .remote_control import (
|
||||
encode_response_for_peer, set_user_password_allowed
|
||||
)
|
||||
from .remote_control import encode_response_for_peer, set_user_password_allowed
|
||||
response: RCResponse = None
|
||||
window = self.window_id_map.get(window_id)
|
||||
choice = choice or 'r'
|
||||
@ -587,9 +591,7 @@ class Boss:
|
||||
self.show_error(_('remote_control mapping failed'), tb)
|
||||
|
||||
def call_remote_control(self, active_window: Optional[Window], args: Tuple[str, ...]) -> 'ResponseType':
|
||||
from .rc.base import (
|
||||
PayloadGetter, command_for_name, parse_subcommand_cli
|
||||
)
|
||||
from .rc.base import PayloadGetter, command_for_name, parse_subcommand_cli
|
||||
from .remote_control import parse_rc_args
|
||||
aa = list(args)
|
||||
silent = False
|
||||
@ -2248,9 +2250,7 @@ class Boss:
|
||||
log_error(f'Failed to process update check data {raw!r}, with error: {e}')
|
||||
|
||||
def dbus_notification_callback(self, activated: bool, a: int, b: Union[int, str]) -> None:
|
||||
from .notify import (
|
||||
dbus_notification_activated, dbus_notification_created
|
||||
)
|
||||
from .notify import dbus_notification_activated, dbus_notification_created
|
||||
if activated:
|
||||
assert isinstance(b, str)
|
||||
dbus_notification_activated(a, b)
|
||||
@ -2284,9 +2284,7 @@ class Boss:
|
||||
map f5 set_colors --configured /path/to/some/config/file/colors.conf
|
||||
''')
|
||||
def set_colors(self, *args: str) -> None:
|
||||
from kitty.rc.base import (
|
||||
PayloadGetter, command_for_name, parse_subcommand_cli
|
||||
)
|
||||
from kitty.rc.base import PayloadGetter, command_for_name, parse_subcommand_cli
|
||||
from kitty.remote_control import parse_rc_args
|
||||
c = command_for_name('set_colors')
|
||||
try:
|
||||
|
||||
@ -790,6 +790,10 @@ def last_focused_os_window_id() -> int:
|
||||
pass
|
||||
|
||||
|
||||
def current_focused_os_window_id() -> int:
|
||||
pass
|
||||
|
||||
|
||||
def cocoa_set_menubar_title(title: str) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ or a name and value, for example, :code:`env:MY_ENV_VAR=2`.
|
||||
The field :code:`state` matches on the state of the window. Supported states are:
|
||||
:code:`active`, :code:`focused`, :code:`needs_attention`, :code:`parent_active` and :code:`parent_focused`.
|
||||
Active windows are the windows that are active in their parent tab. There is only one focused window and it is the
|
||||
window to which keyboard events are delivered.
|
||||
window to which keyboard events are delivered. If no window is focused, the last focused window is matched.
|
||||
|
||||
Note that you can use the :ref:`kitty @ ls <at-ls>` command to get a list of windows.
|
||||
'''
|
||||
@ -134,7 +134,7 @@ variables are matched.
|
||||
The field :code:`state` matches on the state of the tab. Supported states are:
|
||||
:code:`active`, :code:`focused`, :code:`needs_attention`, :code:`parent_active` and :code:`parent_focused`.
|
||||
Active tabs are the tabs that are active in their parent OS window. There is only one focused tab
|
||||
and it is the tab to which keyboard events are delivered.
|
||||
and it is the tab to which keyboard events are delivered. If no tab is focused, the last focused tab is matched.
|
||||
|
||||
Note that you can use the :ref:`kitty @ ls <at-ls>` command to get a list of tabs.
|
||||
'''
|
||||
|
||||
@ -117,6 +117,16 @@ last_focused_os_window_id(void) {
|
||||
}
|
||||
|
||||
|
||||
static id_type
|
||||
current_focused_os_window_id(void) {
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
OSWindow *w = &global_state.os_windows[i];
|
||||
if (w->is_focused) { return w->id; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
OSWindow*
|
||||
os_window_for_kitty_window(id_type kitty_window_id) {
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
@ -682,6 +692,10 @@ PYWRAP0(last_focused_os_window_id) {
|
||||
return PyLong_FromUnsignedLongLong(last_focused_os_window_id());
|
||||
}
|
||||
|
||||
PYWRAP0(current_focused_os_window_id) {
|
||||
return PyLong_FromUnsignedLongLong(current_focused_os_window_id());
|
||||
}
|
||||
|
||||
|
||||
PYWRAP1(handle_for_window_id) {
|
||||
id_type os_window_id;
|
||||
@ -1285,6 +1299,7 @@ static PyMethodDef module_methods[] = {
|
||||
MW(current_os_window, METH_NOARGS),
|
||||
MW(next_window_id, METH_NOARGS),
|
||||
MW(last_focused_os_window_id, METH_NOARGS),
|
||||
MW(current_focused_os_window_id, METH_NOARGS),
|
||||
MW(set_options, METH_VARARGS),
|
||||
MW(get_options, METH_NOARGS),
|
||||
MW(click_mouse_url, METH_VARARGS),
|
||||
|
||||
@ -20,10 +20,10 @@ from .cli_stub import CLIOptions
|
||||
from .constants import appname, kitty_exe
|
||||
from .fast_data_types import (
|
||||
GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, add_tab,
|
||||
attach_window, current_os_window, detach_window, get_boss, get_click_interval,
|
||||
get_options, last_focused_os_window_id, mark_tab_bar_dirty, next_window_id,
|
||||
remove_tab, remove_window, ring_bell, set_active_tab, set_active_window, swap_tabs,
|
||||
sync_os_window_title,
|
||||
attach_window, current_focused_os_window_id, detach_window, get_boss,
|
||||
get_click_interval, get_options, last_focused_os_window_id, mark_tab_bar_dirty,
|
||||
next_window_id, remove_tab, remove_window, ring_bell, set_active_tab,
|
||||
set_active_window, swap_tabs, sync_os_window_title,
|
||||
)
|
||||
from .layout.base import Layout
|
||||
from .layout.interface import create_layout_object_for, evict_cached_layouts
|
||||
@ -701,7 +701,10 @@ class Tab: # {{{
|
||||
|
||||
def list_windows(self, active_window: Optional[Window], self_window: Optional[Window] = None) -> Generator[WindowDict, None, None]:
|
||||
for w in self:
|
||||
yield w.as_dict(is_focused=w is active_window and w.os_window_id == last_focused_os_window_id(), is_self=w is self_window)
|
||||
yield w.as_dict(
|
||||
is_active_window=w is active_window,
|
||||
is_focused=w.os_window_id == current_focused_os_window_id() and w is active_window,
|
||||
is_self=w is self_window)
|
||||
|
||||
def matches_query(self, field: str, query: str, active_tab_manager: Optional['TabManager'] = None) -> bool:
|
||||
if field == 'title':
|
||||
@ -725,7 +728,8 @@ class Tab: # {{{
|
||||
return False
|
||||
if field == 'state':
|
||||
if query == 'active':
|
||||
return active_tab_manager is not None and self is active_tab_manager.active_tab
|
||||
tm = self.tab_manager_ref()
|
||||
return tm is not None and self is tm.active_tab
|
||||
if query == 'focused':
|
||||
return active_tab_manager is not None and self is active_tab_manager.active_tab and self.os_window_id == last_focused_os_window_id()
|
||||
if query == 'needs_attention':
|
||||
@ -735,7 +739,7 @@ class Tab: # {{{
|
||||
if query == 'parent_active':
|
||||
return active_tab_manager is not None and self.tab_manager_ref() is active_tab_manager
|
||||
if query == 'parent_focused':
|
||||
return active_tab_manager is not None and self.tab_manager_ref() is active_tab_manager and self.os_window_id == current_os_window()
|
||||
return active_tab_manager is not None and self.tab_manager_ref() is active_tab_manager and self.os_window_id == last_focused_os_window_id()
|
||||
return False
|
||||
return False
|
||||
|
||||
@ -939,7 +943,7 @@ class TabManager: # {{{
|
||||
for tab in self:
|
||||
yield {
|
||||
'id': tab.id,
|
||||
'is_focused': tab is active_tab and tab.os_window_id == last_focused_os_window_id(),
|
||||
'is_focused': tab is active_tab and tab.os_window_id == current_focused_os_window_id(),
|
||||
'is_active_tab': tab is active_tab,
|
||||
'title': tab.name or tab.title,
|
||||
'layout': str(tab.current_layout.name),
|
||||
|
||||
@ -707,15 +707,20 @@ class Window:
|
||||
return False
|
||||
if field == 'state':
|
||||
if query == 'active':
|
||||
return active_tab is not None and self is active_tab.active_window
|
||||
tab = self.tabref()
|
||||
return tab is not None and tab.active_window is self
|
||||
if query == 'focused':
|
||||
return active_tab is not None and self is active_tab.active_window and last_focused_os_window_id() == self.os_window_id
|
||||
if query == 'needs_attention':
|
||||
return self.needs_attention
|
||||
if query == 'parent_active':
|
||||
return active_tab is not None and self.tabref() is active_tab
|
||||
tab = self.tabref()
|
||||
if tab is not None:
|
||||
tm = tab.tab_manager_ref()
|
||||
return tm is not None and tm.active_tab is tab
|
||||
return False
|
||||
if query == 'parent_focused':
|
||||
return active_tab is not None and self.tabref() is active_tab and current_os_window() == self.os_window_id
|
||||
return active_tab is not None and self.tabref() is active_tab and last_focused_os_window_id() == self.os_window_id
|
||||
return False
|
||||
pat = compile_match_query(query, field != 'env')
|
||||
return self.matches(field, pat)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user