|
| 1 | +/* |
| 2 | +* This file is part of budgie-desktop |
| 3 | +* |
| 4 | +* Copyright Budgie Desktop Developers |
| 5 | +* |
| 6 | +* This program is free software; you can redistribute it and/or modify |
| 7 | +* it under the terms of the GNU General Public License as published by |
| 8 | +* the Free Software Foundation; either version 2 of the License, or |
| 9 | +* (at your option) any later version. |
| 10 | +*/ |
| 11 | + |
| 12 | +/** |
| 13 | +* budgie-brightness-helper |
| 14 | +* |
| 15 | +* Simple command-line utility to adjust screen brightness |
| 16 | +* Designed to be called from keyboard shortcuts |
| 17 | +*/ |
| 18 | + |
| 19 | +namespace Budgie { |
| 20 | + /** |
| 21 | + * DBus interface for logind Session |
| 22 | + */ |
| 23 | + [DBus (name = "org.freedesktop.login1.Session")] |
| 24 | + interface LogindSession : GLib.Object { |
| 25 | + public abstract void SetBrightness(string subsystem, string name, uint32 brightness) throws DBusError, IOError; |
| 26 | + } |
| 27 | + |
| 28 | + public class BrightnessHelper : GLib.Application { |
| 29 | + private BrightnessUtil util; |
| 30 | + private LogindSession? logind_session = null; |
| 31 | + |
| 32 | + public BrightnessHelper() { |
| 33 | + Object( |
| 34 | + application_id: "org.buddiesofbudgie.BrightnessCLI", |
| 35 | + flags: ApplicationFlags.HANDLES_COMMAND_LINE |
| 36 | + ); |
| 37 | + |
| 38 | + // Add options to the application |
| 39 | + add_main_option("up", 'u', OptionFlags.NONE, OptionArg.NONE, |
| 40 | + "Increase brightness", null); |
| 41 | + add_main_option("down", 'd', OptionFlags.NONE, OptionArg.NONE, |
| 42 | + "Decrease brightness", null); |
| 43 | + add_main_option("set", 's', OptionFlags.NONE, OptionArg.INT, |
| 44 | + "Set brightness to PERCENT (0-100)", "PERCENT"); |
| 45 | + add_main_option("step", 't', OptionFlags.NONE, OptionArg.INT, |
| 46 | + "Step size for up/down (default: 5)", "PERCENT"); |
| 47 | + |
| 48 | + util = new BrightnessUtil(); |
| 49 | + } |
| 50 | + |
| 51 | + public override int command_line(ApplicationCommandLine cmd) { |
| 52 | + var options = cmd.get_options_dict(); |
| 53 | + |
| 54 | + // Initialize hardware |
| 55 | + if (!util.find_backlight_device()) { |
| 56 | + cmd.printerr("Failed to find backlight device\n"); |
| 57 | + return 1; |
| 58 | + } |
| 59 | + |
| 60 | + if (!setup_logind_session()) { |
| 61 | + cmd.printerr("Failed to connect to logind session\n"); |
| 62 | + return 1; |
| 63 | + } |
| 64 | + |
| 65 | + // Get option values |
| 66 | + bool opt_up = options.contains("up"); |
| 67 | + bool opt_down = options.contains("down"); |
| 68 | + bool has_set = options.contains("set"); |
| 69 | + int opt_set = has_set ? options.lookup_value("set", VariantType.INT32).get_int32() : -1; |
| 70 | + int opt_step = options.contains("step") ? |
| 71 | + options.lookup_value("step", VariantType.INT32).get_int32() : 5; |
| 72 | + |
| 73 | + // Validate step size |
| 74 | + if (opt_step < 1 || opt_step > 100) { |
| 75 | + cmd.printerr("Error: step must be between 1 and 100\n"); |
| 76 | + return 1; |
| 77 | + } |
| 78 | + |
| 79 | + // Process commands (mutually exclusive) |
| 80 | + int commands_given = 0; |
| 81 | + if (opt_up) commands_given++; |
| 82 | + if (opt_down) commands_given++; |
| 83 | + if (has_set) commands_given++; |
| 84 | + |
| 85 | + if (commands_given == 0) { |
| 86 | + cmd.printerr("Error: Must specify one of --up, --down, or --set\n"); |
| 87 | + cmd.printerr("Run with --help for usage information\n"); |
| 88 | + return 1; |
| 89 | + } |
| 90 | + |
| 91 | + if (commands_given > 1) { |
| 92 | + cmd.printerr("Error: Cannot specify multiple commands (--up, --down, --set) simultaneously\n"); |
| 93 | + return 1; |
| 94 | + } |
| 95 | + |
| 96 | + // Execute the requested command |
| 97 | + bool success = false; |
| 98 | + |
| 99 | + if (opt_up) { |
| 100 | + success = increase_brightness(opt_step); |
| 101 | + } else if (opt_down) { |
| 102 | + success = decrease_brightness(opt_step); |
| 103 | + } else if (has_set) { |
| 104 | + if (opt_set < 0 || opt_set > 100) { |
| 105 | + cmd.printerr("Error: brightness percentage must be between 0 and 100\n"); |
| 106 | + return 1; |
| 107 | + } |
| 108 | + success = set_brightness_percent(opt_set); |
| 109 | + } |
| 110 | + |
| 111 | + return success ? 0 : 1; |
| 112 | + } |
| 113 | + |
| 114 | + private bool setup_logind_session() { |
| 115 | + try { |
| 116 | + string? session_id = BrightnessUtil.get_session_id(); |
| 117 | + |
| 118 | + if (session_id == null || session_id == "") { |
| 119 | + critical("Could not determine session ID"); |
| 120 | + return false; |
| 121 | + } |
| 122 | + |
| 123 | + string session_path = Path.build_filename("/org/freedesktop/login1/session", session_id); |
| 124 | + |
| 125 | + logind_session = Bus.get_proxy_sync( |
| 126 | + BusType.SYSTEM, |
| 127 | + "org.freedesktop.login1", |
| 128 | + session_path |
| 129 | + ); |
| 130 | + |
| 131 | + return true; |
| 132 | + |
| 133 | + } catch (Error e) { |
| 134 | + critical("Error connecting to logind: %s", e.message); |
| 135 | + return false; |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + public bool set_brightness(uint32 value) { |
| 140 | + if (logind_session == null || util.backlight_device == null) { |
| 141 | + critical("Brightness control not initialized"); |
| 142 | + return false; |
| 143 | + } |
| 144 | + |
| 145 | + uint32 clamped = uint32.min(value, util.max_brightness); |
| 146 | + |
| 147 | + try { |
| 148 | + logind_session.SetBrightness("backlight", util.backlight_device, clamped); |
| 149 | + return true; |
| 150 | + } catch (Error e) { |
| 151 | + critical("Failed to set brightness: %s", e.message); |
| 152 | + return false; |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + public bool set_brightness_percent(int percent) { |
| 157 | + if (util.max_brightness == 0) { |
| 158 | + critical("Max brightness is 0"); |
| 159 | + return false; |
| 160 | + } |
| 161 | + |
| 162 | + int clamped = percent.clamp(0, 100); |
| 163 | + uint32 value = (uint32)((clamped * util.max_brightness) / 100); |
| 164 | + return set_brightness(value); |
| 165 | + } |
| 166 | + |
| 167 | + public bool increase_brightness(int step_percent) { |
| 168 | + if (util.max_brightness == 0) { |
| 169 | + critical("Max brightness is 0"); |
| 170 | + return false; |
| 171 | + } |
| 172 | + |
| 173 | + int current_percent = (util.current_brightness * 100) / util.max_brightness; |
| 174 | + int new_percent = (current_percent + step_percent).clamp(0, 100); |
| 175 | + return set_brightness_percent(new_percent); |
| 176 | + } |
| 177 | + |
| 178 | + public bool decrease_brightness(int step_percent) { |
| 179 | + if (util.max_brightness == 0) { |
| 180 | + critical("Max brightness is 0"); |
| 181 | + return false; |
| 182 | + } |
| 183 | + |
| 184 | + int current_percent = (util.current_brightness * 100) / util.max_brightness; |
| 185 | + int new_percent = (current_percent - step_percent).clamp(0, 100); |
| 186 | + return set_brightness_percent(new_percent); |
| 187 | + } |
| 188 | + |
| 189 | + public static int main(string[] args) { |
| 190 | + var app = new BrightnessHelper(); |
| 191 | + return app.run(args); |
| 192 | + } |
| 193 | + } |
| 194 | +} |
0 commit comments