diff options
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Services/HyprlandService.qml')
| -rw-r--r-- | raveos-hyprland-theme/theme-data/dms/Services/HyprlandService.qml | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Services/HyprlandService.qml b/raveos-hyprland-theme/theme-data/dms/Services/HyprlandService.qml new file mode 100644 index 0000000..20096ef --- /dev/null +++ b/raveos-hyprland-theme/theme-data/dms/Services/HyprlandService.qml @@ -0,0 +1,338 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtCore +import QtQuick +import Quickshell +import Quickshell.Hyprland +import qs.Common + +Singleton { + id: root + + readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + readonly property string hyprDmsDir: configDir + "/hypr/dms" + readonly property string outputsPath: hyprDmsDir + "/outputs.conf" + readonly property string layoutPath: hyprDmsDir + "/layout.conf" + readonly property string cursorPath: hyprDmsDir + "/cursor.conf" + readonly property string windowrulesPath: hyprDmsDir + "/windowrules.conf" + + property int _lastGapValue: -1 + + Component.onCompleted: { + if (CompositorService.isHyprland) { + Qt.callLater(generateLayoutConfig); + ensureWindowrulesConfig(); + } + } + + function ensureWindowrulesConfig() { + Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => { + if (exitCode !== 0) + console.warn("HyprlandService: Failed to ensure windowrules.conf:", output); + }); + } + + Connections { + target: SettingsData + function onBarConfigsChanged() { + if (!CompositorService.isHyprland) + return; + const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); + if (newGaps === root._lastGapValue) + return; + root._lastGapValue = newGaps; + generateLayoutConfig(); + } + } + + Connections { + target: CompositorService + function onIsHyprlandChanged() { + if (CompositorService.isHyprland) + generateLayoutConfig(); + } + } + + function getOutputIdentifier(output, outputName) { + if (SettingsData.displayNameMode === "model" && output.make && output.model) + return "desc:" + output.make + " " + output.model + " " + (output.serial || "Unknown"); + return outputName; + } + + function generateOutputsConfig(outputsData, hyprlandSettings) { + if (!outputsData || Object.keys(outputsData).length === 0) + return; + + const settings = hyprlandSettings || SettingsData.hyprlandOutputSettings; + let lines = ["# Auto-generated by DMS - do not edit manually", ""]; + let monitorv2Blocks = []; + + for (const outputName in outputsData) { + const output = outputsData[outputName]; + if (!output) + continue; + + const identifier = getOutputIdentifier(output, outputName); + const outputSettings = settings[identifier] || {}; + + if (outputSettings.disabled) { + lines.push("monitor = " + identifier + ", disable"); + continue; + } + + let resolution = "preferred"; + if (output.modes && output.current_mode !== undefined) { + const mode = output.modes[output.current_mode]; + if (mode) + resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3); + } + + const x = output.logical?.x ?? 0; + const y = output.logical?.y ?? 0; + const position = x + "x" + y; + const scale = output.logical?.scale ?? 1.0; + + let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale; + + const transform = transformToHyprland(output.logical?.transform ?? "Normal"); + if (transform !== 0) + monitorLine += ", transform, " + transform; + + if (output.vrr_supported) { + const vrrMode = outputSettings.vrrFullscreenOnly ? 2 : (output.vrr_enabled ? 1 : 0); + monitorLine += ", vrr, " + vrrMode; + } + + if (output.mirror && output.mirror.length > 0) + monitorLine += ", mirror, " + output.mirror; + + if (outputSettings.bitdepth && outputSettings.bitdepth !== 8) + monitorLine += ", bitdepth, " + outputSettings.bitdepth; + + if (outputSettings.colorManagement && outputSettings.colorManagement !== "auto") + monitorLine += ", cm, " + outputSettings.colorManagement; + + if (outputSettings.sdrBrightness !== undefined && outputSettings.sdrBrightness !== 1.0) + monitorLine += ", sdrbrightness, " + outputSettings.sdrBrightness; + + if (outputSettings.sdrSaturation !== undefined && outputSettings.sdrSaturation !== 1.0) + monitorLine += ", sdrsaturation, " + outputSettings.sdrSaturation; + + lines.push(monitorLine); + + const needsMonitorv2 = outputSettings.supportsHdr || outputSettings.supportsWideColor || outputSettings.sdrMinLuminance !== undefined || outputSettings.sdrMaxLuminance !== undefined || outputSettings.minLuminance !== undefined || outputSettings.maxLuminance !== undefined || outputSettings.maxAvgLuminance !== undefined; + + if (needsMonitorv2) { + let block = "monitorv2 {\n"; + block += " output = " + identifier + "\n"; + + if (outputSettings.supportsWideColor) + block += " supports_wide_color = true\n"; + if (outputSettings.supportsHdr) + block += " supports_hdr = true\n"; + if (outputSettings.sdrMinLuminance !== undefined) + block += " sdr_min_luminance = " + outputSettings.sdrMinLuminance + "\n"; + if (outputSettings.sdrMaxLuminance !== undefined) + block += " sdr_max_luminance = " + outputSettings.sdrMaxLuminance + "\n"; + if (outputSettings.minLuminance !== undefined) + block += " min_luminance = " + outputSettings.minLuminance + "\n"; + if (outputSettings.maxLuminance !== undefined) + block += " max_luminance = " + outputSettings.maxLuminance + "\n"; + if (outputSettings.maxAvgLuminance !== undefined) + block += " max_avg_luminance = " + outputSettings.maxAvgLuminance + "\n"; + + block += "}"; + monitorv2Blocks.push(block); + } + } + + if (monitorv2Blocks.length > 0) { + lines.push(""); + for (const block of monitorv2Blocks) + lines.push(block); + } + + lines.push(""); + + const content = lines.join("\n"); + + Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { + if (exitCode !== 0) { + console.warn("HyprlandService: Failed to write outputs config:", output); + return; + } + console.info("HyprlandService: Generated outputs config at", outputsPath); + if (CompositorService.isHyprland) + reloadConfig(); + }); + } + + function reloadConfig() { + Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => { + if (exitCode !== 0) + console.warn("HyprlandService: hyprctl reload failed:", output); + }); + } + + function generateLayoutConfig() { + if (!CompositorService.isHyprland) + return; + + const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; + const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4; + const defaultBorderSize = 2; + + const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutRadiusOverride >= 0) ? SettingsData.hyprlandLayoutRadiusOverride : defaultRadius; + const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps; + const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize; + + let content = `# Auto-generated by DMS - do not edit manually + +general { + gaps_in = ${gaps} + gaps_out = ${gaps} + border_size = ${borderSize} +} + +decoration { + rounding = ${cornerRadius} +} +`; + + Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { + if (exitCode !== 0) { + console.warn("HyprlandService: Failed to write layout config:", output); + return; + } + console.info("HyprlandService: Generated layout config at", layoutPath); + reloadConfig(); + }); + } + + function transformToHyprland(transform) { + switch (transform) { + case "Normal": + return 0; + case "90": + return 1; + case "180": + return 2; + case "270": + return 3; + case "Flipped": + return 4; + case "Flipped90": + return 5; + case "Flipped180": + return 6; + case "Flipped270": + return 7; + default: + return 0; + } + } + + function hyprlandToTransform(value) { + switch (value) { + case 0: + return "Normal"; + case 1: + return "90"; + case 2: + return "180"; + case 3: + return "270"; + case 4: + return "Flipped"; + case 5: + return "Flipped90"; + case 6: + return "Flipped180"; + case 7: + return "Flipped270"; + default: + return "Normal"; + } + } + + function generateCursorConfig() { + if (!CompositorService.isHyprland) + return; + + const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null; + if (!settings) { + Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { + if (exitCode !== 0) + console.warn("HyprlandService: Failed to write cursor config:", output); + }); + return; + } + + const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme; + const size = settings.size || 24; + const hideOnKeyPress = settings.hyprland?.hideOnKeyPress || false; + const hideOnTouch = settings.hyprland?.hideOnTouch || false; + const inactiveTimeout = settings.hyprland?.inactiveTimeout || 0; + + const hasTheme = themeName && themeName.length > 0; + const hasNonDefaultSize = size !== 24; + const hasCursorSettings = hideOnKeyPress || hideOnTouch || inactiveTimeout > 0; + + if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) { + Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { + if (exitCode !== 0) + console.warn("HyprlandService: Failed to write cursor config:", output); + }); + return; + } + + let lines = ["# Auto-generated by DMS - do not edit manually", ""]; + + if (hasTheme) { + lines.push(`env = HYPRCURSOR_THEME,${themeName}`); + lines.push(`env = XCURSOR_THEME,${themeName}`); + } + lines.push(`env = HYPRCURSOR_SIZE,${size}`); + lines.push(`env = XCURSOR_SIZE,${size}`); + + if (hasCursorSettings) { + lines.push(""); + lines.push("cursor {"); + if (hideOnKeyPress) + lines.push(" hide_on_key_press = true"); + if (hideOnTouch) + lines.push(" hide_on_touch = true"); + if (inactiveTimeout > 0) + lines.push(` inactive_timeout = ${inactiveTimeout}`); + lines.push("}"); + } + + lines.push(""); + const content = lines.join("\n"); + + Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { + if (exitCode !== 0) { + console.warn("HyprlandService: Failed to write cursor config:", output); + return; + } + if (hasTheme) + Proc.runCommand("hyprctl-setcursor", ["hyprctl", "setcursor", themeName, String(size)], () => {}); + reloadConfig(); + }); + } + + function renameWorkspace(newName) { + if (!Hyprland.focusedWorkspace) + return; + const wsId = Hyprland.focusedWorkspace.id; + if (!wsId) + return; + const fullName = wsId + " " + newName; + Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => { + if (exitCode !== 0) { + console.warn("HyprlandService: Failed to rename workspace:", output); + } + }); + } +} |