mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
@@ -203,6 +203,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- Allow holding the :kbd:`Alt` key and triple-clicking to select from the first cell even if it is empty (:pull:`9758`)
|
- Allow holding the :kbd:`Alt` key and triple-clicking to select from the first cell even if it is empty (:pull:`9758`)
|
||||||
|
|
||||||
|
- Fix double click to rename tab being triggered too easily (:iss:`9774`)
|
||||||
|
|
||||||
0.46.2 [2026-03-21]
|
0.46.2 [2026-03-21]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
@@ -85,43 +85,41 @@ def update_tab_bar_visibility(func: Callable[Concatenate['TabManager', P], T]) -
|
|||||||
class MouseEvent(NamedTuple):
|
class MouseEvent(NamedTuple):
|
||||||
button: int
|
button: int
|
||||||
modifiers: int
|
modifiers: int
|
||||||
action: int
|
is_press: bool
|
||||||
at: float
|
at: float
|
||||||
x: float
|
x: float
|
||||||
y: float
|
y: float
|
||||||
object_id: int = 0
|
object_id: int = 0
|
||||||
|
|
||||||
|
def distance_squared(self, other: 'MouseEvent') -> float:
|
||||||
|
return (self.x - other.x) * (self.x - other.x) + (self.y - other.y) * (self.y - other.y)
|
||||||
|
|
||||||
|
def is_click(self, prev: 'MouseEvent') -> bool:
|
||||||
|
cur = self
|
||||||
|
return (
|
||||||
|
cur.button == prev.button and prev.is_press and not cur.is_press and
|
||||||
|
cur.distance_squared(prev) < 25 and
|
||||||
|
cur.object_id == prev.object_id and cur.at - prev.at <= get_click_interval()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MouseEvents(deque[MouseEvent]):
|
class MouseEvents(deque[MouseEvent]):
|
||||||
|
|
||||||
def add(self, button: int, modifiers: int, action: int, x: float, y: float, object_id: int) -> None:
|
def add(self, button: int, modifiers: int, action: int, x: float, y: float, object_id: int) -> None:
|
||||||
super().append(MouseEvent(button, modifiers, action, monotonic(), x, y, object_id))
|
super().append(MouseEvent(button, modifiers, action != GLFW_RELEASE, monotonic(), x, y, object_id))
|
||||||
if len(self) > 5:
|
if len(self) > 5:
|
||||||
self.popleft()
|
self.popleft()
|
||||||
|
|
||||||
def is_click(self, button: int = GLFW_MOUSE_BUTTON_LEFT) -> bool:
|
def click_count(self, button: int = GLFW_MOUSE_BUTTON_LEFT) -> Literal[0, 1, 2]:
|
||||||
if len(self) < 2:
|
if len(self) > 1 and self[-1].button == button and self[-1].is_click(self[-2]):
|
||||||
return False
|
if len(self) > 3 and self[-3].is_click(self[-4]) and self[-1].at - self[-4].at <= 2 * get_click_interval():
|
||||||
cur, prev = self[-1], self[-2]
|
return 2
|
||||||
if cur.button != button:
|
return 1
|
||||||
return False
|
return 0
|
||||||
return (
|
|
||||||
cur.button == prev.button and prev.action == GLFW_PRESS and cur.action == GLFW_RELEASE and
|
|
||||||
cur.object_id == prev.object_id and cur.at - prev.at <= get_click_interval()
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_double_click(self, button: int = GLFW_MOUSE_BUTTON_LEFT) -> bool:
|
def dump(self) -> None:
|
||||||
if len(self) < 3:
|
for x in self:
|
||||||
return False
|
print(x)
|
||||||
cur, prev, prev2 = self[-1], self[-2], self[-3]
|
|
||||||
if cur.button != button:
|
|
||||||
return False
|
|
||||||
return (
|
|
||||||
cur.button == prev.button == prev2.button and
|
|
||||||
prev.action == GLFW_PRESS and cur.action == prev2.action == GLFW_RELEASE and
|
|
||||||
cur.object_id == prev.object_id == prev2.object_id and
|
|
||||||
cur.at - prev.at <= (ci := get_click_interval()) and cur.at - prev2.at <= 2 * ci
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TabDict(TypedDict):
|
class TabDict(TypedDict):
|
||||||
@@ -1782,37 +1780,45 @@ class TabManager: # {{{
|
|||||||
if threshold and math.sqrt((x-start_x)**2 + (y-start_y)**2) > threshold:
|
if threshold and math.sqrt((x-start_x)**2 + (y-start_y)**2) > threshold:
|
||||||
set_tab_being_dragged(dragged_tab_id, True, start_x, start_y)
|
set_tab_being_dragged(dragged_tab_id, True, start_x, start_y)
|
||||||
request_callback_with_thumbnail("start_tab_drag", self.os_window_id)
|
request_callback_with_thumbnail("start_tab_drag", self.os_window_id)
|
||||||
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
return
|
return
|
||||||
|
|
||||||
tab_id_at_x = self.tab_bar.tab_id_at(int(x))
|
tab_id_at_x = self.tab_bar.tab_id_at(int(x))
|
||||||
self.recent_tab_bar_mouse_events.add(button, modifiers, action, x, y, tab_id_at_x)
|
self.recent_tab_bar_mouse_events.add(button, modifiers, action, x, y, tab_id_at_x)
|
||||||
if tab_id_at_x < 0: # synthetic tab (e.g. "+" new-tab button)
|
if tab_id_at_x < 0: # synthetic tab (e.g. "+" new-tab button)
|
||||||
if self.recent_tab_bar_mouse_events.is_click():
|
if self.recent_tab_bar_mouse_events.click_count(GLFW_MOUSE_BUTTON_LEFT) == 1:
|
||||||
self.new_tab()
|
self.new_tab()
|
||||||
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
return
|
return
|
||||||
drag_started = get_tab_being_dragged()[1]
|
drag_started = get_tab_being_dragged()[1]
|
||||||
if drag_started:
|
if drag_started:
|
||||||
return
|
return
|
||||||
tab = self.tab_for_id(tab_id_at_x)
|
tab = self.tab_for_id(tab_id_at_x)
|
||||||
if tab is None:
|
if tab is None:
|
||||||
if self.recent_tab_bar_mouse_events.is_double_click(GLFW_MOUSE_BUTTON_LEFT):
|
if self.recent_tab_bar_mouse_events.click_count(GLFW_MOUSE_BUTTON_LEFT) == 2:
|
||||||
self.new_tab()
|
self.new_tab()
|
||||||
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
return
|
return
|
||||||
if button == GLFW_MOUSE_BUTTON_LEFT:
|
if button == GLFW_MOUSE_BUTTON_LEFT:
|
||||||
if action == GLFW_PRESS:
|
if action == GLFW_PRESS:
|
||||||
set_tab_being_dragged(tab.id, False, x, y)
|
set_tab_being_dragged(tab.id, False, x, y)
|
||||||
return
|
return
|
||||||
if self.recent_tab_bar_mouse_events.is_double_click(GLFW_MOUSE_BUTTON_LEFT):
|
match self.recent_tab_bar_mouse_events.click_count(GLFW_MOUSE_BUTTON_LEFT):
|
||||||
self.set_active_tab(tab)
|
case 2:
|
||||||
get_boss().set_tab_title()
|
self.set_active_tab(tab)
|
||||||
set_tab_being_dragged()
|
get_boss().set_tab_title()
|
||||||
elif self.recent_tab_bar_mouse_events.is_click(GLFW_MOUSE_BUTTON_LEFT):
|
set_tab_being_dragged()
|
||||||
self.set_active_tab(tab)
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
|
case 1:
|
||||||
|
if self.active_tab is not tab:
|
||||||
|
self.set_active_tab(tab)
|
||||||
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
set_tab_being_dragged()
|
set_tab_being_dragged()
|
||||||
return
|
return
|
||||||
if button == GLFW_MOUSE_BUTTON_MIDDLE:
|
if button == GLFW_MOUSE_BUTTON_MIDDLE:
|
||||||
if self.recent_tab_bar_mouse_events.is_click(GLFW_MOUSE_BUTTON_MIDDLE):
|
if self.recent_tab_bar_mouse_events.click_count(GLFW_MOUSE_BUTTON_MIDDLE) == 1:
|
||||||
get_boss().close_tab(tab)
|
get_boss().close_tab(tab)
|
||||||
|
self.recent_tab_bar_mouse_events.clear()
|
||||||
return
|
return
|
||||||
|
|
||||||
def handle_window_title_bar_mouse(self, window_id: int, x: float, y: float, button: int, modifiers: int, action: int) -> None:
|
def handle_window_title_bar_mouse(self, window_id: int, x: float, y: float, button: int, modifiers: int, action: int) -> None:
|
||||||
@@ -1825,6 +1831,7 @@ class TabManager: # {{{
|
|||||||
if threshold and dist_sq > threshold * threshold:
|
if threshold and dist_sq > threshold * threshold:
|
||||||
set_window_being_dragged(dragged_window_id, True, start_x, start_y)
|
set_window_being_dragged(dragged_window_id, True, start_x, start_y)
|
||||||
request_callback_with_thumbnail("start_window_drag", self.os_window_id, dragged_window_id)
|
request_callback_with_thumbnail("start_window_drag", self.os_window_id, dragged_window_id)
|
||||||
|
self.recent_title_bar_mouse_events.clear()
|
||||||
return
|
return
|
||||||
self.recent_title_bar_mouse_events.add(button, modifiers, action, x, y, window_id)
|
self.recent_title_bar_mouse_events.add(button, modifiers, action, x, y, window_id)
|
||||||
if button != GLFW_MOUSE_BUTTON_LEFT:
|
if button != GLFW_MOUSE_BUTTON_LEFT:
|
||||||
@@ -1839,7 +1846,8 @@ class TabManager: # {{{
|
|||||||
|
|
||||||
dragged_window_id, drag_started = get_window_being_dragged()[:2]
|
dragged_window_id, drag_started = get_window_being_dragged()[:2]
|
||||||
set_window_being_dragged()
|
set_window_being_dragged()
|
||||||
if not drag_started and self.recent_title_bar_mouse_events.is_double_click():
|
if not drag_started and self.recent_title_bar_mouse_events.click_count() == 2:
|
||||||
|
self.recent_title_bar_mouse_events.clear()
|
||||||
if (w := boss.window_id_map.get(window_id)) is not None:
|
if (w := boss.window_id_map.get(window_id)) is not None:
|
||||||
w.set_window_title()
|
w.set_window_title()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user