Skip to content

Commit 0250083

Browse files
committed
fix(Backlight): add support for 'brightnessctl'
1 parent 941a7be commit 0250083

File tree

1 file changed

+244
-77
lines changed

1 file changed

+244
-77
lines changed

core/global/display_manager.gd

Lines changed: 244 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,16 @@ enum VALUE {
1010
RELATIVE,
1111
}
1212

13-
enum BRIGHTNESS_PROVIDER {
14-
NONE,
15-
STEAMOS,
16-
}
17-
1813
signal brightness_changed
1914

20-
const backlight_path := "/sys/class/backlight"
21-
const steamos_write_bin := "/usr/bin/steamos-polkit-helpers/steamos-priv-write"
22-
2315
var logger := Log.get_logger("DisplayManager", Log.LEVEL.INFO)
16+
var brightness_provider := _get_backlight_provider()
2417
var backlights := get_backlight_paths()
25-
var brightness_provider := _get_brightness_provider()
2618

2719

2820
## Returns true if OpenGamepadUI has access to adjust brightness
2921
func supports_brightness() -> bool:
30-
brightness_provider = _get_brightness_provider()
31-
if brightness_provider == BRIGHTNESS_PROVIDER.NONE:
22+
if brightness_provider == null:
3223
logger.debug("No brightness setter found")
3324
return false
3425
backlights = get_backlight_paths()
@@ -40,97 +31,273 @@ func supports_brightness() -> bool:
4031

4132
## Sets the brightness on all discovered backlights to the given value as a
4233
## percentage (e.g. 1.0 is 100% brightness)
43-
func set_brightness(value: float, type: VALUE = VALUE.ABSOLUTE) -> int:
34+
func set_brightness(value: float, type: VALUE = VALUE.ABSOLUTE, backlight: String = "") -> int:
4435
if not supports_brightness():
4536
logger.debug("Failed to set brightness, no providers found")
4637
return FAILED
47-
value = minf(value, 1.0)
48-
value = maxf(value, 0.0)
49-
backlights = get_backlight_paths()
50-
51-
# Set the brightness for all backlights
52-
for backlight_path in backlights:
53-
# Calculate the value based on whether this is an absolute or relative change
54-
var abs_value := value
55-
if type == VALUE.RELATIVE:
56-
abs_value = get_brightness(backlight_path) + value
57-
abs_value = minf(abs_value, 1.0)
58-
abs_value = maxf(abs_value, 0.0)
59-
var real_value := int(abs_value * get_max_brightness_value(backlight_path))
60-
61-
# Use the preferred method of setting brightness
62-
var brightness_file := "/".join([backlight_path, "brightness"])
63-
logger.debug("Setting brightness on " + brightness_file + " to " + str(real_value))
64-
if brightness_provider == BRIGHTNESS_PROVIDER.STEAMOS:
65-
if _steamos_priv_write(brightness_file, real_value) != OK:
66-
return FAILED
67-
continue
68-
69-
return FAILED
70-
38+
39+
var err := brightness_provider.set_brightness(value, type, backlight)
40+
if err != OK:
41+
return err
7142
brightness_changed.emit()
72-
73-
return OK
43+
44+
return err
7445

7546

7647
## Returns the current brightness level for the given backlight as a percent
7748
func get_brightness(backlight_path: String) -> float:
78-
var cur_brightness := get_brightness_value(backlight_path)
79-
var max_brightness := get_max_brightness_value(backlight_path)
80-
if cur_brightness == -1 or max_brightness == -1:
81-
return -1
82-
return float(cur_brightness) / max_brightness
49+
if brightness_provider == null:
50+
return -1.0
51+
return brightness_provider.get_brightness(backlight_path)
8352

8453

