mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
* feat: add workspace rename dialog - Adds a modal dialog to rename the current workspace - Supports both Niri (via IPC socket) and Hyprland (via hyprctl dispatch) - Default keybinding: Ctrl+Shift+R to open the dialog - Pre-fills with current workspace name - Allows setting empty name to reset to default * refactor: wrap WorkspaceRenameModal in LazyLoader Reduces memory footprint when the modal is not in use.
326 lines
12 KiB
QML
326 lines
12 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtCore
|
|
import QtQuick
|
|
import Quickshell
|
|
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"
|
|
|
|
property int _lastGapValue: -1
|
|
|
|
Component.onCompleted: {
|
|
if (CompositorService.isHyprland)
|
|
Qt.callLater(generateLayoutConfig);
|
|
}
|
|
|
|
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;
|
|
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 && output.vrr_enabled)
|
|
monitorLine += ", vrr, 1";
|
|
|
|
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);
|
|
}
|
|
});
|
|
}
|
|
}
|