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
|
Set a new display configuration
|
||||||
|
|
||||||
|
``pref``
|
||||||
|
|
||||||
|
Set display related preferences.
|
||||||
|
|
||||||
SHOW OPTIONS
|
SHOW OPTIONS
|
||||||
------------
|
------------
|
||||||
``--help``, ``-h``
|
``--help``, ``-h``
|
||||||
@ -143,6 +147,23 @@ MONITOR OPTIONS
|
|||||||
Set the color mode of the monitor. Available color modes are ``default`` and
|
Set the color mode of the monitor. Available color modes are ``default`` and
|
||||||
``bt2100``.
|
``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
|
EXAMPLES
|
||||||
--------
|
--------
|
||||||
|
@ -3,14 +3,20 @@ Monitors:
|
|||||||
│ ├──Vendor: MetaProduct's Inc.
|
│ ├──Vendor: MetaProduct's Inc.
|
||||||
│ ├──Product: MetaMonitor
|
│ ├──Product: MetaMonitor
|
||||||
│ ├──Serial: 0x1234560
|
│ ├──Serial: 0x1234560
|
||||||
│ └──Current mode
|
│ ├──Current mode
|
||||||
│ └──3840x2160@60.000
|
│ │ └──3840x2160@60.000
|
||||||
|
│ └──Preferences:
|
||||||
|
│ └──Luminances:
|
||||||
|
│ └──default ⇒ 100.0 (default) (current)
|
||||||
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
||||||
├──Vendor: MetaProduct's Inc.
|
├──Vendor: MetaProduct's Inc.
|
||||||
├──Product: MetaMonitor
|
├──Product: MetaMonitor
|
||||||
├──Serial: 0x1234561
|
├──Serial: 0x1234561
|
||||||
└──Current mode
|
├──Current mode
|
||||||
└──2560x1440@60.000
|
│ └──2560x1440@60.000
|
||||||
|
└──Preferences:
|
||||||
|
└──Luminances:
|
||||||
|
└──default ⇒ 100.0 (default) (current)
|
||||||
|
|
||||||
Logical monitors:
|
Logical monitors:
|
||||||
├──Logical monitor #1
|
├──Logical monitor #1
|
||||||
|
@ -8,6 +8,9 @@ Monitors:
|
|||||||
│ ├──3840x2160@30.000
|
│ ├──3840x2160@30.000
|
||||||
│ ├──2560x1440@60.000
|
│ ├──2560x1440@60.000
|
||||||
│ └──1440x900@60.000
|
│ └──1440x900@60.000
|
||||||
|
│ └──Preferences:
|
||||||
|
│ └──Luminances:
|
||||||
|
│ └──default ⇒ 100.0 (default) (current)
|
||||||
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
└──Monitor DP-2 (MetaProduct's Inc. 13")
|
||||||
├──Vendor: MetaProduct's Inc.
|
├──Vendor: MetaProduct's Inc.
|
||||||
├──Product: MetaMonitor
|
├──Product: MetaMonitor
|
||||||
@ -17,6 +20,9 @@ Monitors:
|
|||||||
├──1440x900@60.000
|
├──1440x900@60.000
|
||||||
├──1366x768@60.000
|
├──1366x768@60.000
|
||||||
└──800x600@60.000
|
└──800x600@60.000
|
||||||
|
└──Preferences:
|
||||||
|
└──Luminances:
|
||||||
|
└──default ⇒ 100.0 (default) (current)
|
||||||
|
|
||||||
Logical monitors:
|
Logical monitors:
|
||||||
├──Logical monitor #1
|
├──Logical monitor #1
|
||||||
|
@ -12,6 +12,9 @@ Monitors:
|
|||||||
│ │ └──Properties: (2)
|
│ │ └──Properties: (2)
|
||||||
│ │ ├──is-current ⇒ yes
|
│ │ ├──is-current ⇒ yes
|
||||||
│ │ └──is-preferred ⇒ yes
|
│ │ └──is-preferred ⇒ yes
|
||||||
|
│ ├──Preferences:
|
||||||
|
│ │ └──Luminances:
|
||||||
|
│ │ └──default ⇒ 100.0 (default) (current)
|
||||||
│ └──Properties: (5)
|
│ └──Properties: (5)
|
||||||
│ ├──is-builtin ⇒ no
|
│ ├──is-builtin ⇒ no
|
||||||
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
||||||
@ -31,6 +34,9 @@ Monitors:
|
|||||||
│ └──Properties: (2)
|
│ └──Properties: (2)
|
||||||
│ ├──is-current ⇒ yes
|
│ ├──is-current ⇒ yes
|
||||||
│ └──is-preferred ⇒ yes
|
│ └──is-preferred ⇒ yes
|
||||||
|
├──Preferences:
|
||||||
|
│ └──Luminances:
|
||||||
|
│ └──default ⇒ 100.0 (default) (current)
|
||||||
└──Properties: (5)
|
└──Properties: (5)
|
||||||
├──is-builtin ⇒ no
|
├──is-builtin ⇒ no
|
||||||
├──display-name ⇒ MetaProduct's Inc. 13"
|
├──display-name ⇒ MetaProduct's Inc. 13"
|
||||||
|
@ -30,6 +30,9 @@ Monitors:
|
|||||||
│ │ ├──Preferred scale: 1.0
|
│ │ ├──Preferred scale: 1.0
|
||||||
│ │ ├──Supported scales: [1.0, 1.25, 1.5, 1.7475727796554565]
|
│ │ ├──Supported scales: [1.0, 1.25, 1.5, 1.7475727796554565]
|
||||||
│ │ └──Properties: (0)
|
│ │ └──Properties: (0)
|
||||||
|
│ ├──Preferences:
|
||||||
|
│ │ └──Luminances:
|
||||||
|
│ │ └──default ⇒ 100.0 (default) (current)
|
||||||
│ └──Properties: (5)
|
│ └──Properties: (5)
|
||||||
│ ├──is-builtin ⇒ no
|
│ ├──is-builtin ⇒ no
|
||||||
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
│ ├──display-name ⇒ MetaProduct's Inc. 14"
|
||||||
@ -67,6 +70,9 @@ Monitors:
|
|||||||
│ ├──Preferred scale: 1.0
|
│ ├──Preferred scale: 1.0
|
||||||
│ ├──Supported scales: [1.0]
|
│ ├──Supported scales: [1.0]
|
||||||
│ └──Properties: (0)
|
│ └──Properties: (0)
|
||||||
|
├──Preferences:
|
||||||
|
│ └──Luminances:
|
||||||
|
│ └──default ⇒ 100.0 (default) (current)
|
||||||
└──Properties: (5)
|
└──Properties: (5)
|
||||||
├──is-builtin ⇒ no
|
├──is-builtin ⇒ no
|
||||||
├──display-name ⇒ MetaProduct's Inc. 13"
|
├──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):
|
def strip_dbus_error_prefix(message):
|
||||||
if message.startswith("GDBus.Error"):
|
if message.startswith("GDBus.Error"):
|
||||||
return message.partition(" ")[2]
|
return message.partition(" ")[2]
|
||||||
@ -290,6 +325,50 @@ class DisplayConfig:
|
|||||||
cancellable=None,
|
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
|
@dataclass
|
||||||
class MonitorMode:
|
class MonitorMode:
|
||||||
@ -324,6 +403,7 @@ class Monitor:
|
|||||||
current_mode: MonitorMode | None
|
current_mode: MonitorMode | None
|
||||||
preferred_mode: MonitorMode | None
|
preferred_mode: MonitorMode | None
|
||||||
color_mode: ColorMode | None
|
color_mode: ColorMode | None
|
||||||
|
supported_color_modes: list[ColorMode]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_variant(cls, variant):
|
def from_variant(cls, variant):
|
||||||
@ -349,6 +429,7 @@ class Monitor:
|
|||||||
|
|
||||||
display_name = properties.get("display-name", None)
|
display_name = properties.get("display-name", None)
|
||||||
color_mode = properties.get("color-mode", None)
|
color_mode = properties.get("color-mode", None)
|
||||||
|
supported_color_modes = properties.get("supported-color-modes")
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
connector=connector,
|
connector=connector,
|
||||||
@ -361,6 +442,7 @@ class Monitor:
|
|||||||
preferred_mode=preferred_mode,
|
preferred_mode=preferred_mode,
|
||||||
display_name=display_name,
|
display_name=display_name,
|
||||||
color_mode=color_mode,
|
color_mode=color_mode,
|
||||||
|
supported_color_modes=supported_color_modes,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -915,6 +997,7 @@ class MonitorsState:
|
|||||||
def __init__(self, display_config):
|
def __init__(self, display_config):
|
||||||
current_state = display_config.get_current_state()
|
current_state = display_config.get_current_state()
|
||||||
|
|
||||||
|
self.display_config = display_config
|
||||||
self.server_serial = current_state[0]
|
self.server_serial = current_state[0]
|
||||||
self.properties = translate_properties(current_state[3])
|
self.properties = translate_properties(current_state[3])
|
||||||
self.supports_changing_layout_mode = self.properties.get(
|
self.supports_changing_layout_mode = self.properties.get(
|
||||||
@ -1054,12 +1137,20 @@ class MonitorsState:
|
|||||||
if mode:
|
if mode:
|
||||||
print_data(
|
print_data(
|
||||||
level=1,
|
level=1,
|
||||||
is_last=not show_properties,
|
is_last=False,
|
||||||
lines=lines,
|
lines=lines,
|
||||||
data=f"{mode_type} mode",
|
data=f"{mode_type} mode",
|
||||||
)
|
)
|
||||||
self.print_mode(mode, True, show_properties, lines)
|
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:
|
if show_properties:
|
||||||
print_properties(level=1, lines=lines, properties=properties)
|
print_properties(level=1, lines=lines, properties=properties)
|
||||||
|
|
||||||
@ -1200,7 +1291,14 @@ class Config:
|
|||||||
|
|
||||||
class GroupAction(argparse.Action):
|
class GroupAction(argparse.Action):
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
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 = namespace.__dict__.setdefault(self.dest, [])
|
||||||
groups.append(namespace._current_group)
|
groups.append(namespace._current_group)
|
||||||
|
|
||||||
@ -1509,6 +1607,40 @@ if __name__ == "__main__":
|
|||||||
type=str,
|
type=str,
|
||||||
).completer = MonitorCompleter() # type: ignore[attr-defined]
|
).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:
|
if argcomplete:
|
||||||
for action in [
|
for action in [
|
||||||
GroupAction,
|
GroupAction,
|
||||||
@ -1585,3 +1717,45 @@ if __name__ == "__main__":
|
|||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
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