8554
## Returns the current brightness value for the given backlight
8655
func get_brightness_value(backlight_path: String) -> int:
87-
var brightness_file := "/".join([backlight_path, "brightness"])
88-
var output := []
89-
var code := OS.execute("cat", [brightness_file], output)
90-
if code != OK:
91-
logger.debug("Unable to get current brightness: " + output[0])
56+
if brightness_provider == null:
9257
return -1
93-
var value := (output[0] as String).strip_edges()
94-
if value.is_valid_int():
95-
return value.to_int()
96-
logger.debug("Brightness is not a valid number: " + value)
97-
return -1
58+
return brightness_provider.get_brightness_value(backlight_path)
9859

9960

10061
## Returns the maximum brightness for the given backlight
10162
func get_max_brightness_value(backlight_path: String) -> int:
102-
var max_brightness_file := "/".join([backlight_path, "max_brightness"])
103-
var output := []
104-
var code := OS.execute("cat", [max_brightness_file], output)
105-
if code != OK:
106-
logger.debug("Unable to get max brightness: " + output[0])
63+
if brightness_provider == null:
10764
return -1
108-
var value := (output[0] as String).strip_edges()
109-
if value.is_valid_int():
110-
return value.to_int()
111-
logger.debug("Max brightness is not a valid number: " + value)
112-
return -1
65+
return brightness_provider.get_max_brightness_value(backlight_path)
11366

11467

11568
## Returns a list of all detected backlight devices
11669
func get_backlight_paths() -> PackedStringArray:
117-
var backlights := PackedStringArray()
118-
var backlight_dir := DirAccess.open(backlight_path)
119-
var devices := backlight_dir.get_directories()
120-
for device in devices:
121-
backlights.append("/".join([backlight_path, device]))
122-
logger.debug("Found backlights: " + str(backlights))
123-
return backlights
70+
if brightness_provider == null:
71+
return PackedStringArray()
72+
return brightness_provider.get_backlights()
12473

12574

