master ohmu/fastfetch-openbsd / src / detection / brightness / brightness_windows.c
ohmu  ·  2026-10-15
  1#include "brightness.h"
  2#include "detection/displayserver/displayserver.h"
  3#include "common/debug.h"
  4#include "common/library.h"
  5#include "common/mallocHelper.h"
  6#include "common/windows/wmi.h"
  7#include "common/windows/unicode.h"
  8
  9#include <inttypes.h>
 10#include <winternl.h>
 11#include <windows.h>
 12
 13NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
 14    _In_ UNICODE_STRING* pstrDeviceName,
 15    _In_ DWORD dwPhysicalMonitorArraySize,
 16    _Out_ DWORD* pdwNumPhysicalMonitorHandlesInArray,
 17    _Out_ HANDLE* phPhysicalMonitorArray);
 18
 19typedef enum _MC_VCP_CODE_TYPE {
 20    MC_MOMENTARY,
 21    MC_SET_PARAMETER
 22} MC_VCP_CODE_TYPE,
 23    *LPMC_VCP_CODE_TYPE;
 24
 25NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
 26    _In_ HANDLE hMonitor,
 27    _In_ DWORD dwVCPCode,
 28    _Out_opt_ LPMC_VCP_CODE_TYPE pvct,
 29    _Out_ DWORD* pdwCurrentValue,
 30    _Out_opt_ DWORD* pdwMaximumValue);
 31
 32NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
 33    _In_ HANDLE hMonitor);
 34
 35NTSTATUS WINAPI GetPhysicalMonitorDescription(
 36    _In_ HANDLE hMonitor,
 37    _In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
 38    _Out_ LPWSTR szPhysicalMonitorDescription);
 39
 40static const char* detectWithWmi(FFlist* result) {
 41    FF_DEBUG("WMI: start detection");
 42
 43    // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/wmicore.mof#L21200
 44    const GUID WmiMonitorBrightnessGuid = {
 45        0xd43412ac, 0x67f9, 0x4fbb, { 0xa0, 0x81, 0x17, 0x52, 0xa2, 0xc3, 0x3e, 0x84 }
 46    };
 47
 48    [[gnu::cleanup(ffCloseWmiBlock)]] HANDLE hBlock = nullptr;
 49
 50    ULONG status = WmiOpenBlock(&WmiMonitorBrightnessGuid, WMIGUID_QUERY, &hBlock);
 51    if (status != 0) {
 52        FF_DEBUG("WMI: WmiOpenBlock failed: %s", ffDebugWin32Error(status));
 53        return "WmiOpenBlock() failed";
 54    }
 55
 56    ULONG bufferSize = 0;
 57    status = WmiQueryAllDataW(hBlock, &bufferSize, nullptr);
 58    if (status != ERROR_SUCCESS && status != ERROR_INSUFFICIENT_BUFFER) {
 59        FF_DEBUG("WMI: first WmiQueryAllDataW failed, bufferSize=%lu: %s", bufferSize, ffDebugWin32Error(status));
 60        return "WmiQueryAllDataW() failed";
 61    }
 62
 63    FF_DEBUG("WMI: initial query bufferSize=%lu", bufferSize);
 64
 65    if (bufferSize == 0) {
 66        FF_DEBUG("WMI: WmiQueryAllDataW returned empty buffer");
 67        return "WmiQueryAllDataW() returned no data";
 68    }
 69
 70    FF_AUTO_FREE PWNODE_ALL_DATA pAllData = (PWNODE_ALL_DATA) malloc(bufferSize);
 71
 72    status = WmiQueryAllDataW(hBlock, &bufferSize, pAllData);
 73    if (status != ERROR_SUCCESS) {
 74        FF_DEBUG("WMI: second WmiQueryAllDataW failed, bufferSize=%lu: %s", bufferSize, ffDebugWin32Error(status));
 75        return "WmiQueryAllDataW() failed";
 76    }
 77
 78    if (bufferSize < sizeof(WNODE_ALL_DATA)) {
 79        FF_DEBUG("WMI: insufficient buffer for WNODE_ALL_DATA, bufferSize=%lu", bufferSize);
 80        return "WmiQueryAllDataW() returned insufficient data for WNODE_ALL_DATA";
 81    }
 82
 83    FF_DEBUG("WMI: instanceCount=%lu, flags=0x%lX", pAllData->InstanceCount, pAllData->WnodeHeader.Flags);
 84
 85    PULONG pNameOffsets = (PULONG) ((PUCHAR) pAllData + pAllData->OffsetInstanceNameOffsets);
 86
 87    for (ULONG i = 0; i < pAllData->InstanceCount; i++) {
 88        ULONG dataOffset = 0;
 89        ULONG dataLength = 0;
 90
 91        if (pAllData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE) {
 92            dataLength = pAllData->FixedInstanceSize;
 93            dataOffset = pAllData->DataBlockOffset + i * dataLength;
 94        } else {
 95            dataOffset = pAllData->OffsetInstanceDataAndLength[i].OffsetInstanceData;
 96            dataLength = pAllData->OffsetInstanceDataAndLength[i].LengthInstanceData;
 97        }
 98
 99        if (dataLength == 0 || dataOffset >= bufferSize || dataLength > bufferSize - dataOffset) {
100            FF_DEBUG("WMI: skip invalid instance %lu (dataOffset=%lu, dataLength=%lu, bufferSize=%lu)", i, dataOffset, dataLength, bufferSize);
101            continue;
102        }
103
104        USHORT nameCharsCount = *(PUSHORT) ((PUCHAR) pAllData + pNameOffsets[i]) / sizeof(WCHAR);
105        PCWSTR pNameChars = (PCWSTR) ((PUCHAR) pAllData + (pNameOffsets[i] + sizeof(USHORT)));
106
107        PUCHAR pDataBlock = (PUCHAR) pAllData + dataOffset;
108        UCHAR currentBrightness = pDataBlock[0];
109
110        FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
111        brightness->max = 100;
112        brightness->min = 0;
113        brightness->current = currentBrightness;
114        brightness->builtin = true;
115        ffStrbufInitNWS(&brightness->name, nameCharsCount, pNameChars);
116        ffStrbufSubstrAfterFirstC(&brightness->name, '\\');
117        ffStrbufSubstrBeforeFirstC(&brightness->name, '\\');
118
119        FF_DEBUG("WMI: detected builtin display '%s', current=%u", brightness->name.chars, (unsigned) currentBrightness);
120    }
121
122    FF_DEBUG("WMI: finished detection, total results=%u", result->length);
123
124    return nullptr;
125}
126
127static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result) {
128    FF_DEBUG("DDC/CI: start detection, displayCount=%u", displayServer->displays.length);
129
130    void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
131    if (!gdi32) {
132        FF_DEBUG("DDC/CI: failed to load gdi32.dll");
133        return "ffLibraryGetModule(gdi32.dll) failed";
134    }
135    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
136    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
137    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
138
139    FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
140        if (display->type == FF_DISPLAY_TYPE_BUILTIN) {
141            FF_DEBUG("DDC/CI: skip builtin display id=%" PRIu64, display->id);
142            continue;
143        }
144
145        MONITORINFOEXW mi;
146        mi.cbSize = sizeof(mi);
147        if (!GetMonitorInfoW((HMONITOR) (uintptr_t) display->id, (LPMONITORINFO) &mi)) {
148            FF_DEBUG("DDC/CI: GetMonitorInfoW failed for display id=%" PRIu64 ": %s", display->id, ffDebugWin32Error(GetLastError()));
149            continue;
150        }
151
152        UNICODE_STRING deviceName = {
153            .Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
154            .MaximumLength = 0,
155            .Buffer = mi.szDevice,
156        };
157        HANDLE physicalMonitor;
158        DWORD monitorCount = 0;
159        NTSTATUS monitorStatus = ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor);
160        if (NT_SUCCESS(monitorStatus) && monitorCount >= 1) {
161            DWORD curr = 0, max = 0;
162            monitorStatus = ffDDCCIGetVCPFeature(physicalMonitor, FF_DDC_CI_LUMINANCE_OPCODE, nullptr, &curr, &max);
163            if (NT_SUCCESS(monitorStatus)) {
164                FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
165                if (display->name.length > 0) {
166                    ffStrbufInitCopy(&brightness->name, &display->name);
167                } else {
168                    FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
169                    if (ffGetPhysicalMonitorDescription) {
170                        wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
171                        monitorStatus = ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description);
172                        if (NT_SUCCESS(monitorStatus)) {
173                            ffStrbufInitWS(&brightness->name, description);
174                        } else {
175                            FF_DEBUG("DDC/CI: GetPhysicalMonitorDescription failed for monitor '%ls': %s", deviceName.Buffer, ffDebugNtStatus(monitorStatus));
176                        }
177                    }
178                    if (brightness->name.length == 0) {
179                        ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
180                    }
181                }
182                brightness->max = max;
183                brightness->min = 0;
184                brightness->current = curr;
185                brightness->builtin = false;
186
187                FF_DEBUG("DDC/CI: detected external display '%s', current=%u, max=%u", brightness->name.chars, (unsigned) curr, (unsigned) max);
188            } else {
189                FF_DEBUG("DDC/CI: DDCCIGetVCPFeature failed for monitor '%ls': %s", deviceName.Buffer, ffDebugNtStatus(monitorStatus));
190            }
191
192            ffDestroyPhysicalMonitorInternal(physicalMonitor);
193        } else {
194            FF_DEBUG("DDC/CI: GetPhysicalMonitors failed for '%ls', status=0x%08X, monitorCount=%lu, error=%s", deviceName.Buffer, (unsigned) monitorStatus, monitorCount, ffDebugWin32Error(GetLastError()));
195        }
196    }
197
198    FF_DEBUG("DDC/CI: finished detection, total results=%u", result->length);
199    return nullptr;
200}
201
202static bool hasBuiltinDisplay(const FFDisplayServerResult* displayServer) {
203    FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
204        if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN) {
205            return true;
206        }
207    }
208    return false;
209}
210
211const char* ffDetectBrightness([[maybe_unused]] FFBrightnessOptions* options, FFlist* result) {
212    const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
213    FF_DEBUG("start, displayCount=%u", displayServer->displays.length);
214
215    if (hasBuiltinDisplay(displayServer)) {
216        FF_DEBUG("builtin display detected, trying WMI");
217        detectWithWmi(result);
218    }
219
220    if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP && result->length < displayServer->displays.length) {
221        FF_DEBUG("resultCount=%u < displayCount=%u, trying DDC/CI", result->length, displayServer->displays.length);
222        detectWithDdcci(displayServer, result);
223    }
224
225    FF_DEBUG("finished, resultCount=%u", result->length);
226    return nullptr;
227}