gdctl: Support showing and setting output luminance
`gdctl show` now prints "monitor preferences", which currently consists of only the luminance setting. `gdctl prefs` is introduced, where one can run e.g. `gdctl prefs --monitor DP-1 --luminance 80.0` to set the output luminance of the monitor connected to DP-1 to 80%. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4271>
This commit is contained in:
parent
be6af00d6b
commit
de2d19e882
@ -31,6 +31,10 @@ COMMANDS
|
||||
|
||||
Set a new display configuration
|
||||
|
||||
``pref``
|
||||
|
||||
Set display related preferences.
|
||||
|
||||
SHOW OPTIONS
|
||||
------------
|
||||
``--help``, ``-h``
|
||||
@ -143,6 +147,23 @@ MONITOR OPTIONS
|
||||
Set the color mode of the monitor. Available color modes are ``default`` and
|
||||
``bt2100``.
|
||||
|
||||
PREFS OPTIONS
|
||||
-------------
|
||||
|
||||
``--monitor CONNECTOR``, ``-M CONNECTOR``
|
||||
|
||||
Change monitor preferences. See MONITOR PREFS OPTIONS.
|
||||
|
||||
MONITOR PREFS OPTIONS
|
||||
---------------------
|
||||
|
||||
``--luminance LUMINANCE``, ``-l LUMINANCE``
|
||||
|
||||
Set the luminance of the monitor for the current color mode.
|
||||
|
||||
``--reset-luminance``
|
||||
|
||||
Reset the luminance of the monitor for the current color mode to its default.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
@ -3,14 +3,20 @@ Monitors:
|
||||
│ ├──Vendor: MetaProduct's Inc.
|
||||
│ ├──Product: MetaMonitor
|
||||
│ ├──Serial: 0x1234560
|
||||
│ └──Current mode
|
||||
│ └──3840x2160@60.000
|
||||
│ ├──Current mode
|
||||
│ │ └──3840x2160@60.000
|
||||
│ └──Preferences:
|
||||
│ └──Luminances:
|
||||
│ └──default ⇒ 100.0 (default) (current)
|
||||
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
||||
├──Vendor: MetaProduct's Inc.
|
||||
├──Product: MetaMonitor
|
||||
├──Serial: 0x1234561
|
||||
└──Current mode
|
||||
└──2560x1440@60.000
|
||||
├──Current mode
|
||||
│ └──2560x1440@60.000
|
||||
└──Preferences:
|
||||
└──Luminances:
|
||||
└──default ⇒ 100.0 (default) (current)
|
||||
|
||||
Logical monitors:
|
||||
├──Logical monitor #1
|
||||
|
@ -8,6 +8,9 @@ Monitors:
|
||||
│ ├──3840x2160@30.000
|
||||
│ ├──2560x1440@60.000
|
||||
│ └──1440x900@60.000
|
||||
│ └──Preferences:
|
||||
│ └──Luminances:
|
||||
│ └──default ⇒ 100.0 (default) (current)
|
||||
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
||||
├──Vendor: MetaProduct's Inc.
|
||||
├──Product: MetaMonitor
|
||||
@ -17,6 +20,9 @@ Monitors:
|
||||
├──1440x900@60.000
|
||||
├──1366x768@60.000
|
||||
└──800x600@60.000
|
||||
└──Preferences:
|
||||
└──Luminances:
|
||||
└──default ⇒ 100.0 (default) (current)
|
||||
|
||||
Logical monitors:
|
||||
├──Logical monitor #1
|
||||
|
@ -12,6 +12,9 @@ Monitors:
|
||||
│ │ └──Properties: (2)
|
||||
│ │ ├──is-current ⇒ yes
|
||||
│ │ └──is-preferred ⇒ yes
|
||||
│ ├──Preferences:
|
||||
│ │ └──Luminances:
|
||||
│ │ └──default ⇒ 100.0 (default) (current)
|
||||
│ └──Properties: (5)
|
||||
│ ├──is-builtin ⇒ no
|
||||
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
||||
@ -31,6 +34,9 @@ Monitors:
|
||||
│ └──Properties: (2)
|
||||
│ ├──is-current ⇒ yes
|
||||
│ └──is-preferred ⇒ yes
|
||||
├──Preferences:
|
||||
│ └──Luminances:
|
||||
│ └──default ⇒ 100.0 (default) (current)
|
||||
└──Properties: (5)
|
||||
├──is-builtin ⇒ no
|
||||
├──display-name ⇒ MetaProduct's Inc. 13"
|
||||
|
@ -30,6 +30,9 @@ Monitors:
|
||||
│ │ ├──Preferred scale: 1.0
|
||||
│ │ ├──Supported scales: [1.0, 1.25, 1.5, 1.7475727796554565]
|
||||
│ │ └──Properties: (0)
|
||||
│ ├──Preferences:
|
||||
│ │ └──Luminances:
|
||||
│ │ └──default ⇒ 100.0 (default) (current)
|
||||
│ └──Properties: (5)
|
||||
│ ├──is-builtin ⇒ no
|
||||
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
||||
@ -67,6 +70,9 @@ Monitors:
|
||||
│ ├──Preferred scale: 1.0
|
||||
│ ├──Supported scales: [1.0]
|
||||
│ └──Properties: (0)
|
||||
├──Preferences:
|
||||
│ └──Luminances:
|
||||
│ └──default ⇒ 100.0 (default) (current)
|
||||
└──Properties: (5)
|
||||
├──is-builtin ⇒ no
|
||||
├──display-name ⇒ MetaProduct's Inc. 13"
|
||||
|
178
tools/gdctl
178
tools/gdctl
@ -197,6 +197,41 @@ def print_properties(*, level, lines, properties):
|
||||
)
|
||||
|
||||
|
||||
def print_monitor_prefs(
|
||||
display_config, monitor, level: int, lines: list[int], is_last: bool
|
||||
):
|
||||
print_data(
|
||||
level=level,
|
||||
is_last=is_last,
|
||||
lines=lines,
|
||||
data="Preferences:",
|
||||
)
|
||||
|
||||
print_data(
|
||||
level=level + 1,
|
||||
is_last=True,
|
||||
lines=lines,
|
||||
data="Luminances:",
|
||||
)
|
||||
|
||||
for color_mode in monitor.supported_color_modes:
|
||||
(output_luminance, is_unset) = display_config.get_luminance(
|
||||
monitor, color_mode
|
||||
)
|
||||
is_last = color_mode == monitor.supported_color_modes[-1]
|
||||
|
||||
is_default_string = " (default)" if is_unset else ""
|
||||
is_current_string = (
|
||||
" (current)" if monitor.color_mode == color_mode else ""
|
||||
)
|
||||
print_data(
|
||||
level=level + 2,
|
||||
is_last=is_last,
|
||||
lines=lines,
|
||||
data=f"{color_mode} ⇒ {output_luminance}{is_default_string}{is_current_string}",
|
||||
)
|
||||
|
||||
|
||||
def strip_dbus_error_prefix(message):
|
||||
if message.startswith("GDBus.Error"):
|
||||
return message.partition(" ")[2]
|
||||
@ -290,6 +325,50 @@ class DisplayConfig:
|
||||
cancellable=None,
|
||||
)
|
||||
|
||||
def get_luminance(self, monitor, color_mode) -> tuple[float, bool]:
|
||||
variant = self._proxy.get_cached_property("Luminance")
|
||||
|
||||
luminance_entry = next(
|
||||
entry
|
||||
for entry in variant
|
||||
if entry["connector"] == monitor.connector
|
||||
and ColorMode(entry["color-mode"]) == color_mode
|
||||
)
|
||||
output_luminance = luminance_entry["luminance"]
|
||||
is_unset = luminance_entry["is-unset"]
|
||||
|
||||
return (output_luminance, is_unset)
|
||||
|
||||
def set_luminance(self, monitor, color_mode, luminance):
|
||||
parameters = GLib.Variant(
|
||||
"(sud)",
|
||||
(
|
||||
monitor.connector,
|
||||
color_mode.value,
|
||||
luminance,
|
||||
),
|
||||
)
|
||||
self._proxy.call_sync(
|
||||
method_name="SetLuminance",
|
||||
parameters=parameters,
|
||||
flags=Gio.DBusCallFlags.NO_AUTO_START,
|
||||
timeout_msec=-1,
|
||||
cancellable=None,
|
||||
)
|
||||
|
||||
def reset_luminance(self, monitor, color_mode):
|
||||
parameters = GLib.Variant(
|
||||
"(su)",
|
||||
(monitor.connector, color_mode.value),
|
||||
)
|
||||
self._proxy.call_sync(
|
||||
method_name="ResetLuminance",
|
||||
parameters=parameters,
|
||||
flags=Gio.DBusCallFlags.NO_AUTO_START,
|
||||
timeout_msec=-1,
|
||||
cancellable=None,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MonitorMode:
|
||||
@ -324,6 +403,7 @@ class Monitor:
|
||||
current_mode: MonitorMode | None
|
||||
preferred_mode: MonitorMode | None
|
||||
color_mode: ColorMode | None
|
||||
supported_color_modes: list[ColorMode]
|
||||
|
||||
@classmethod
|
||||
def from_variant(cls, variant):
|
||||
@ -349,6 +429,7 @@ class Monitor:
|
||||
|
||||
display_name = properties.get("display-name", None)
|
||||
color_mode = properties.get("color-mode", None)
|
||||
supported_color_modes = properties.get("supported-color-modes")
|
||||
|
||||
return cls(
|
||||
connector=connector,
|
||||
@ -361,6 +442,7 @@ class Monitor:
|
||||
preferred_mode=preferred_mode,
|
||||
display_name=display_name,
|
||||
color_mode=color_mode,
|
||||
supported_color_modes=supported_color_modes,
|
||||
)
|
||||
|
||||
|
||||
@ -915,6 +997,7 @@ class MonitorsState:
|
||||
def __init__(self, display_config):
|
||||
current_state = display_config.get_current_state()
|
||||
|
||||
self.display_config = display_config
|
||||
self.server_serial = current_state[0]
|
||||
self.properties = translate_properties(current_state[3])
|
||||
self.supports_changing_layout_mode = self.properties.get(
|
||||
@ -1054,12 +1137,20 @@ class MonitorsState:
|
||||
if mode:
|
||||
print_data(
|
||||
level=1,
|
||||
is_last=not show_properties,
|
||||
is_last=False,
|
||||
lines=lines,
|
||||
data=f"{mode_type} mode",
|
||||
)
|
||||
self.print_mode(mode, True, show_properties, lines)
|
||||
|
||||
print_monitor_prefs(
|
||||
self.display_config,
|
||||
monitor,
|
||||
level=1,
|
||||
lines=lines,
|
||||
is_last=not show_properties,
|
||||
)
|
||||
|
||||
if show_properties:
|
||||
print_properties(level=1, lines=lines, properties=properties)
|
||||
|
||||
@ -1200,7 +1291,14 @@ class Config:
|
||||
|
||||
class GroupAction(argparse.Action):
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
namespace._current_group = {}
|
||||
if len(values) == 1:
|
||||
(value,) = values
|
||||
namespace._current_group = {
|
||||
"key": value,
|
||||
}
|
||||
else:
|
||||
namespace._current_group = {}
|
||||
|
||||
groups = namespace.__dict__.setdefault(self.dest, [])
|
||||
groups.append(namespace._current_group)
|
||||
|
||||
@ -1509,6 +1607,40 @@ if __name__ == "__main__":
|
||||
type=str,
|
||||
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||
|
||||
prefs_parser = subparser.add_parser(
|
||||
"prefs",
|
||||
help="Set display preferences",
|
||||
)
|
||||
prefs_parser.add_argument(
|
||||
"-M",
|
||||
"--monitor",
|
||||
dest="monitors",
|
||||
metavar="CONNECTOR",
|
||||
action=GroupAction,
|
||||
nargs=1,
|
||||
default=[],
|
||||
help="Change monitor preferences",
|
||||
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
||||
monitor_prefs_parser = prefs_parser.add_argument_group(
|
||||
"monitor",
|
||||
"Monitor preferences (pass after --monitor)",
|
||||
argument_default=argparse.SUPPRESS,
|
||||
)
|
||||
monitor_prefs_parser.add_argument(
|
||||
"-l",
|
||||
"--luminance",
|
||||
action=AppendToGroup,
|
||||
type=float,
|
||||
nargs=1,
|
||||
)
|
||||
monitor_prefs_parser.add_argument(
|
||||
"--reset-luminance",
|
||||
action=AppendToGroup,
|
||||
type=bool,
|
||||
const=True,
|
||||
nargs=0,
|
||||
)
|
||||
|
||||
if argcomplete:
|
||||
for action in [
|
||||
GroupAction,
|
||||
@ -1585,3 +1717,45 @@ if __name__ == "__main__":
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
case "prefs":
|
||||
try:
|
||||
display_config = DisplayConfig()
|
||||
monitors_state = MonitorsState(display_config)
|
||||
except GLib.Error as e:
|
||||
if e.domain == GLib.quark_to_string(Gio.DBusError.quark()):
|
||||
error_message = strip_dbus_error_prefix(e.message)
|
||||
print(
|
||||
f"Failed to retrieve current state: {error_message}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
for monitor_prefs in args.monitors:
|
||||
connector = monitor_prefs["key"]
|
||||
|
||||
if (
|
||||
"luminance" in monitor_prefs
|
||||
and "reset_luminance" in monitor_prefs
|
||||
):
|
||||
print(
|
||||
"Cannot both set and reset luminance",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
if connector not in monitors_state.monitors:
|
||||
print(
|
||||
f"Monitor with connector {connector} not found",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
monitor = monitors_state.monitors[connector]
|
||||
|
||||
if "luminance" in monitor_prefs:
|
||||
(luminance,) = monitor_prefs["luminance"]
|
||||
display_config.set_luminance(
|
||||
monitor, monitor.color_mode, luminance
|
||||
)
|
||||
elif "reset_luminance" in monitor_prefs:
|
||||
display_config.reset_luminance(monitor, monitor.color_mode)
|
||||
|
Loading…
x
Reference in New Issue
Block a user