126-
func _get_brightness_provider() -> BRIGHTNESS_PROVIDER:
127-
if FileAccess.file_exists(steamos_write_bin):
75+
func _get_backlight_provider() -> BacklightProvider:
76+
if FileAccess.file_exists("/usr/bin/steamos-polkit-helpers/steamos-priv-write"):
12877
logger.debug("Using SteamOS backlight writer")
129-
return BRIGHTNESS_PROVIDER.STEAMOS
78+
return SteamOsBacklight.new()
79+
if OS.execute("which", ["brightnessctl"]) == OK:
80+
logger.debug("Using brightnessctl backlight provider")
81+
return BrightnessctlBacklight.new()
13082
logger.debug("No backlight writer found")
131-
return BRIGHTNESS_PROVIDER.NONE
83+
return null
84+
85+
86+
## Interface for controlling backlights (e.g. screen brightness)
87+
class BacklightProvider:
88+
## Returns all available backlights
89+
func get_backlights() -> PackedStringArray:
90+
return PackedStringArray()
91+
92+
## Returns the maximum raw brightness value of the given backlight. If
93+
## No backlight is passed, then this should return the value for the "main"
94+
## display. Returns -1 if there is an error fetching the value.
95+
func get_max_brightness_value(_backlight: String = "") -> int:
96+
return -1
97+
98+
## Returns the current raw brightness value of the given backlight. If no
99+
## backlight is passed, then this should return the value for the "main"
100+
## display. Returns -1 if there is an error fetching the value.
101+
func get_brightness_value(_backlight: String = "") -> int:
102+
return -1
103+
104+
## Returns the current brightness level for the given backlight as a percent.
105+
## Returns -1 if there is an error fetching the value
106+
func get_brightness(_backlight: String = "") -> float:
107+
return -1.0
108+
109+
## Sets the brightness for the given backlight to the given value as a
110+
## percentage (e.g. 1.0 is 100% brightness). If no backlight is specified,
111+
## this should set the value on _all_ discovered backlights. Returns OK
112+
## if set successfully.
113+
func set_brightness(_value: float, _type: VALUE = VALUE.ABSOLUTE, _backlight: String = "") -> int:
114+
return ERR_METHOD_NOT_FOUND
115+
116+
117+
## SteamOS implementation of backlight control
118+
class SteamOsBacklight extends BacklightProvider:
119+
const backlight_path_base := "/sys/class/backlight"
120+
const steamos_write_bin := "/usr/bin/steamos-polkit-helpers/steamos-priv-write"
121+
var logger := Log.get_logger("SteamOsBacklight", Log.LEVEL.INFO)
122+
123+
func get_backlights() -> PackedStringArray:
124+
var backlights := PackedStringArray()
125+
var backlight_dir := DirAccess.open(backlight_path_base)
126+
var devices := backlight_dir.get_directories()
127+
for device in devices:
128+
backlights.append("/".join([backlight_path_base, device]))
129+
self.logger.debug("Found backlights: " + str(backlights))
130+
return backlights
131+
132+
func set_brightness(value: float, type: VALUE = VALUE.ABSOLUTE, backlight: String = "") -> int:
133+
value = minf(value, 1.0)
134+
value = maxf(value, 0.0)
135+
var backlights := PackedStringArray()
136+
if backlight.is_empty():
137+
backlights = self.get_backlights()
138+
else:
139+
backlights.push_back(backlight)
140+
141+
# Set the brightness for all backlights
142+
for backlight_path in backlights:
143+
# Calculate the value based on whether this is an absolute or relative change
144+
var abs_value := value
145+
if type == VALUE.RELATIVE:
146+
abs_value = self.get_brightness(backlight_path) + value
147+
abs_value = minf(abs_value, 1.0)
148+
abs_value = maxf(abs_value, 0.0)
149+
var real_value := int(abs_value * self.get_max_brightness_value(backlight_path))
150+
151+
# Use the preferred method of setting brightness
152+
var brightness_file := "/".join([backlight_path, "brightness"])
153+
self.logger.debug("Setting brightness on " + brightness_file + " to " + str(real_value))
154+
if self._steamos_priv_write(brightness_file, real_value) != OK:
155+
return FAILED
156+
157+
return OK
158+
159+
func get_brightness(backlight_path: String = "") -> float:
160+
var cur_brightness := self.get_brightness_value(backlight_path)
161+
var max_brightness := self.get_max_brightness_value(backlight_path)
162+
if cur_brightness == -1 or max_brightness == -1:
163+
return -1
164+
return float(cur_brightness) / max_brightness
165+
166+
func get_brightness_value(backlight_path: String = "") -> int:
167+
var brightness_file := "/".join([backlight_path, "brightness"])
168+
var output := []
169+
var code := OS.execute("cat", [brightness_file], output)
170+
if code != OK:
171+
logger.debug("Unable to get current brightness: " + output[0])
172+
return -1
173+
var value := (output[0] as String).strip_edges()
174+
if value.is_valid_int():
175+
return value.to_int()
176+
self.logger.debug("Brightness is not a valid number: " + value)
177+
return -1
178+
179+
func get_max_brightness_value(backlight_path: String = "") -> int:
180+
var max_brightness_file := "/".join([backlight_path, "max_brightness"])
181+
var output := []
182+
var code := OS.execute("cat", [max_brightness_file], output)
183+
if code != OK:
184+
self.logger.debug("Unable to get max brightness: " + output[0])
185+
return -1
186+
var value := (output[0] as String).strip_edges()
187+
if value.is_valid_int():
188+
return value.to_int()
189+
self.logger.debug("Max brightness is not a valid number: " + value)
190+
return -1
191+
192+
## Write a value using steamos polkit helper
193+
func _steamos_priv_write(path: String, value: int) -> int:
194+
return OS.execute(steamos_write_bin, [path, str(value)])
195+
196+
197+
## Brightnessctl implementation of backlight control
198+
class BrightnessctlBacklight extends BacklightProvider:
199+
var logger := Log.get_logger("BrightnessctlBacklight", Log.LEVEL.INFO)
200+
201+
func _exec(args: Array[String]) -> Command:
202+
var cmd := Command.create("brightnessctl", args)
203+
cmd.execute_blocking()
204+
return cmd
205+
206+
func _get_info(backlight: String = "") -> PackedStringArray:
207+
var args: Array[String] = ["--machine", "--class", "backlight", "info"]
208+
if not backlight.is_empty():
209+
args.push_front(backlight)
210+
args.push_front("--device")
211+
var cmd := _exec(args)
212+
if cmd.code != OK:
213+
return PackedStringArray()
214+
215+
var lines := cmd.stdout.split("\n", false)
216+
if lines.is_empty():
217+
return PackedStringArray()
218+
219+
# Example Output: amdgpu_bl1,backlight,128,50%,255
220+
var parts := lines[0].split(",", false)
221+
return parts
222+
223+
func get_backlights() -> PackedStringArray:
224+
# brightnessctl -l -c backlight -m
225+
# Output: amdgpu_bl1,backlight,128,50%,255
226+
var backlights := PackedStringArray()
227+
var cmd := self._exec(["--list", "--class", "backlight", "--machine"])
228+
if cmd.code != OK:
229+
return backlights
230+
231+
var lines := cmd.stdout.split("\n", false)
232+
for line in lines:
233+
var parts := line.split(",")
234+
if parts.is_empty():
235+
continue
236+
backlights.push_back(parts[0])
237+
238+
self.logger.debug("Found backlights: " + str(backlights))
239+
return backlights
240+
241+
func set_brightness(value: float, type: VALUE = VALUE.ABSOLUTE, backlight: String = "") -> int:
242+
value = minf(value, 1.0)
243+
value = maxf(value, -1.0)
244+
value = value * 100.0
245+
var backlights := PackedStringArray()
246+
if backlight.is_empty():
247+
backlights = self.get_backlights()
248+
else:
249+
backlights.push_back(backlight)
250+
251+
# Set the brightness for all backlights
252+
for backlight_name in backlights:
253+
var value_str := str(value) + "%"
254+
if type == VALUE.RELATIVE:
255+
if value > 0.0:
256+
value_str = "+" + value_str
257+
else:
258+
value_str = value_str + "-"
259+
260+
self.logger.debug("Setting brightness on " + backlight_name + " to " + value_str)
261+
var cmd := _exec(["--device", backlight, "set", value_str])
262+
if cmd.code != OK:
263+
return FAILED
264+
265+
return OK
266+
267+
func get_brightness(backlight: String = "") -> float:
268+
var info := self._get_info(backlight)
269+
if info.size() < 4:
270+
return -1.0
271+
272+
# Example Output: amdgpu_bl1,backlight,128,50%,255
273+
var cur_brightness := info[3]
274+
cur_brightness = cur_brightness.replace("%", "")
275+
if not cur_brightness.is_valid_int():
276+
return -1.0
277+
278+
return cur_brightness.to_float() / 100.0
279+
280+
281+
func get_brightness_value(backlight: String = "") -> int:
282+
var info := self._get_info(backlight)
283+
if info.size() < 4:
284+
return -1
285+
286+
# Example Output: amdgpu_bl1,backlight,128,50%,255
287+
var cur_brightness := info[2]
288+
if not cur_brightness.is_valid_int():
289+
return -1
290+
291+
return cur_brightness.to_int()
292+
293+
func get_max_brightness_value(backlight: String = "") -> int:
294+
var info := self._get_info(backlight)
295+
if info.size() < 5:
296+
return -1
132297

298+
# Example Output: amdgpu_bl1,backlight,128,50%,255
299+
var max_brightness := info[4]
300+
if not max_brightness.is_valid_int():
301+
return -1
133302

134-
## Write a value using steamos polkit helper
135-
func _steamos_priv_write(path: String, value: int) -> int:
136-
return OS.execute(steamos_write_bin, [path, str(value)])
303+
return max_brightness.to_int()

0 commit comments

Comments
 (0)