Improved output name selection and context scoring
This commit is contained in:
parent
c478a4f7d4
commit
c439ad41aa
@ -1,10 +1,8 @@
|
||||
from sdbus import (
|
||||
DbusInterfaceCommonAsync,
|
||||
dbus_method_async,
|
||||
dbus_property_async,
|
||||
dbus_signal_async,
|
||||
)
|
||||
import os
|
||||
from .workspace_tree import WorkspaceTree
|
||||
from i3ipc.aio import Connection
|
||||
import json
|
||||
@ -25,6 +23,15 @@ class ContextMngrInterface(
|
||||
self.workspace_tree = workspace_tree
|
||||
self.connection = connection
|
||||
|
||||
@dbus_method_async(input_signature="", result_signature="as")
|
||||
async def get_available_contexts(self) -> list[str]:
|
||||
"""
|
||||
Request a list of contexts compatible with the current monitor configuration, sorted by score.
|
||||
"""
|
||||
scores = await self.workspace_tree.score_contexts(self.connection)
|
||||
contexts = [score[0].name for score in scores if score[1] > 0]
|
||||
return contexts
|
||||
|
||||
@dbus_method_async(input_signature="s", result_signature="s")
|
||||
async def request_context(self, context: str) -> str:
|
||||
"""Request a context switch. This will fail if the current monitor configuration is not compatible with the requested context."""
|
||||
|
||||
@ -3,8 +3,8 @@ import json
|
||||
from i3ipc.replies import OutputReply, WorkspaceReply
|
||||
from i3ipc.aio import Connection
|
||||
import asyncio
|
||||
import subprocess
|
||||
from .utils import OutputMatch
|
||||
import itertools
|
||||
|
||||
DEFAULT_TERMINAL = "alacritty"
|
||||
|
||||
@ -90,6 +90,7 @@ class WorkspaceGroup:
|
||||
name: str = None
|
||||
workspaces: list[Workspace] = None
|
||||
reverse: bool = False
|
||||
output_name: str = None
|
||||
|
||||
def __init__(self, output_data: dict[str, str]):
|
||||
self.name = output_data["group"]
|
||||
@ -156,10 +157,12 @@ class WorkspaceGroup:
|
||||
mode = f"mode {self.mode}"
|
||||
if self.make and self.model and self.serial:
|
||||
selector = f'"{self.make} {self.model} {self.serial}"'
|
||||
await self.get_output_name(i3, force=True)
|
||||
elif len(self.output_names) > 0:
|
||||
for name in self.output_names:
|
||||
if name in [output.name for output in outputs]:
|
||||
selector = name
|
||||
self.output_name = selector
|
||||
break
|
||||
# Configure the output
|
||||
await i3.command(
|
||||
@ -193,8 +196,10 @@ class WorkspaceGroup:
|
||||
)
|
||||
await workspace.relocate(i3, ouput_name)
|
||||
|
||||
async def get_output_name(self, i3: Connection) -> str:
|
||||
async def get_output_name(self, i3: Connection, force: bool = False) -> str:
|
||||
"""Get the name of the output in Sway."""
|
||||
if not force and self.output_name is not None:
|
||||
return self.output_name
|
||||
outputs = await i3.get_outputs()
|
||||
# If we have make, model, and serial, search by those first
|
||||
if self.make and self.model and self.serial:
|
||||
@ -208,6 +213,7 @@ class WorkspaceGroup:
|
||||
f"Found output {output.name} by make, model, and serial for group {self.name}",
|
||||
flush=True,
|
||||
)
|
||||
self.output_name = output.name
|
||||
return output.name
|
||||
# If we don't find an exact match for the output, search by name if we have any
|
||||
if len(self.output_names) > 0:
|
||||
@ -217,6 +223,7 @@ class WorkspaceGroup:
|
||||
f"Found output {output.name} by name for group {self.name}",
|
||||
flush=True,
|
||||
)
|
||||
self.output_name = output.name
|
||||
return output.name
|
||||
return None
|
||||
|
||||
@ -239,9 +246,6 @@ class WorkspaceGroup:
|
||||
flush=True,
|
||||
)
|
||||
return OutputMatch.NAME_MATCH
|
||||
print(
|
||||
f"Match level: NO_MATCH for {output.name} on group {self.name}", flush=True
|
||||
)
|
||||
return OutputMatch.NO_MATCH
|
||||
|
||||
|
||||
@ -293,6 +297,7 @@ class WorkspaceContext:
|
||||
[group.get_match_level(output).value for output in outputs]
|
||||
)
|
||||
if group_result == 0:
|
||||
print(f"Context {self.name}: failed to match group {group.name}")
|
||||
return 0
|
||||
result += group_result
|
||||
return result
|
||||
@ -308,9 +313,6 @@ class WorkspaceContext:
|
||||
|
||||
async def activate(self, i3: Connection):
|
||||
"""Activate the context in Sway."""
|
||||
defined_displays = [
|
||||
f"{group.make} {group.model} {group.serial}" for group in self.groups
|
||||
]
|
||||
outputs = await i3.get_outputs()
|
||||
|
||||
# Configure all displays defined in the context
|
||||
@ -335,11 +337,13 @@ class WorkspaceContext:
|
||||
"eww",
|
||||
"open",
|
||||
window,
|
||||
"--id",
|
||||
f"{group.name}-{window}",
|
||||
"--screen",
|
||||
await group.get_output_name(i3),
|
||||
"--arg",
|
||||
f"group={group.name}",
|
||||
*extra_args,
|
||||
*list(itertools.chain(*extra_args)),
|
||||
)
|
||||
await proc.wait()
|
||||
|
||||
@ -479,19 +483,19 @@ class WorkspaceTree:
|
||||
if ws not in touched:
|
||||
ws.deactivate()
|
||||
|
||||
async def update_context(self, i3: Connection, match_context_on_name: bool = False):
|
||||
"""Activates a new context in Sway based on the current display configuration."""
|
||||
# First, get the current display configuration
|
||||
async def score_contexts(self, i3: Connection):
|
||||
outputs = await i3.get_outputs()
|
||||
print(outputs, flush=True)
|
||||
|
||||
# Next, calculate match scores for each context
|
||||
scores = [
|
||||
(context, context.compatability_rank(outputs)) for context in self.contexts
|
||||
]
|
||||
print([f"{context.name}: {score}" for context, score in scores], flush=True)
|
||||
# Sort the scores by rank
|
||||
scores.sort(key=lambda x: x[1], reverse=True)
|
||||
return scores
|
||||
|
||||
async def update_context(self, i3: Connection, match_context_on_name: bool = False):
|
||||
"""Activates a new context in Sway based on the current display configuration."""
|
||||
# Get the scores
|
||||
scores = await self.score_contexts(i3)
|
||||
|
||||
# If the top context is the current context, or the rank is 0, do nothing
|
||||
if scores[0][1] == 0:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user