When multiple confirmable close requests are made focus the existing close confirmation window instead of opening a new one for each request

Fixes #6601
This commit is contained in:
Kovid Goyal 2023-09-03 13:03:16 +05:30
parent 2f20bb3f43
commit d6851210d7
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 50 additions and 14 deletions

View file

@ -72,6 +72,8 @@ Detailed list of changes
- When running a shell for ``--hold`` set the env variable ``KITTY_HOLD=1`` to allow users to customize what happens (:disc:`6587`)
- When multiple confirmable close requests are made focus the existing close confirmation window instead of opening a new one for each request (:iss:`6601`)
0.29.2 [2023-07-27]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -942,7 +942,7 @@ def confirm(
window: Optional[Window] = None, # the window associated with the confirmation
confirm_on_cancel: bool = False, # on closing window
confirm_on_accept: bool = True, # on pressing enter
) -> None:
) -> Window:
result: bool = False
def callback_(res: Dict[str, Any], x: int, boss: Boss) -> None:
@ -952,10 +952,12 @@ def callback_(res: Dict[str, Any], x: int, boss: Boss) -> None:
def on_popup_overlay_removal(wid: int, boss: Boss) -> None:
callback(result, *args)
self.run_kitten_with_metadata(
w = self.run_kitten_with_metadata(
'ask', ['--type=yesno', '--message', msg, '--default', 'y' if confirm_on_accept else 'n'],
window=window, custom_callback=callback_, action_on_removal=on_popup_overlay_removal,
default_data={'response': 'y' if confirm_on_cancel else 'n'})
assert isinstance(w, Window)
return w
def choose(
self, msg: str, # can contain newlines and ANSI formatting
@ -1029,20 +1031,27 @@ def confirm_tab_close(self, tab: Tab) -> None:
tm = tab.tab_manager_ref()
if tm is not None:
tm.set_active_tab(tab)
self.confirm(ngettext('Are you sure you want to close this tab, it has one window running?',
if tab.confirm_close_window_id and tab.confirm_close_window_id in self.window_id_map:
w = self.window_id_map[tab.confirm_close_window_id]
if w in tab:
tab.set_active_window(w)
return
w = self.confirm(ngettext('Are you sure you want to close this tab, it has one window running?',
'Are you sure you want to close this tab, it has {} windows running?', num).format(num),
self.handle_close_tab_confirmation, tab.id,
window=tab.active_window,
)
tab.confirm_close_window_id = w.id
def handle_close_tab_confirmation(self, confirmed: bool, tab_id: int) -> None:
if not confirmed:
return
for tab in self.all_tabs:
if tab.id == tab_id:
tab.confirm_close_window_id = 0
break
else:
return
if not confirmed:
return
self.close_tab_no_confirm(tab)
def close_tab_no_confirm(self, tab: Tab) -> None:
@ -1619,15 +1628,25 @@ def confirm_os_window_close(self, os_window_id: int) -> None:
self.mark_os_window_for_close(os_window_id)
return
if tm is not None:
w = tm.active_window
self.confirm(
if tm.confirm_close_window_id and tm.confirm_close_window_id in self.window_id_map:
cw = self.window_id_map[tm.confirm_close_window_id]
ctab = cw.tabref()
if ctab is not None and ctab in tm and cw in ctab:
tm.set_active_tab(ctab)
ctab.set_active_window(cw)
return
w = self.confirm(
ngettext('Are you sure you want to close this OS window, it has one window running?',
'Are you sure you want to close this OS window, it has {} windows running', num).format(num),
self.handle_close_os_window_confirmation, os_window_id,
window=w,
window=tm.active_window,
)
tm.confirm_close_window_id = w.id
def handle_close_os_window_confirmation(self, confirmed: bool, os_window_id: int) -> None:
tm = self.os_window_map.get(os_window_id)
if tm is not None:
tm.confirm_close_window_id = 0
if confirmed:
self.mark_os_window_for_close(os_window_id)
else:
@ -1646,6 +1665,8 @@ def on_os_window_closed(self, os_window_id: int, viewport_width: int, viewport_h
if action is not None:
action()
quit_confirmation_window_id: int = 0
@ac('win', 'Quit, closing all windows')
def quit(self, *args: Any) -> None:
tm = self.active_tab
@ -1658,17 +1679,29 @@ def quit(self, *args: Any) -> None:
set_application_quit_request(IMPERATIVE_CLOSE_REQUESTED)
return
if current_application_quit_request() == CLOSE_BEING_CONFIRMED:
if self.quit_confirmation_window_id and self.quit_confirmation_window_id in self.window_id_map:
w = self.window_id_map[self.quit_confirmation_window_id]
tab = w.tabref()
if tab is not None:
ctm = tab.tab_manager_ref()
if ctm is not None and tab in ctm and w in tab:
focus_os_window(ctm.os_window_id)
ctm.set_active_tab(tab)
tab.set_active_window(w)
return
return
assert tm is not None
self.confirm(
w = self.confirm(
ngettext('Are you sure you want to quit kitty, it has one window running?',
'Are you sure you want to quit kitty, it has {} windows running?', num).format(num),
self.handle_quit_confirmation,
window=tm.active_window,
)
self.quit_confirmation_window_id = w.id
set_application_quit_request(CLOSE_BEING_CONFIRMED)
def handle_quit_confirmation(self, confirmed: bool) -> None:
self.quit_confirmation_window_id = 0
set_application_quit_request(IMPERATIVE_CLOSE_REQUESTED if confirmed else NO_CLOSE_REQUESTED)
def notify_on_os_window_death(self, address: str) -> None:

View file

@ -266,11 +266,9 @@ window_pos_callback(GLFWwindow* window, int x UNUSED, int y UNUSED) {
static void
window_close_callback(GLFWwindow* window) {
if (!set_callback_window(window)) return;
if (global_state.callback_os_window->close_request == NO_CLOSE_REQUESTED) {
global_state.callback_os_window->close_request = CONFIRMABLE_CLOSE_REQUESTED;
global_state.has_pending_closes = true;
request_tick_callback();
}
global_state.callback_os_window->close_request = CONFIRMABLE_CLOSE_REQUESTED;
global_state.has_pending_closes = true;
request_tick_callback();
glfwSetWindowShouldClose(window, false);
global_state.callback_os_window = NULL;
}

View file

@ -124,6 +124,7 @@ class Tab: # {{{
active_bg: Optional[int] = None
inactive_fg: Optional[int] = None
inactive_bg: Optional[int] = None
confirm_close_window_id: int = 0
def __init__(
self,
@ -848,6 +849,8 @@ def make_active(self) -> None:
class TabManager: # {{{
confirm_close_window_id: int = 0
def __init__(self, os_window_id: int, args: CLIOptions, wm_class: str, wm_name: str, startup_session: Optional[SessionType] = None):
self.os_window_id = os_window_id
self.wm_class = wm_class