Added better support for kubuntu and fixed some issues with telemetry.

This commit is contained in:
2026-09-09 22:35:13 +02:00
parent 6e6219107e
commit 290d1a5383
8 changed files with 587 additions and 65 deletions

View File

@@ -106,6 +106,7 @@ def collect_extended_environment(
"dependencies": dependencies,
}
display = _display_info(sysfs_drm)
display.update(_kde_display_scaling_info(environment, run_probe))
if display:
result["display"] = display
if gpu:
@@ -263,6 +264,23 @@ def _vulkan_info(
return result
def inspect_vulkan_support(
environment: Mapping[str, str],
*,
probe_runner: ProbeRunner | None = None,
manifest_directories: Sequence[Path] = _VULKAN_MANIFEST_DIRECTORIES,
library_roots: Sequence[Path] = _LIBRARY_ROOTS,
) -> dict[str, object]:
"""Return host Vulkan loader and ICD readiness for dependency checks."""
return _vulkan_info(
environment,
probe_runner or _run_probe,
manifest_directories=manifest_directories,
library_roots=library_roots,
)
def _gpu_info(
vulkan_summary: object,
*,
@@ -362,7 +380,7 @@ def _dependency_health(
try:
from .doctor import inspect_host
report = inspect_host(environment)
report = inspect_host(environment, vulkan_support=runtime)
for item in report.tools:
available = item.path is not None
tools[item.name] = available
@@ -834,15 +852,18 @@ def _vulkan_manifests(
directories: Sequence[Path],
) -> tuple[Path, ...]:
candidates: list[Path] = []
explicit = environment.get("VK_ICD_FILENAMES", "")
for value in explicit.split(os.pathsep):
if value:
candidates.append(Path(value).expanduser())
for directory in directories:
try:
candidates.extend(sorted(directory.glob("*.json")))
except OSError:
continue
override = environment.get("VK_DRIVER_FILES", "").strip()
if not override:
override = environment.get("VK_ICD_FILENAMES", "").strip()
if override:
candidates.extend(_manifest_entries(override))
else:
candidates.extend(_manifest_entries(environment.get("VK_ADD_DRIVER_FILES", "")))
for directory in _vulkan_manifest_search_directories(environment, directories):
try:
candidates.extend(sorted(directory.glob("*.json")))
except OSError:
continue
seen: set[Path] = set()
result: list[Path] = []
for candidate in candidates:
@@ -857,6 +878,54 @@ def _vulkan_manifests(
return tuple(result)
def _manifest_entries(value: str) -> tuple[Path, ...]:
result: list[Path] = []
for raw_entry in value.split(os.pathsep):
if not raw_entry:
continue
entry = Path(raw_entry).expanduser()
try:
if entry.is_dir():
result.extend(sorted(entry.glob("*.json")))
else:
result.append(entry)
except OSError:
continue
return tuple(result)
def _vulkan_manifest_search_directories(
environment: Mapping[str, str],
directories: Sequence[Path],
) -> tuple[Path, ...]:
if directories is not _VULKAN_MANIFEST_DIRECTORIES:
return tuple(dict.fromkeys(directories))
home = environment.get("HOME", "").strip()
config_home = environment.get("XDG_CONFIG_HOME", "").strip()
data_home = environment.get("XDG_DATA_HOME", "").strip()
config_directories = environment.get("XDG_CONFIG_DIRS", "/etc/xdg")
data_directories = environment.get(
"XDG_DATA_DIRS",
"/usr/local/share:/usr/share",
)
result = list(directories)
if config_home:
result.append(Path(config_home).expanduser() / "vulkan/icd.d")
elif home:
result.append(Path(home).expanduser() / ".config/vulkan/icd.d")
for value in config_directories.split(os.pathsep):
if value:
result.append(Path(value).expanduser() / "vulkan/icd.d")
if data_home:
result.append(Path(data_home).expanduser() / "vulkan/icd.d")
elif home:
result.append(Path(home).expanduser() / ".local/share/vulkan/icd.d")
for value in data_directories.split(os.pathsep):
if value:
result.append(Path(value).expanduser() / "vulkan/icd.d")
return tuple(dict.fromkeys(result))
def _vulkan_loader_architectures(library_roots: Sequence[Path]) -> set[int]:
architectures: set[int] = set()
for root in library_roots:
@@ -967,6 +1036,101 @@ def _display_info(sysfs_drm: Path) -> dict[str, object]:
return {"monitor_count": monitor_count} if monitor_count is not None else {}
def _kde_display_scaling_info(
environment: Mapping[str, str],
probe_runner: ProbeRunner,
) -> dict[str, object]:
"""Collect bounded Plasma scale facts without monitor names or resolutions."""
if not environment.get("WAYLAND_DISPLAY", "").strip() or not _is_kde_desktop(
environment
):
return {}
result: dict[str, object] = {"kde_wayland": True}
executable = shutil.which(
"kscreen-doctor",
path=environment.get("PATH", ""),
)
result["kscreen_doctor_available"] = executable is not None
if executable is None:
return result
probe = probe_runner(
(executable, "--json"),
environment,
PROBE_TIMEOUT_SECONDS,
)
if probe is None or probe.returncode != 0:
result["scale_probe_succeeded"] = False
return result
try:
payload = json.loads(probe.stdout)
except (json.JSONDecodeError, TypeError, UnicodeError):
result["scale_probe_succeeded"] = False
return result
if not isinstance(payload, dict):
result["scale_probe_succeeded"] = False
return result
raw_outputs = payload.get("outputs")
if isinstance(raw_outputs, list):
outputs = raw_outputs
elif isinstance(raw_outputs, dict):
outputs = list(raw_outputs.values())
else:
outputs = []
scales: list[float] = []
for output in outputs[:32]:
if not isinstance(output, dict):
continue
if output.get("connected") is False or output.get("enabled") is False:
continue
value = output.get("scale")
if isinstance(value, bool):
continue
try:
scale = float(value)
except (TypeError, ValueError):
continue
if not 0.5 <= scale <= 8.0:
continue
scales.append(round(scale, 3))
result["scale_probe_succeeded"] = bool(scales)
if not scales:
return result
unique_scales = sorted(set(scales))
result.update(
{
"scale_output_count": len(scales),
"scale_min": unique_scales[0],
"scale_max": unique_scales[-1],
"fractional_scaling": any(
abs(scale - round(scale)) > 0.001 for scale in unique_scales
),
"mixed_scaling": len(unique_scales) > 1,
"scale_detection": "kscreen_doctor",
}
)
return result
def _is_kde_desktop(environment: Mapping[str, str]) -> bool:
if environment.get("KDE_FULL_SESSION", "").strip().casefold() in {
"1",
"true",
"yes",
}:
return True
if environment.get("KDE_SESSION_VERSION", "").strip():
return True
for key in ("XDG_CURRENT_DESKTOP", "XDG_SESSION_DESKTOP", "DESKTOP_SESSION"):
tokens = re.split(
r"[^a-z0-9]+",
environment.get(key, "").strip().casefold(),
)
if "kde" in tokens or any(token.startswith("plasma") for token in tokens):
return True
return False
def _connected_monitor_count(sysfs_drm: Path) -> int | None:
try:
connectors = sorted(sysfs_drm.glob("card[0-9]*-*/status"))[:32]