From c2d28a32a4a322c54cbc06bc76c541dc53556c0a Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Sun, 23 Jun 2024 17:42:55 -0700 Subject: [PATCH 1/9] Adds some snap helpers to split windows to the left in various ways --- core/windows_and_tabs/window_management.talon | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 859c6fb7dd..2ec8c38e1b 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -17,5 +17,24 @@ snap last [screen]: user.move_window_previous_screen() snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) +snap left : + user.switcher_focus(running_applications_1) + user.snap_window_to_position("left") + user.switcher_focus(running_applications_2) + user.snap_window_to_position("right") +snap left : + user.switcher_focus(running_applications_1) + user.snap_window_to_position("left third") + user.switcher_focus(running_applications_2) + user.snap_window_to_position("center third") + user.switcher_focus(running_applications_3) + user.snap_window_to_position("right third") +snap clock : + user.switcher_focus(running_applications_1) + user.snap_window_to_position("left") + user.switcher_focus(running_applications_2) + user.snap_window_to_position("top right") + user.switcher_focus(running_applications_3) + user.snap_window_to_position("bottom right") snap [screen] : user.move_app_to_screen(running_applications, number) From 7ff556412d745ecf60efa6bd1016bca7a0110655 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Sun, 23 Jun 2024 17:49:41 -0700 Subject: [PATCH 2/9] Add snap right command - operates opposite of snap left --- core/windows_and_tabs/window_management.talon | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 2ec8c38e1b..5f22d666c9 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -29,6 +29,18 @@ snap left : + user.switcher_focus(running_applications_2) + user.snap_window_to_position("left") + user.switcher_focus(running_applications_1) + user.snap_window_to_position("right") +snap right : + user.switcher_focus(running_applications_3) + user.snap_window_to_position("left third") + user.switcher_focus(running_applications_2) + user.snap_window_to_position("center third") + user.switcher_focus(running_applications_1) + user.snap_window_to_position("right third") snap clock : user.switcher_focus(running_applications_1) user.snap_window_to_position("left") From e9c71191bfcb1ccad05ee9b011d2fea1e8eada5a Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Sun, 23 Jun 2024 18:11:06 -0700 Subject: [PATCH 3/9] Add counterclock and focus main content --- core/windows_and_tabs/window_management.talon | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 5f22d666c9..a1fc85bd49 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -42,11 +42,18 @@ snap right : - user.switcher_focus(running_applications_1) - user.snap_window_to_position("left") user.switcher_focus(running_applications_2) user.snap_window_to_position("top right") user.switcher_focus(running_applications_3) user.snap_window_to_position("bottom right") + user.switcher_focus(running_applications_1) + user.snap_window_to_position("left") +snap counterclock : + user.switcher_focus(running_applications_2) + user.snap_window_to_position("top left") + user.switcher_focus(running_applications_3) + user.snap_window_to_position("bottom left") + user.switcher_focus(running_applications_1) + user.snap_window_to_position("right") snap [screen] : user.move_app_to_screen(running_applications, number) From 2fd3a03f379b568f69ace32b616b0e37aab42511 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Sat, 6 Jul 2024 13:55:45 -0700 Subject: [PATCH 4/9] Used custom functions instead - We're concerned about using the existing names in talonscript since folks may want to remap the names - This relies on existing internal apis instead --- core/windows_and_tabs/window_management.talon | 42 +++-------------- core/windows_and_tabs/window_snap.py | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index a1fc85bd49..0a1c2d0575 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -17,43 +17,13 @@ snap last [screen]: user.move_window_previous_screen() snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) -snap left : - user.switcher_focus(running_applications_1) - user.snap_window_to_position("left") - user.switcher_focus(running_applications_2) - user.snap_window_to_position("right") -snap left : - user.switcher_focus(running_applications_1) - user.snap_window_to_position("left third") - user.switcher_focus(running_applications_2) - user.snap_window_to_position("center third") - user.switcher_focus(running_applications_3) - user.snap_window_to_position("right third") -snap right : - user.switcher_focus(running_applications_2) - user.snap_window_to_position("left") - user.switcher_focus(running_applications_1) - user.snap_window_to_position("right") -snap right : - user.switcher_focus(running_applications_3) - user.snap_window_to_position("left third") - user.switcher_focus(running_applications_2) - user.snap_window_to_position("center third") - user.switcher_focus(running_applications_1) - user.snap_window_to_position("right third") +snap split : + user.snap_split_two(running_applications_1, running_applications_2) +snap split : + user.snap_split_three(running_applications_1, running_applications_2, running_applications_3) snap clock : - user.switcher_focus(running_applications_2) - user.snap_window_to_position("top right") - user.switcher_focus(running_applications_3) - user.snap_window_to_position("bottom right") - user.switcher_focus(running_applications_1) - user.snap_window_to_position("left") + user.snap_clock_three(running_applications_1, running_applications_2, running_applications_3) snap counterclock : - user.switcher_focus(running_applications_2) - user.snap_window_to_position("top left") - user.switcher_focus(running_applications_3) - user.snap_window_to_position("bottom left") - user.switcher_focus(running_applications_1) - user.snap_window_to_position("right") + user.snap_counterclock_three(running_applications_1, running_applications_2, running_applications_3) snap [screen] : user.move_app_to_screen(running_applications, number) diff --git a/core/windows_and_tabs/window_snap.py b/core/windows_and_tabs/window_snap.py index ef56cc83fb..45706f1017 100644 --- a/core/windows_and_tabs/window_snap.py +++ b/core/windows_and_tabs/window_snap.py @@ -310,6 +310,51 @@ def snap_app(app_name: str, position: RelativeScreenPos): _bring_forward(window) _snap_window_helper(window, position) + def snap_split_two(app_one: str, app_two: str): + """Split the screen between two applications.""" + window_two = _get_app_window(app_two) + _bring_forward(window_two) + _snap_window_helper(window_two, RelativeScreenPos(0.5, 0, 1, 1)) + window = _get_app_window(app_one) + _bring_forward(window) + _snap_window_helper(window, RelativeScreenPos(0, 0, 0.5, 1)) + + def snap_clock_three(app_one: str, app_two: str, app_three: str): + """Split the screen clockwise between three applications.""" + window_three = _get_app_window(app_three) + _bring_forward(window_three) + _snap_window_helper(window_three, RelativeScreenPos(0.5, 0.5, 1, 1)) + window_two = _get_app_window(app_two) + _bring_forward(window_two) + _snap_window_helper(window_two, RelativeScreenPos(0.5, 0, 1, 0.5)) + window = _get_app_window(app_one) + _bring_forward(window) + _snap_window_helper(window, RelativeScreenPos(0, 0, 0.5, 1)) + + def snap_counterclock_three(app_one: str, app_two: str, app_three: str): + """Split the screen between two applications.""" + window_three = _get_app_window(app_three) + _bring_forward(window_three) + _snap_window_helper(window_three, RelativeScreenPos(0, 0.5, 0.5, 1)) + window_two = _get_app_window(app_two) + _bring_forward(window_two) + _snap_window_helper(window_two, RelativeScreenPos(0, 0, 0.5, 0.5)) + window = _get_app_window(app_one) + _bring_forward(window) + _snap_window_helper(window, RelativeScreenPos(0.5, 0, 1, 1)) + + def snap_split_three(app_one: str, app_two: str, app_three: str): + """Split the screen counterclockwise between three applications.""" + window_three = _get_app_window(app_three) + _bring_forward(window_three) + _snap_window_helper(window_three, RelativeScreenPos(2 / 3, 0, 1, 1)) + window_two = _get_app_window(app_two) + _bring_forward(window_two) + _snap_window_helper(window_two, RelativeScreenPos(1 / 3, 0, 2 / 3, 1)) + window = _get_app_window(app_one) + _bring_forward(window) + _snap_window_helper(window, RelativeScreenPos(0, 0, 1 / 3, 1)) + def move_app_to_screen(app_name: str, screen_number: int): """Move a specific application to another screen.""" window = _get_app_window(app_name) From a0ba23877db1a07ce76e2c25a06c355bf398e67e Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Wed, 21 Aug 2024 17:29:04 -0700 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9C=A8=20feat(window-management):=20enha?= =?UTF-8?q?nce=20window=20snapping=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This consolidates the logic into a single rule in the talon file and reused keys of the existing map for readability. --- core/windows_and_tabs/window_management.talon | 10 +-- core/windows_and_tabs/window_snap.py | 81 ++++++++++--------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 0a1c2d0575..40774a0bd7 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -17,13 +17,9 @@ snap last [screen]: user.move_window_previous_screen() snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) -snap split : +snap : user.snap_split_two(running_applications_1, running_applications_2) -snap split : - user.snap_split_three(running_applications_1, running_applications_2, running_applications_3) -snap clock : - user.snap_clock_three(running_applications_1, running_applications_2, running_applications_3) -snap counterclock : - user.snap_counterclock_three(running_applications_1, running_applications_2, running_applications_3) +snap : + user.snap_split_three(window_split_position, running_applications_1, running_applications_2, running_applications_3) snap [screen] : user.move_app_to_screen(running_applications, number) diff --git a/core/windows_and_tabs/window_snap.py b/core/windows_and_tabs/window_snap.py index 45706f1017..0e42f92539 100644 --- a/core/windows_and_tabs/window_snap.py +++ b/core/windows_and_tabs/window_snap.py @@ -17,6 +17,10 @@ "window_snap_positions", "Predefined window positions for the current window. See `RelativeScreenPos`.", ) +mod.list( + "window_split_positions", + "Predefined window positions when splitting the screen between three applications.", +) mod.setting( "window_snap_screen", type=str, @@ -272,14 +276,38 @@ def __init__(self, left, top, right, bottom): "fullscreen": RelativeScreenPos(0, 0, 1, 1), } +_split_positions = { + "split": [ + _snap_positions["left third"], + _snap_positions["center third"], + _snap_positions["right third"], + ], + "clock": [ + _snap_positions["left"], + _snap_positions["top right"], + _snap_positions["bottom right"], + ], + "counterclock": [ + _snap_positions["right"], + _snap_positions["top left"], + _snap_positions["bottom left"], + ], +} + @mod.capture(rule="{user.window_snap_positions}") def window_snap_position(m) -> RelativeScreenPos: return _snap_positions[m.window_snap_positions] +@mod.capture(rule="{user.window_split_positions}") +def window_split_position(m) -> list[RelativeScreenPos]: + return _split_positions[m.window_split_positions] + + ctx = Context() ctx.lists["user.window_snap_positions"] = _snap_positions.keys() +ctx.lists["user.window_split_positions"] = _split_positions.keys() @mod.action_class @@ -312,48 +340,27 @@ def snap_app(app_name: str, position: RelativeScreenPos): def snap_split_two(app_one: str, app_two: str): """Split the screen between two applications.""" - window_two = _get_app_window(app_two) - _bring_forward(window_two) - _snap_window_helper(window_two, RelativeScreenPos(0.5, 0, 1, 1)) window = _get_app_window(app_one) - _bring_forward(window) - _snap_window_helper(window, RelativeScreenPos(0, 0, 0.5, 1)) - - def snap_clock_three(app_one: str, app_two: str, app_three: str): - """Split the screen clockwise between three applications.""" - window_three = _get_app_window(app_three) - _bring_forward(window_three) - _snap_window_helper(window_three, RelativeScreenPos(0.5, 0.5, 1, 1)) window_two = _get_app_window(app_two) - _bring_forward(window_two) - _snap_window_helper(window_two, RelativeScreenPos(0.5, 0, 1, 0.5)) - window = _get_app_window(app_one) - _bring_forward(window) - _snap_window_helper(window, RelativeScreenPos(0, 0, 0.5, 1)) + _snap_window_helper(window_two, _snap_positions["right"]) + _snap_window_helper(window, _snap_positions["left"]) + window_two.focus() + window.focus() - def snap_counterclock_three(app_one: str, app_two: str, app_three: str): - """Split the screen between two applications.""" - window_three = _get_app_window(app_three) - _bring_forward(window_three) - _snap_window_helper(window_three, RelativeScreenPos(0, 0.5, 0.5, 1)) - window_two = _get_app_window(app_two) - _bring_forward(window_two) - _snap_window_helper(window_two, RelativeScreenPos(0, 0, 0.5, 0.5)) + def snap_split_three( + positions: list[RelativeScreenPos], app_one: str, app_two: str, app_three: str + ): + """Split the screen between three applications.""" window = _get_app_window(app_one) - _bring_forward(window) - _snap_window_helper(window, RelativeScreenPos(0.5, 0, 1, 1)) - - def snap_split_three(app_one: str, app_two: str, app_three: str): - """Split the screen counterclockwise between three applications.""" - window_three = _get_app_window(app_three) - _bring_forward(window_three) - _snap_window_helper(window_three, RelativeScreenPos(2 / 3, 0, 1, 1)) window_two = _get_app_window(app_two) - _bring_forward(window_two) - _snap_window_helper(window_two, RelativeScreenPos(1 / 3, 0, 2 / 3, 1)) - window = _get_app_window(app_one) - _bring_forward(window) - _snap_window_helper(window, RelativeScreenPos(0, 0, 1 / 3, 1)) + window_three = _get_app_window(app_three) + _snap_window_helper(window, positions[0]) + _snap_window_helper(window_two, positions[1]) + _snap_window_helper(window_three, positions[2]) + + window_three.focus() + window_two.focus() + window.focus() def move_app_to_screen(app_name: str, screen_number: int): """Move a specific application to another screen.""" From fb34ba6d9f79b1f12c49b0894a5a526b57e9ddc9 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 17 Oct 2024 19:05:22 -0700 Subject: [PATCH 6/9] Respond to pull request feedback --- core/windows_and_tabs/window_management.talon | 4 +- core/windows_and_tabs/window_snap.py | 77 +++++++++---------- 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 40774a0bd7..12bef8e7d7 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -18,8 +18,8 @@ snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) snap : - user.snap_split_two(running_applications_1, running_applications_2) + user.snap_layout(window_split_position, running_applications_1, running_applications_2) snap : - user.snap_split_three(window_split_position, running_applications_1, running_applications_2, running_applications_3) + user.snap_layout(window_split_position, running_applications_1, running_applications_2, running_applications_3) snap [screen] : user.move_app_to_screen(running_applications, number) diff --git a/core/windows_and_tabs/window_snap.py b/core/windows_and_tabs/window_snap.py index 0e42f92539..c0962d88ed 100644 --- a/core/windows_and_tabs/window_snap.py +++ b/core/windows_and_tabs/window_snap.py @@ -8,7 +8,7 @@ # platforms import logging -from typing import Optional +from typing import Dict, Optional from talon import Context, Module, actions, settings, ui @@ -277,21 +277,30 @@ def __init__(self, left, top, right, bottom): } _split_positions = { - "split": [ - _snap_positions["left third"], - _snap_positions["center third"], - _snap_positions["right third"], - ], - "clock": [ - _snap_positions["left"], - _snap_positions["top right"], - _snap_positions["bottom right"], - ], - "counterclock": [ - _snap_positions["right"], - _snap_positions["top left"], - _snap_positions["bottom left"], - ], + "split": { + 2: [_snap_positions["left"], _snap_positions["right"]], + 3: [ + _snap_positions["left third"], + _snap_positions["center third"], + _snap_positions["right third"], + ], + }, + "clock": { + 2: [_snap_positions["left"], _snap_positions["right"]], + 3: [ + _snap_positions["left"], + _snap_positions["top right"], + _snap_positions["bottom right"], + ], + }, + "counterclock": { + 2: [_snap_positions["left"], _snap_positions["right"]], + 3: [ + _snap_positions["right"], + _snap_positions["top left"], + _snap_positions["bottom left"], + ], + }, } @@ -301,7 +310,7 @@ def window_snap_position(m) -> RelativeScreenPos: @mod.capture(rule="{user.window_split_positions}") -def window_split_position(m) -> list[RelativeScreenPos]: +def window_split_position(m) -> Dict[int, list[RelativeScreenPos]]: return _split_positions[m.window_split_positions] @@ -338,29 +347,19 @@ def snap_app(app_name: str, position: RelativeScreenPos): _bring_forward(window) _snap_window_helper(window, position) - def snap_split_two(app_one: str, app_two: str): - """Split the screen between two applications.""" - window = _get_app_window(app_one) - window_two = _get_app_window(app_two) - _snap_window_helper(window_two, _snap_positions["right"]) - _snap_window_helper(window, _snap_positions["left"]) - window_two.focus() - window.focus() - - def snap_split_three( - positions: list[RelativeScreenPos], app_one: str, app_two: str, app_three: str + def snap_layout( + positions_by_count: Dict[int, list[RelativeScreenPos]], + app_one: str, + app_two: str, + app_three: Optional[str] = None, ): - """Split the screen between three applications.""" - window = _get_app_window(app_one) - window_two = _get_app_window(app_two) - window_three = _get_app_window(app_three) - _snap_window_helper(window, positions[0]) - _snap_window_helper(window_two, positions[1]) - _snap_window_helper(window_three, positions[2]) - - window_three.focus() - window_two.focus() - window.focus() + """Split the screen between multiple applications.""" + apps = [app for app in [app_one, app_two, app_three] if app is not None] + positions = positions_by_count[len(apps)] + for index, app in enumerate(apps): + window = _get_app_window(app) + _snap_window_helper(window, positions[index]) + window.focus() def move_app_to_screen(app_name: str, screen_number: int): """Move a specific application to another screen.""" From d50497bd68223502bae288602005bb3c872e4dd6 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 17 Oct 2024 19:11:38 -0700 Subject: [PATCH 7/9] Respond to pull request feedback --- core/windows_and_tabs/window_management.talon | 6 ++---- core/windows_and_tabs/window_snap.py | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 12bef8e7d7..aa7dfb9567 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -17,9 +17,7 @@ snap last [screen]: user.move_window_previous_screen() snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) -snap : - user.snap_layout(window_split_position, running_applications_1, running_applications_2) -snap : - user.snap_layout(window_split_position, running_applications_1, running_applications_2, running_applications_3) +snap +: + user.snap_layout(window_split_position, running_applications_list) snap [screen] : user.move_app_to_screen(running_applications, number) diff --git a/core/windows_and_tabs/window_snap.py b/core/windows_and_tabs/window_snap.py index c0962d88ed..a31598839c 100644 --- a/core/windows_and_tabs/window_snap.py +++ b/core/windows_and_tabs/window_snap.py @@ -349,12 +349,9 @@ def snap_app(app_name: str, position: RelativeScreenPos): def snap_layout( positions_by_count: Dict[int, list[RelativeScreenPos]], - app_one: str, - app_two: str, - app_three: Optional[str] = None, + apps: list[str], ): """Split the screen between multiple applications.""" - apps = [app for app in [app_one, app_two, app_three] if app is not None] positions = positions_by_count[len(apps)] for index, app in enumerate(apps): window = _get_app_window(app) From 64ca1b0c83696406d5817ce1393d01c1d30431fc Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 17 Oct 2024 20:11:30 -0700 Subject: [PATCH 8/9] Print a more helpful error message when a split layout is not yet defined --- core/windows_and_tabs/window_snap.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/windows_and_tabs/window_snap.py b/core/windows_and_tabs/window_snap.py index a31598839c..e098841817 100644 --- a/core/windows_and_tabs/window_snap.py +++ b/core/windows_and_tabs/window_snap.py @@ -352,7 +352,12 @@ def snap_layout( apps: list[str], ): """Split the screen between multiple applications.""" - positions = positions_by_count[len(apps)] + try: + positions = positions_by_count[len(apps)] + except KeyError: + raise NotImplementedError( + f"There is no such layout yet defined for {len(apps)} items" + ) for index, app in enumerate(apps): window = _get_app_window(app) _snap_window_helper(window, positions[index]) From 66f99bf719c72c61e18c8fd263ce22ecb1a4636b Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 17 Oct 2024 21:20:45 -0700 Subject: [PATCH 9/9] Make it so it's impossible to match snap split with a single application --- core/windows_and_tabs/window_management.talon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index aa7dfb9567..539d53b0a2 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -17,7 +17,7 @@ snap last [screen]: user.move_window_previous_screen() snap screen : user.move_window_to_screen(number) snap : user.snap_app(running_applications, window_snap_position) -snap +: +snap +: user.snap_layout(window_split_position, running_applications_list) snap [screen] : user.move_app_to_screen(running_applications, number)