|
@@ -114,6 +114,7 @@ class Yabai(CLIWrapper):
|
|
|
("Browser", True, ["Firefox"], True),
|
|
("Browser", True, ["Firefox"], True),
|
|
|
]
|
|
]
|
|
|
_initial_window: Window | None = None
|
|
_initial_window: Window | None = None
|
|
|
|
|
+ _initial_spaces: list[Space] = []
|
|
|
_dual_display: None | Literal[True] | Literal[False] = None
|
|
_dual_display: None | Literal[True] | Literal[False] = None
|
|
|
_exit_with_rule_apply: bool = False
|
|
_exit_with_rule_apply: bool = False
|
|
|
_exit_with_refocus: bool = False
|
|
_exit_with_refocus: bool = False
|
|
@@ -121,8 +122,7 @@ class Yabai(CLIWrapper):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
def __init__(self):
|
|
|
self._dual_display = len(self.get_displays()) > 1
|
|
self._dual_display = len(self.get_displays()) > 1
|
|
|
- if self._dual_display:
|
|
|
|
|
- self.spaces.append(
|
|
|
|
|
|
|
+ self.spaces.append(
|
|
|
(
|
|
(
|
|
|
"Communication",
|
|
"Communication",
|
|
|
False,
|
|
False,
|
|
@@ -130,6 +130,7 @@ class Yabai(CLIWrapper):
|
|
|
False,
|
|
False,
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
|
|
|
+ if self._dual_display:
|
|
|
for application in [
|
|
for application in [
|
|
|
"Google Meet",
|
|
"Google Meet",
|
|
|
"Obsidian",
|
|
"Obsidian",
|
|
@@ -147,18 +148,11 @@ class Yabai(CLIWrapper):
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
|
else:
|
|
else:
|
|
|
- self.spaces.append(
|
|
|
|
|
- (
|
|
|
|
|
- "Communication",
|
|
|
|
|
- False,
|
|
|
|
|
- ["Slack", "Signal", "Spotify", "Notion"],
|
|
|
|
|
- False,
|
|
|
|
|
- )
|
|
|
|
|
- )
|
|
|
|
|
- self.spaces.append(("Notetaking", True, ["Obsidian", "Asana"], False))
|
|
|
|
|
|
|
+ self.spaces.append(("Notetaking", True, ["Obsidian", "Asana", "Notion"], False))
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
def __enter__(self):
|
|
|
self._initial_window = self.get_focused_window()
|
|
self._initial_window = self.get_focused_window()
|
|
|
|
|
+ self._initial_spaces = [s for s in self.get_spaces() if s.is_visible and len(s.label)]
|
|
|
return self
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any):
|
|
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any):
|
|
@@ -167,10 +161,15 @@ class Yabai(CLIWrapper):
|
|
|
if self._exit_with_rule_apply:
|
|
if self._exit_with_rule_apply:
|
|
|
self.message(["rule", "--apply"])
|
|
self.message(["rule", "--apply"])
|
|
|
if self._exit_with_refocus or self._exit_with_rule_apply:
|
|
if self._exit_with_refocus or self._exit_with_rule_apply:
|
|
|
|
|
+ for space in self._initial_spaces:
|
|
|
|
|
+ try:
|
|
|
|
|
+ self.message(["space", "--focus", space.label])
|
|
|
|
|
+ except CalledProcessError:
|
|
|
|
|
+ pass
|
|
|
if self._initial_window is not None:
|
|
if self._initial_window is not None:
|
|
|
self.message(["window", "--focus", self._initial_window.id])
|
|
self.message(["window", "--focus", self._initial_window.id])
|
|
|
if exc_type is None:
|
|
if exc_type is None:
|
|
|
- debug(f"Executed successfully")
|
|
|
|
|
|
|
+ debug("Executed successfully")
|
|
|
|
|
|
|
|
def get_windows(self) -> set[Window]:
|
|
def get_windows(self) -> set[Window]:
|
|
|
return {
|
|
return {
|
|
@@ -189,7 +188,7 @@ class Yabai(CLIWrapper):
|
|
|
def get_main_display(
|
|
def get_main_display(
|
|
|
self, displays: set[YabaiDisplay] | None = None
|
|
self, displays: set[YabaiDisplay] | None = None
|
|
|
) -> YabaiDisplay:
|
|
) -> YabaiDisplay:
|
|
|
- return sorted(list(displays if displays != None else self.get_displays()))[-1]
|
|
|
|
|
|
|
+ return sorted(list(displays if displays is not None else self.get_displays()))[-1]
|
|
|
|
|
|
|
|
def is_blank_space(self, space: Space) -> bool:
|
|
def is_blank_space(self, space: Space) -> bool:
|
|
|
return (
|
|
return (
|
|
@@ -206,7 +205,7 @@ class Yabai(CLIWrapper):
|
|
|
self.message(
|
|
self.message(
|
|
|
["display", display.index, "--label", self._display_labels[0]]
|
|
["display", display.index, "--label", self._display_labels[0]]
|
|
|
)
|
|
)
|
|
|
- elif secondary_display == None:
|
|
|
|
|
|
|
+ elif secondary_display is None:
|
|
|
self.message(
|
|
self.message(
|
|
|
["display", display.index, "--label", self._display_labels[1]]
|
|
["display", display.index, "--label", self._display_labels[1]]
|
|
|
)
|
|
)
|
|
@@ -274,6 +273,19 @@ class Yabai(CLIWrapper):
|
|
|
# Return focus
|
|
# Return focus
|
|
|
if initial_window is not None:
|
|
if initial_window is not None:
|
|
|
self.message(["window", "--focus", initial_window.id])
|
|
self.message(["window", "--focus", initial_window.id])
|
|
|
|
|
+ if self._dual_display:
|
|
|
|
|
+ display_by_space_label = {s[0]: 1 if s[-1] else 2 for s in self.spaces}
|
|
|
|
|
+ spaces = self.get_spaces()
|
|
|
|
|
+ wrong_spaces = [s for s in spaces
|
|
|
|
|
+ if s.label in display_by_space_label and
|
|
|
|
|
+ s.display != display_by_space_label[s.label]]
|
|
|
|
|
+ wrong_main_spaces = [s for s in wrong_spaces if s.display != 1]
|
|
|
|
|
+ wrong_secondary_spaces = [s for s in wrong_spaces if s.display != 2]
|
|
|
|
|
+ while len(wrong_main_spaces) and len (wrong_secondary_spaces):
|
|
|
|
|
+ self.message([ "space", wrong_main_spaces.pop().label, "--swap", wrong_secondary_spaces.pop().label ])
|
|
|
|
|
+ wrong_spaces = wrong_main_spaces + wrong_secondary_spaces
|
|
|
|
|
+ while len(wrong_spaces) and (space := wrong_spaces.pop().label):
|
|
|
|
|
+ self.message([ "space", space, "--display", display_by_space_label[space]])
|
|
|
info(f"Spaces configured: {sorted(self.get_spaces())}")
|
|
info(f"Spaces configured: {sorted(self.get_spaces())}")
|
|
|
|
|
|
|
|
def set_space_background(self, space: SpaceSel):
|
|
def set_space_background(self, space: SpaceSel):
|
|
@@ -290,6 +302,10 @@ class Yabai(CLIWrapper):
|
|
|
]
|
|
]
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ def set_global_config( self,):
|
|
|
|
|
+ self.message(["config", "auto_balance", "on"])
|
|
|
|
|
+ self.message(["config", "mouse_follows_focus", "on"])
|
|
|
|
|
+
|
|
|
def set_config(
|
|
def set_config(
|
|
|
self,
|
|
self,
|
|
|
space: SpaceSel,
|
|
space: SpaceSel,
|
|
@@ -391,10 +407,21 @@ class Yabai(CLIWrapper):
|
|
|
"event=window_focused",
|
|
"event=window_focused",
|
|
|
"app=Alacritty",
|
|
"app=Alacritty",
|
|
|
"label=AlacrittyCheckDarkMode",
|
|
"label=AlacrittyCheckDarkMode",
|
|
|
- f"action=/bin/zsh {HOME}/.scripts/lightmode.zsh",
|
|
|
|
|
|
|
+ "action=/bin/zsh $DOTFILES_DIR/.scripts/lightmode.zsh",
|
|
|
]
|
|
]
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ if self._dual_display:
|
|
|
|
|
+ self.message(
|
|
|
|
|
+ [
|
|
|
|
|
+ "signal",
|
|
|
|
|
+ "--add",
|
|
|
|
|
+ "event=window_focused",
|
|
|
|
|
+ "label=DisplayBrightnessManager",
|
|
|
|
|
+ "action=/bin/zsh $DOTFILES_DIR/.scripts/display_brightness.zsh",
|
|
|
|
|
+ ]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
for trigger in [
|
|
for trigger in [
|
|
|
"display_added",
|
|
"display_added",
|
|
|
"display_removed",
|
|
"display_removed",
|
|
@@ -412,9 +439,7 @@ class Yabai(CLIWrapper):
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
# Rules that differ for one or multiple displays
|
|
# Rules that differ for one or multiple displays
|
|
|
- if self._dual_display:
|
|
|
|
|
- pass
|
|
|
|
|
- else:
|
|
|
|
|
|
|
+ if not self._dual_display:
|
|
|
# Google Meet and Slack Huddles should be "sticky"
|
|
# Google Meet and Slack Huddles should be "sticky"
|
|
|
for app, title in (("Google Meet", ".*"), ("Slack", "Huddle.*")):
|
|
for app, title in (("Google Meet", ".*"), ("Slack", "Huddle.*")):
|
|
|
self.message(
|
|
self.message(
|
|
@@ -435,8 +460,8 @@ class Yabai(CLIWrapper):
|
|
|
[
|
|
[
|
|
|
"rule",
|
|
"rule",
|
|
|
"--add",
|
|
"--add",
|
|
|
- f"label=NetflixFloatingWindowRule",
|
|
|
|
|
- f"app=Netflix",
|
|
|
|
|
|
|
+ "label=NetflixFloatingWindowRule",
|
|
|
|
|
+ "app=Netflix",
|
|
|
"sticky=on",
|
|
"sticky=on",
|
|
|
"manage=on",
|
|
"manage=on",
|
|
|
]
|
|
]
|
|
@@ -535,48 +560,6 @@ class Yabai(CLIWrapper):
|
|
|
return windows.pop()
|
|
return windows.pop()
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
- def invert_displays(self) -> None:
|
|
|
|
|
- if not self._dual_display:
|
|
|
|
|
- return
|
|
|
|
|
- displays = self.get_displays()
|
|
|
|
|
- for display in displays:
|
|
|
|
|
- self.message(
|
|
|
|
|
- [
|
|
|
|
|
- "display",
|
|
|
|
|
- display.index,
|
|
|
|
|
- "--label",
|
|
|
|
|
- f"TEMP{display.label}",
|
|
|
|
|
- ]
|
|
|
|
|
- )
|
|
|
|
|
- for display in displays:
|
|
|
|
|
- if display.label == self._display_labels[0]:
|
|
|
|
|
- self.message(
|
|
|
|
|
- [
|
|
|
|
|
- "display",
|
|
|
|
|
- display.index,
|
|
|
|
|
- "--label",
|
|
|
|
|
- self._display_labels[1],
|
|
|
|
|
- ]
|
|
|
|
|
- )
|
|
|
|
|
- elif display.label == self._display_labels[1]:
|
|
|
|
|
- self.message(
|
|
|
|
|
- [
|
|
|
|
|
- "display",
|
|
|
|
|
- display.index,
|
|
|
|
|
- "--label",
|
|
|
|
|
- self._display_labels[0],
|
|
|
|
|
- ]
|
|
|
|
|
- )
|
|
|
|
|
- else:
|
|
|
|
|
- self.message(
|
|
|
|
|
- [
|
|
|
|
|
- "display",
|
|
|
|
|
- display.index,
|
|
|
|
|
- "--label",
|
|
|
|
|
- display.label,
|
|
|
|
|
- ]
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
def enable_exit_with_rule_apply(self):
|
|
def enable_exit_with_rule_apply(self):
|
|
|
self._exit_with_rule_apply = True
|
|
self._exit_with_rule_apply = True
|
|
|
self.enable_exit_with_refocus()
|
|
self.enable_exit_with_refocus()
|
|
@@ -590,21 +573,16 @@ if __name__ == "__main__":
|
|
|
debug(f"Called with parameters {argv}")
|
|
debug(f"Called with parameters {argv}")
|
|
|
with Yabai() as yabai:
|
|
with Yabai() as yabai:
|
|
|
if argv[1] == "manage" or argv[1] == "initialize":
|
|
if argv[1] == "manage" or argv[1] == "initialize":
|
|
|
|
|
+ yabai.set_global_config()
|
|
|
yabai.enable_exit_with_rule_apply()
|
|
yabai.enable_exit_with_rule_apply()
|
|
|
yabai.manage_displays()
|
|
yabai.manage_displays()
|
|
|
yabai.manage_spaces()
|
|
yabai.manage_spaces()
|
|
|
if argv[1] == "initialize":
|
|
if argv[1] == "initialize":
|
|
|
yabai.set_rules_and_signals()
|
|
yabai.set_rules_and_signals()
|
|
|
- if argv[1] == "invert":
|
|
|
|
|
- yabai.invert_displays()
|
|
|
|
|
- yabai.enable_exit_with_rule_apply()
|
|
|
|
|
if (
|
|
if (
|
|
|
argv[1] == "move"
|
|
argv[1] == "move"
|
|
|
or argv[1] == "manage"
|
|
or argv[1] == "manage"
|
|
|
or argv[1] == "initialize"
|
|
or argv[1] == "initialize"
|
|
|
- or argv[1] == "invert"
|
|
|
|
|
):
|
|
):
|
|
|
yabai.enable_exit_with_refocus()
|
|
yabai.enable_exit_with_refocus()
|
|
|
yabai.move_spaces_to_displays()
|
|
yabai.move_spaces_to_displays()
|
|
|
- # Disabled until moving spaces no longer triggers mission control
|
|
|
|
|
- # yabai.sort_spaces()
|
|
|