gdctl: Fix typing and resulting handling of int|None variables
Introduces two new NamedTuples to deal with dimensions and positions. The position is special in that x and y can be None. This was previously wrongly declared to be only int. This commit fixes instances mypy found where None positions were not handled. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4267>
This commit is contained in:
parent
e5f6704a81
commit
674ebecd00
113
tools/gdctl
113
tools/gdctl
@ -5,7 +5,8 @@ import argcomplete
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from gi.repository import GLib, Gio
|
from typing import NamedTuple, Any
|
||||||
|
from gi.repository import GLib, Gio # type: ignore
|
||||||
from enum import Enum, Flag
|
from enum import Enum, Flag
|
||||||
from argcomplete.completers import BaseCompleter, SuppressCompleter
|
from argcomplete.completers import BaseCompleter, SuppressCompleter
|
||||||
|
|
||||||
@ -14,6 +15,16 @@ INTERFACE = "org.gnome.Mutter.DisplayConfig"
|
|||||||
OBJECT_PATH = "/org/gnome/Mutter/DisplayConfig"
|
OBJECT_PATH = "/org/gnome/Mutter/DisplayConfig"
|
||||||
|
|
||||||
|
|
||||||
|
class Dimension(NamedTuple):
|
||||||
|
width: int
|
||||||
|
height: int
|
||||||
|
|
||||||
|
|
||||||
|
class Position(NamedTuple):
|
||||||
|
x: int | None
|
||||||
|
y: int | None
|
||||||
|
|
||||||
|
|
||||||
class NamedEnum(Enum):
|
class NamedEnum(Enum):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return next(
|
return next(
|
||||||
@ -125,8 +136,7 @@ def print_data(*, level: int, is_last: bool, lines: list[int], data: str):
|
|||||||
|
|
||||||
if level >= 0:
|
if level >= 0:
|
||||||
indent = level
|
indent = level
|
||||||
buffer = f"{link:{padding}>{indent * 4}}──{data}"
|
buffer = list(f"{link:{padding}>{indent * 4}}──{data}")
|
||||||
buffer = list(buffer)
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line == level:
|
if line == level:
|
||||||
continue
|
continue
|
||||||
@ -134,11 +144,10 @@ def print_data(*, level: int, is_last: bool, lines: list[int], data: str):
|
|||||||
if line > 0:
|
if line > 0:
|
||||||
index -= 1
|
index -= 1
|
||||||
buffer[index] = "│"
|
buffer[index] = "│"
|
||||||
buffer = "".join(buffer)
|
|
||||||
else:
|
else:
|
||||||
buffer = data
|
buffer = list(data)
|
||||||
|
|
||||||
print(buffer)
|
print("".join(buffer))
|
||||||
|
|
||||||
if is_last and level in lines:
|
if is_last and level in lines:
|
||||||
lines.remove(level)
|
lines.remove(level)
|
||||||
@ -182,7 +191,7 @@ def strip_dbus_error_prefix(message):
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
def transform_size(size, transform) -> tuple[int, int]:
|
def transform_size(size: Dimension, transform) -> Dimension:
|
||||||
match transform:
|
match transform:
|
||||||
case (
|
case (
|
||||||
Transform.NORMAL
|
Transform.NORMAL
|
||||||
@ -198,14 +207,14 @@ def transform_size(size, transform) -> tuple[int, int]:
|
|||||||
| Transform.ROTATE_270_FLIPPED
|
| Transform.ROTATE_270_FLIPPED
|
||||||
):
|
):
|
||||||
width, height = size
|
width, height = size
|
||||||
return (height, width)
|
return Dimension(height, width)
|
||||||
case _:
|
case _:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def scale_size(size, scale) -> tuple[int, int]:
|
def scale_size(size: Dimension, scale) -> Dimension:
|
||||||
width, height = size
|
width, height = size
|
||||||
return (round(width / scale), round(height / scale))
|
return Dimension(round(width / scale), round(height / scale))
|
||||||
|
|
||||||
|
|
||||||
class DisplayConfig:
|
class DisplayConfig:
|
||||||
@ -266,11 +275,10 @@ class DisplayConfig:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class MonitorMode:
|
class MonitorMode:
|
||||||
name: str
|
name: str
|
||||||
resolution: tuple[int, int]
|
resolution: Dimension
|
||||||
refresh_rate: float
|
refresh_rate: float
|
||||||
preferred_scale: float
|
preferred_scale: float
|
||||||
supported_scales: list[float]
|
supported_scales: list[float]
|
||||||
refresh_rate: float
|
|
||||||
properties: dict
|
properties: dict
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -341,11 +349,11 @@ class Monitor:
|
|||||||
class LogicalMonitor:
|
class LogicalMonitor:
|
||||||
monitors: list[Monitor]
|
monitors: list[Monitor]
|
||||||
scale: float
|
scale: float
|
||||||
position: tuple[int, int] | None = (0, 0)
|
position: Position = Position(0, 0)
|
||||||
transform: Transform = Transform.NORMAL
|
transform: Transform = Transform.NORMAL
|
||||||
is_primary: bool = False
|
is_primary: bool = False
|
||||||
properties: dict = field(default_factory=dict)
|
properties: dict[str, Any] = field(default_factory=dict)
|
||||||
args: dict | None = None
|
args: dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_variant(cls, monitors_state, variant):
|
def from_variant(cls, monitors_state, variant):
|
||||||
@ -434,7 +442,7 @@ def place_right_of(
|
|||||||
else:
|
else:
|
||||||
y = None
|
y = None
|
||||||
|
|
||||||
logical_monitor.position = (x, y)
|
logical_monitor.position = Position(x, y)
|
||||||
|
|
||||||
|
|
||||||
def place_left_of(
|
def place_left_of(
|
||||||
@ -459,7 +467,7 @@ def place_left_of(
|
|||||||
else:
|
else:
|
||||||
y = None
|
y = None
|
||||||
|
|
||||||
logical_monitor.position = (x, y)
|
logical_monitor.position = Position(x, y)
|
||||||
|
|
||||||
|
|
||||||
def place_below(
|
def place_below(
|
||||||
@ -479,9 +487,9 @@ def place_below(
|
|||||||
if set_x_position:
|
if set_x_position:
|
||||||
x, _ = connector_logical_monitor.position
|
x, _ = connector_logical_monitor.position
|
||||||
else:
|
else:
|
||||||
x = logical_monitor.position[0]
|
x = logical_monitor.position.x
|
||||||
|
|
||||||
logical_monitor.position = (x, y)
|
logical_monitor.position = Position(x, y)
|
||||||
|
|
||||||
|
|
||||||
def place_above(
|
def place_above(
|
||||||
@ -504,9 +512,9 @@ def place_above(
|
|||||||
if set_x_position:
|
if set_x_position:
|
||||||
x, _ = connector_logical_monitor.position
|
x, _ = connector_logical_monitor.position
|
||||||
else:
|
else:
|
||||||
x = logical_monitor.position[0]
|
x = logical_monitor.position.x
|
||||||
|
|
||||||
logical_monitor.position = (x, y)
|
logical_monitor.position = Position(x, y)
|
||||||
|
|
||||||
|
|
||||||
class PositionType(Flag):
|
class PositionType(Flag):
|
||||||
@ -536,13 +544,13 @@ def calculate_position(
|
|||||||
|
|
||||||
set_y_position = vertical_args == 0
|
set_y_position = vertical_args == 0
|
||||||
|
|
||||||
|
x = None
|
||||||
|
y = None
|
||||||
|
|
||||||
if "x" in logical_monitor.args:
|
if "x" in logical_monitor.args:
|
||||||
x = int(logical_monitor.args["x"])
|
x = int(logical_monitor.args["x"])
|
||||||
if set_y_position:
|
y = 0 if set_y_position else None
|
||||||
y = 0
|
logical_monitor.position = Position(x, y)
|
||||||
else:
|
|
||||||
y = None
|
|
||||||
logical_monitor.position = (x, y)
|
|
||||||
position_types |= PositionType.ABSOLUTE_X
|
position_types |= PositionType.ABSOLUTE_X
|
||||||
elif "right_of" in logical_monitor.args:
|
elif "right_of" in logical_monitor.args:
|
||||||
connector = logical_monitor.args["right_of"]
|
connector = logical_monitor.args["right_of"]
|
||||||
@ -573,17 +581,14 @@ def calculate_position(
|
|||||||
)
|
)
|
||||||
position_types |= PositionType.RELATIVE_X
|
position_types |= PositionType.RELATIVE_X
|
||||||
else:
|
else:
|
||||||
logical_monitor.position = (0, 0)
|
logical_monitor.position = Position(0, 0)
|
||||||
|
|
||||||
set_x_position = horizontal_args == 0
|
set_x_position = horizontal_args == 0
|
||||||
|
|
||||||
if "y" in logical_monitor.args:
|
if "y" in logical_monitor.args:
|
||||||
y = int(logical_monitor.args["y"])
|
y = int(logical_monitor.args["y"])
|
||||||
if set_x_position:
|
x = 0 if set_x_position else logical_monitor.position.x
|
||||||
x = 0
|
logical_monitor.position = Position(x, y)
|
||||||
else:
|
|
||||||
x = logical_monitor.position[0]
|
|
||||||
logical_monitor.position = (x, y)
|
|
||||||
position_types |= PositionType.ABSOLUTE_Y
|
position_types |= PositionType.ABSOLUTE_Y
|
||||||
elif "below" in logical_monitor.args:
|
elif "below" in logical_monitor.args:
|
||||||
connector = logical_monitor.args["below"]
|
connector = logical_monitor.args["below"]
|
||||||
@ -613,17 +618,19 @@ def calculate_position(
|
|||||||
x, y = logical_monitor.position
|
x, y = logical_monitor.position
|
||||||
if not y:
|
if not y:
|
||||||
y = 0
|
y = 0
|
||||||
logical_monitor.position = (x, y)
|
logical_monitor.position = Position(x, y)
|
||||||
|
|
||||||
assert logical_monitor.position[0] is not None
|
assert logical_monitor.position.x is not None
|
||||||
assert logical_monitor.position[1] is not None
|
assert logical_monitor.position.y is not None
|
||||||
|
|
||||||
return position_types
|
return position_types
|
||||||
|
|
||||||
|
|
||||||
def align_horizontally(logical_monitors: list[LogicalMonitor]):
|
def align_horizontally(logical_monitors: list[LogicalMonitor]):
|
||||||
min_x = min(
|
min_x = min(
|
||||||
logical_monitor.position[0] for logical_monitor in logical_monitors
|
logical_monitor.position.x
|
||||||
|
for logical_monitor in logical_monitors
|
||||||
|
if logical_monitor.position.x is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
dx = min_x
|
dx = min_x
|
||||||
@ -632,12 +639,16 @@ def align_horizontally(logical_monitors: list[LogicalMonitor]):
|
|||||||
|
|
||||||
for logical_monitor in logical_monitors:
|
for logical_monitor in logical_monitors:
|
||||||
x, y = logical_monitor.position
|
x, y = logical_monitor.position
|
||||||
logical_monitor.position = (x - dx, y)
|
logical_monitor.position = Position(
|
||||||
|
x - dx if x is not None else None, y
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def align_vertically(logical_monitors: list[LogicalMonitor]):
|
def align_vertically(logical_monitors: list[LogicalMonitor]):
|
||||||
min_y = min(
|
min_y = min(
|
||||||
logical_monitor.position[1] for logical_monitor in logical_monitors
|
logical_monitor.position.y
|
||||||
|
for logical_monitor in logical_monitors
|
||||||
|
if logical_monitor.position.y is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
dy = min_y
|
dy = min_y
|
||||||
@ -646,7 +657,9 @@ def align_vertically(logical_monitors: list[LogicalMonitor]):
|
|||||||
|
|
||||||
for logical_monitor in logical_monitors:
|
for logical_monitor in logical_monitors:
|
||||||
x, y = logical_monitor.position
|
x, y = logical_monitor.position
|
||||||
logical_monitor.position = (x, y - dy)
|
logical_monitor.position = Position(
|
||||||
|
x, y - dy if y is not None else None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def calculate_positions(
|
def calculate_positions(
|
||||||
@ -1324,7 +1337,7 @@ if __name__ == "__main__":
|
|||||||
choices=[str(layout_mode) for layout_mode in list(LayoutMode)],
|
choices=[str(layout_mode) for layout_mode in list(LayoutMode)],
|
||||||
type=str,
|
type=str,
|
||||||
action=AppendToGlobal,
|
action=AppendToGlobal,
|
||||||
).completer = LayoutModeCompleter()
|
).completer = LayoutModeCompleter() # type: ignore[attr-defined]
|
||||||
set_parser.add_argument(
|
set_parser.add_argument(
|
||||||
"-L",
|
"-L",
|
||||||
"--logical-monitor",
|
"--logical-monitor",
|
||||||
@ -1346,7 +1359,7 @@ if __name__ == "__main__":
|
|||||||
action=SubGroupAction,
|
action=SubGroupAction,
|
||||||
nargs=1,
|
nargs=1,
|
||||||
help="Configure monitor",
|
help="Configure monitor",
|
||||||
).completer = MonitorCompleter()
|
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||||
monitor_parser = set_parser.add_argument_group(
|
monitor_parser = set_parser.add_argument_group(
|
||||||
"monitor",
|
"monitor",
|
||||||
"Monitor options (pass after --monitor)",
|
"Monitor options (pass after --monitor)",
|
||||||
@ -1358,7 +1371,7 @@ if __name__ == "__main__":
|
|||||||
action=AppendToSubGroup,
|
action=AppendToSubGroup,
|
||||||
help="Monitor mode",
|
help="Monitor mode",
|
||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorModeCompleter()
|
).completer = MonitorModeCompleter() # type: ignore[attr-defined]
|
||||||
monitor_parser.add_argument(
|
monitor_parser.add_argument(
|
||||||
"--color-mode",
|
"--color-mode",
|
||||||
"-c",
|
"-c",
|
||||||
@ -1366,7 +1379,7 @@ if __name__ == "__main__":
|
|||||||
help="Color mode",
|
help="Color mode",
|
||||||
choices=[str(color_mode) for color_mode in list(ColorMode)],
|
choices=[str(color_mode) for color_mode in list(ColorMode)],
|
||||||
type=str,
|
type=str,
|
||||||
).completer = ColorModeCompleter()
|
).completer = ColorModeCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--primary",
|
"--primary",
|
||||||
"-p",
|
"-p",
|
||||||
@ -1382,7 +1395,7 @@ if __name__ == "__main__":
|
|||||||
action=AppendToGroup,
|
action=AppendToGroup,
|
||||||
help="Logical monitor scale",
|
help="Logical monitor scale",
|
||||||
type=float,
|
type=float,
|
||||||
).completer = ScaleCompleter()
|
).completer = ScaleCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--transform",
|
"--transform",
|
||||||
"-t",
|
"-t",
|
||||||
@ -1390,7 +1403,7 @@ if __name__ == "__main__":
|
|||||||
help="Apply viewport transform",
|
help="Apply viewport transform",
|
||||||
choices=[str(transform) for transform in list(Transform)],
|
choices=[str(transform) for transform in list(Transform)],
|
||||||
type=str,
|
type=str,
|
||||||
).completer = TransformCompleter()
|
).completer = TransformCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--x",
|
"--x",
|
||||||
"-x",
|
"-x",
|
||||||
@ -1411,28 +1424,28 @@ if __name__ == "__main__":
|
|||||||
metavar="CONNECTOR",
|
metavar="CONNECTOR",
|
||||||
help="Place right of other monitor",
|
help="Place right of other monitor",
|
||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorCompleter()
|
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--left-of",
|
"--left-of",
|
||||||
action=AppendToGroup,
|
action=AppendToGroup,
|
||||||
metavar="CONNECTOR",
|
metavar="CONNECTOR",
|
||||||
help="Place left of other monitor",
|
help="Place left of other monitor",
|
||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorCompleter()
|
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--above",
|
"--above",
|
||||||
action=AppendToGroup,
|
action=AppendToGroup,
|
||||||
metavar="CONNECTOR",
|
metavar="CONNECTOR",
|
||||||
help="Place above other monitor",
|
help="Place above other monitor",
|
||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorCompleter()
|
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||||
logical_monitor_parser.add_argument(
|
logical_monitor_parser.add_argument(
|
||||||
"--below",
|
"--below",
|
||||||
action=AppendToGroup,
|
action=AppendToGroup,
|
||||||
metavar="CONNECTOR",
|
metavar="CONNECTOR",
|
||||||
help="Place below other monitor",
|
help="Place below other monitor",
|
||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorCompleter()
|
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||||
|
|
||||||
for action in [
|
for action in [
|
||||||
GroupAction,
|
GroupAction,
|
||||||
@ -1442,7 +1455,7 @@ if __name__ == "__main__":
|
|||||||
AppendToGlobal,
|
AppendToGlobal,
|
||||||
]:
|
]:
|
||||||
argcomplete.safe_actions.add(action)
|
argcomplete.safe_actions.add(action)
|
||||||
argcomplete.autocomplete(parser, default_completer=SuppressCompleter)
|
argcomplete.autocomplete(parser, default_completer=SuppressCompleter) # type: ignore[arg-type]
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user