ohmu
·
2026-10-15
1#include "common/percent.h"
2#include "common/printing.h"
3#include "common/jsonconfig.h"
4#include "common/strutil.h"
5#include "detection/brightness/brightness.h"
6#include "modules/brightness/brightness.h"
7
8bool ffPrintBrightness(FFBrightnessOptions* options) {
9 FF_LIST_AUTO_DESTROY result = ffListCreate();
10
11 const char* error = ffDetectBrightness(options, &result);
12
13 if (error) {
14 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
15 return false;
16 }
17
18 if (result.length == 0) {
19 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result is detected.");
20 return false;
21 }
22
23 FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
24
25 if (options->compact) {
26 FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate();
27
28 FF_LIST_FOR_EACH (FFBrightnessResult, item, result) {
29 if (str.length > 0) {
30 ffStrbufAppendC(&str, ' ');
31 }
32
33 const double percent = (item->current - item->min) / (item->max - item->min) * 100;
34 ffPercentAppendNum(&str, percent, options->percent, false, &options->moduleArgs);
35 }
36
37 ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
38 ffStrbufPutTo(&str, stdout);
39 return true;
40 }
41
42 FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
43
44 uint32_t index = 0;
45 FF_LIST_FOR_EACH (FFBrightnessResult, item, result) {
46 if (options->moduleArgs.key.length == 0) {
47 ffStrbufAppendF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Brightness), item->name.chars);
48 } else {
49 uint32_t moduleIndex = result.length == 1 ? 0 : index + 1;
50 FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
51 FF_ARG(moduleIndex, "index"),
52 FF_ARG(item->name, "name"),
53 FF_ARG(options->moduleArgs.keyIcon, "icon"),
54 FF_ARG(FF_MODULE_GET_DISPLAY_NAME(Brightness), "module-name"),
55 }));
56 }
57
58 const double percent = (item->current - item->min) / (item->max - item->min) * 100;
59
60 if (options->moduleArgs.outputFormat.length == 0) {
61 FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate();
62 ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
63
64 if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
65 ffPercentAppendBar(&str, percent, options->percent, &options->moduleArgs);
66 }
67
68 if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
69 if (str.length > 0) {
70 ffStrbufAppendC(&str, ' ');
71 }
72
73 ffPercentAppendNum(&str, percent, options->percent, str.length > 0, &options->moduleArgs);
74 }
75
76 ffStrbufAppendS(&str, item->builtin ? " [Built-in]" : " [External]");
77
78 ffStrbufPutTo(&str, stdout);
79 } else {
80 FF_STRBUF_AUTO_DESTROY valueNum = ffStrbufCreate();
81 if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
82 ffPercentAppendNum(&valueNum, percent, options->percent, false, &options->moduleArgs);
83 }
84 FF_STRBUF_AUTO_DESTROY valueBar = ffStrbufCreate();
85 if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
86 ffPercentAppendBar(&valueBar, percent, options->percent, &options->moduleArgs);
87 }
88
89 FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
90 FF_ARG(valueNum, "percentage"),
91 FF_ARG(item->name, "name"),
92 FF_ARG(item->max, "max"),
93 FF_ARG(item->min, "min"),
94 FF_ARG(item->current, "current"),
95 FF_ARG(valueBar, "percentage-bar"),
96 FF_ARG(item->builtin, "is-builtin"),
97 }));
98 }
99
100 ffStrbufClear(&key);
101 ffStrbufDestroy(&item->name);
102 ++index;
103 }
104
105 return true;
106}
107
108void ffParseBrightnessJsonObject(FFBrightnessOptions* options, yyjson_val* module) {
109 yyjson_val *key, *val;
110 size_t idx, max;
111 yyjson_obj_foreach (module, idx, max, key, val) {
112 if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
113 continue;
114 }
115
116 if (unsafe_yyjson_equals_str(key, "ddcciSleep")) {
117 if (yyjson_is_null(val)) {
118 options->ddcciSleep = FF_BRIGHTNESS_DDCCI_SLEEP_SKIP;
119 } else {
120 options->ddcciSleep = (uint32_t) yyjson_get_uint(val);
121 }
122 continue;
123 }
124
125 if (unsafe_yyjson_equals_str(key, "compact")) {
126 options->compact = (uint32_t) yyjson_get_bool(val);
127 continue;
128 }
129
130 if (ffPercentParseJsonObject(key, val, &options->percent)) {
131 continue;
132 }
133
134 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
135 }
136}
137
138[[gnu::cold]]
139void ffGenerateBrightnessJsonConfig(FFBrightnessOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
140 ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
141
142 if (options->ddcciSleep == FF_BRIGHTNESS_DDCCI_SLEEP_SKIP) {
143 yyjson_mut_obj_add_null(doc, module, "ddcciSleep");
144 } else {
145 yyjson_mut_obj_add_uint(doc, module, "ddcciSleep", options->ddcciSleep);
146 }
147
148 ffPercentGenerateJsonConfig(doc, module, options->percent);
149
150 yyjson_mut_obj_add_bool(doc, module, "compact", options->compact);
151}
152
153bool ffGenerateBrightnessJsonResult([[maybe_unused]] FFBrightnessOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
154 FF_LIST_AUTO_DESTROY result = ffListCreate();
155
156 const char* error = ffDetectBrightness(options, &result);
157
158 if (error) {
159 yyjson_mut_obj_add_str(doc, module, "error", error);
160 return false;
161 }
162
163 yyjson_mut_val* arr = yyjson_mut_arr(doc);
164 yyjson_mut_obj_add_val(doc, module, "result", arr);
165
166 FF_LIST_FOR_EACH (FFBrightnessResult, item, result) {
167 yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
168 yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
169 yyjson_mut_obj_add_real(doc, obj, "max", item->max);
170 yyjson_mut_obj_add_real(doc, obj, "min", item->min);
171 yyjson_mut_obj_add_real(doc, obj, "current", item->current);
172 yyjson_mut_obj_add_bool(doc, obj, "builtin", item->builtin);
173 }
174
175 FF_LIST_FOR_EACH (FFBrightnessResult, item, result) {
176 ffStrbufDestroy(&item->name);
177 }
178
179 return true;
180}
181
182void ffInitBrightnessOptions(FFBrightnessOptions* options) {
183 ffOptionInitModuleArg(&options->moduleArgs, "");
184
185 options->ddcciSleep = 10;
186 options->percent = (FFPercentageModuleConfig) { 100, 100, 0 };
187 options->compact = false;
188}
189
190void ffDestroyBrightnessOptions(FFBrightnessOptions* options) {
191 ffOptionDestroyModuleArg(&options->moduleArgs);
192}
193
194FFModuleBaseInfo ffBrightnessModuleInfo = {
195 .name = "Brightness",
196 .description = "Print the current brightness level of your monitors",
197 .displayName = {
198 .en = "Brightness",
199 .ar = "السطوع",
200 .cs = "Jas",
201 .de = "Helligkeit",
202 .es = "Brillo",
203 .fi = "Kirkkaus",
204 .fr = "Luminosité",
205 .gl = "Brillo",
206 .he = "בהירות",
207 .id = "Kecerahan",
208 .it = "Luminosità",
209 .ja = "明るさ",
210 .ko = "밝기",
211 .pl = "Jasność",
212 .pt = "Brilho",
213 .ru = "Яркость",
214 .tr = "Parlaklık",
215 .uk = "Яскравість",
216 .vi = "Độ sáng",
217 .zh_CN = "亮度",
218 .zh_TW = "亮度",
219 },
220 .initOptions = (void*) ffInitBrightnessOptions,
221 .destroyOptions = (void*) ffDestroyBrightnessOptions,
222 .parseJsonObject = (void*) ffParseBrightnessJsonObject,
223 .printModule = (void*) ffPrintBrightness,
224 .generateJsonResult = (void*) ffGenerateBrightnessJsonResult,
225 .generateJsonConfig = (void*) ffGenerateBrightnessJsonConfig,
226 .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
227 { "Screen brightness (percentage num)", "percentage" },
228 { "Screen name *", "name" },
229 { "Maximum brightness value", "max" },
230 { "Minimum brightness value", "min" },
231 { "Current brightness value", "current" },
232 { "Screen brightness (percentage bar)", "percentage-bar" },
233 { "Is built-in screen", "is-builtin" },
234 })),
235 .defaultOrder = 18,
236};