150 lines
4.1 KiB
Python
150 lines
4.1 KiB
Python
from abc import ABC, abstractmethod
|
|
from .config import OutputConfig
|
|
|
|
|
|
class AbstractWorkspaceBackend(ABC):
|
|
"""
|
|
Abstract class for workspace backends (i.e. an IPC interface to a compositor / window manager)
|
|
"""
|
|
|
|
_instance: "AbstractWorkspaceBackend" = None
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
if self._instance is not None:
|
|
raise RuntimeError(
|
|
"Cannot instantiate more than one WorkspaceBackend at a time. Use getBackend() to get the current backend."
|
|
)
|
|
self._instance = self
|
|
|
|
def _scaleToString(self, scale: int) -> str:
|
|
"""Convert the fixed-point scale to a string"""
|
|
# We do it this way to not lose precision when converting to a float
|
|
return f"{scale // 100}.{scale % 100}"
|
|
|
|
@abstractmethod
|
|
async def focusWorkspace(self, index: int):
|
|
"""Focus a workspace in the compositor based off of its compositor index"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def moveWorkspace(self, index: int, output: str):
|
|
"""Move a workspace to a given output"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def focusOutput(self, output: str):
|
|
"""Focus an output in the compositor"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def moveContainer(self, workspace: int):
|
|
"""Move the focused container to a given workspace compositor index"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def configureOutput(self, output: str, config: OutputConfig):
|
|
"""Configure an output"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def disableOutput(self, output: str):
|
|
"""Disable an output"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def onWorkspaceChange(self, callback):
|
|
"""Register a callback to be called when the workspace changes"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def onOutputChange(self, callback):
|
|
"""Register a callback to be called when the output configuration changes"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def onModeChange(self, callback):
|
|
"""Register a callback to be called when the binding mode changes, in compositors that support it"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def getOutputs(self) -> list[OutputAdapter]:
|
|
"""Get the currently connected outputs"""
|
|
|
|
@abstractmethod
|
|
@property
|
|
def name(self) -> str:
|
|
"""The name of the backend"""
|
|
pass
|
|
|
|
|
|
def getBackend() -> AbstractWorkspaceBackend:
|
|
"""
|
|
Get the currently-active workspace backend
|
|
"""
|
|
|
|
if AbstractWorkspaceBackend._instance is None:
|
|
raise RuntimeError(
|
|
"No workspace backend is currently active. Please instantiate one."
|
|
)
|
|
return AbstractWorkspaceBackend._instance
|
|
|
|
|
|
class WorkspaceAdapter:
|
|
"""
|
|
Common interface for workspace backends that represents the result of a
|
|
workspace query. Only contains information that the workspace manager needs to know.
|
|
"""
|
|
|
|
def __init__(
|
|
self, index: int, output: str, focused: bool, visible: bool, urgent: bool
|
|
):
|
|
self.index = index
|
|
self.output = output
|
|
self.focused = focused
|
|
self.visible = visible
|
|
self.urgent = urgent
|
|
|
|
|
|
class RectAdapter:
|
|
"""
|
|
Common interface for workspace backends that represents a rectangle.
|
|
"""
|
|
|
|
def __init__(self, x: int, y: int, width: int, height: int):
|
|
self.x = x
|
|
self.y = y
|
|
self.width = width
|
|
self.height = height
|
|
|
|
|
|
class OutputAdapter:
|
|
"""
|
|
Common interface for workspace backends that represents the result of an
|
|
output query. Only contains information that the workspace manager needs to know.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
active: bool,
|
|
rect: RectAdapter,
|
|
scale: int,
|
|
transform: str,
|
|
focused: bool,
|
|
current_workspace: int,
|
|
make: str,
|
|
model: str,
|
|
serial: str,
|
|
):
|
|
self.name = name
|
|
self.active = active
|
|
self.rect = rect
|
|
self.scale = scale
|
|
self.transform = transform
|
|
self.focused = focused
|
|
self.current_workspace = current_workspace
|
|
self.make = make
|
|
self.model = model
|
|
self.serial = serial
|