From b9cdf92e49bbce8d72744c42b557a0c583e21026 Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Sat, 10 Jan 2026 22:47:59 +0100 Subject: [PATCH] feat: add display server detection to osInfo() Adds displayServer field to detect which graphical display server is currently active. This helps identify the graphics stack being used and whether the system is running in GUI or headless mode. Supported display servers: - wayland, x11 (Linux/BSD) - quartz (macOS) - dwm (Windows) - surfaceflinger (Android) Returns empty string for headless/console sessions on all platforms. --- README.md | 1 + docs/os.html | 13 +++++++- docs/v4/os.html | 13 +++++++- lib/index.d.ts | 1 + lib/osinfo.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 108 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5ac4062a..3b1755c8 100644 --- a/README.md +++ b/README.md @@ -468,6 +468,7 @@ Full function reference with examples can be found at | | uefi | X | X | X | X | | OS started via UEFI | | | hypervisor | | | | X | | hyper-v enabled? (win only) | | | remoteSession | | | | X | | runs in remote session (win only) | +| | displayServer | X | X | X | X | X | display server e.g. wayland, x11, quartz, dwm, surfaceflinger or '' (headless) | | si.uuid(cb) | {...} | X | X | X | X | X | object of several UUIDs | | | os | X | X | X | X | | os specific UUID | | | hardware | X | X | X | X | | hardware specific UUID | diff --git a/docs/os.html b/docs/os.html index eec6157f..572ad6bc 100644 --- a/docs/os.html +++ b/docs/os.html @@ -236,6 +236,16 @@

Operating System, Shell, Versions, Users

runs in remote session (win only) + + + displayServer + X + X + X + X + X + display server: wayland, x11, quartz, dwm, tty + @@ -257,7 +267,8 @@
Example
serial: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', build: '19D76', servicepack: '', - uefi: true + uefi: true, + displayServer: 'quartz' } diff --git a/docs/v4/os.html b/docs/v4/os.html index add0487c..3d96222b 100644 --- a/docs/v4/os.html +++ b/docs/v4/os.html @@ -216,6 +216,16 @@

Operating System, Shell, Versions, Users

OS uses UEFI on startup + + + displayServer + X + X + X + X + X + display server: wayland, x11, quartz, dwm, tty + @@ -237,7 +247,8 @@
Example
serial: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', build: '19D76', servicepack: '', - uefi: true + uefi: true, + displayServer: 'quartz' } diff --git a/lib/index.d.ts b/lib/index.d.ts index e38786f4..f481f41e 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -379,6 +379,7 @@ export namespace Systeminformation { uefi: boolean | null; hypervizor?: boolean; remoteSession?: boolean; + displayServer: string; } interface UuidData { diff --git a/lib/osinfo.js b/lib/osinfo.js index f8ae96cb..d3ada2f6 100644 --- a/lib/osinfo.js +++ b/lib/osinfo.js @@ -217,6 +217,81 @@ function getFQDN() { return fqdn; } +// -------------------------- +// Display Server Detection + +function getDisplayServer() { + let result = ''; + + // Linux and BSD systems can use X11, Wayland, or run headless (tty) + // Android uses SurfaceFlinger + if (_linux || _freebsd || _openbsd || _netbsd || _sunos) { + // Check for Android's SurfaceFlinger first + if (_platform === 'android') { + try { + // Check if surfaceflinger process is running + const stdout = execSync('pgrep -f surfaceflinger 2>/dev/null || ps -A 2>/dev/null | grep surfaceflinger', { encoding: 'utf8' }); + if (stdout && stdout.trim()) { + result = 'surfaceflinger'; + } + } catch { + // If check fails, still might be Android but headless or termux environment + result = ''; + } + } else { + // Primary method: XDG_SESSION_TYPE is the most reliable + const sessionType = process.env.XDG_SESSION_TYPE || ''; + if (sessionType) { + result = sessionType.toLowerCase(); + } else { + // Fallback: check for display environment variables + if (process.env.WAYLAND_DISPLAY) { + result = 'wayland'; + } else if (process.env.DISPLAY) { + result = 'x11'; + } else { + // No GUI - TTY/console session or headless + result = ''; + } + } + } + } + + // macOS uses Quartz Compositor when GUI is active + if (_darwin) { + try { + // Try to verify WindowServer is running + const stdout = execSync('pgrep WindowServer 2>/dev/null', { encoding: 'utf8' }); + // If output exists, WindowServer is running + if (stdout && stdout.trim()) { + result = 'quartz'; + } + } catch { + // If pgrep fails or WindowServer not found, assume headless + result = ''; + } + } + + // Windows uses DWM (Desktop Window Manager) when GUI is active + // Note: WSL2/WSLg is detected as Linux, not Windows + if (_windows) { + try { + // Check if dwm.exe process exists using simpler tasklist approach + const stdout = execSync('tasklist /NH /FI "IMAGENAME eq dwm.exe"', util.execOptsWin); + const output = stdout.toString().toLowerCase(); + // If dwm.exe in output, GUI is running + if (output && output.indexOf('dwm.exe') !== -1) { + result = 'dwm'; + } + } catch { + // If tasklist fails or dwm.exe not found, assume headless + result = ''; + } + } + + return result; +} + // -------------------------- // OS Information @@ -237,7 +312,8 @@ function osInfo(callback) { serial: '', build: '', servicepack: '', - uefi: false + uefi: false, + displayServer: '' }; if (_linux) { @@ -273,6 +349,7 @@ function osInfo(callback) { result.codename = codename; result.codepage = util.getCodepage(); result.build = (release.BUILD_ID || '').replace(/"/g, '').trim(); + result.displayServer = getDisplayServer(); isUefiLinux().then((uefi) => { result.uefi = uefi; uuid().then((data) => { @@ -302,6 +379,7 @@ function osInfo(callback) { result.codename = ''; result.codepage = util.getCodepage(); result.uefi = uefi || null; + result.displayServer = getDisplayServer(); if (callback) { callback(result); } @@ -337,6 +415,7 @@ function osInfo(callback) { result.codename = result.release.startsWith('26.') ? 'Tahoe' : result.codename; result.uefi = true; result.codepage = util.getCodepage(); + result.displayServer = getDisplayServer(); if (callback) { callback(result); } @@ -349,6 +428,7 @@ function osInfo(callback) { const lines = stdout.toString().split('\n'); result.distro = lines[0]; result.logofile = getLogoFile(result.distro); + result.displayServer = getDisplayServer(); if (callback) { callback(result); } @@ -383,6 +463,7 @@ function osInfo(callback) { result.codename = getWindowsRelease(buildNum); } result.remoteSession = term.toString().toLowerCase().indexOf('true') >= 0; + result.displayServer = getDisplayServer(); isUefiWindows().then((uefi) => { result.uefi = uefi; if (callback) {