mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-12 23:32:50 -04:00
feat(display): Fix and implement display auto-switching with JSON profile storage (#2275)
* feat(display): fix monitor auto config and add output disable guard * feat(display): fixed some race conditions and sole display getting disabled. Co-authored-by: Copilot <copilot@github.com> * feat(display): changes console log to use new log service * feat(display): fix trailing spaces * prek run * add migration, fix missing hyprland HDR parameters, use FileView > python --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: bbedward <bbedward@gmail.com>
This commit is contained in:
@@ -24,6 +24,7 @@ import qs.Modules.DankBar
|
|||||||
import qs.Modules.DankBar.Popouts
|
import qs.Modules.DankBar.Popouts
|
||||||
import qs.Modules.Frame
|
import qs.Modules.Frame
|
||||||
import qs.Modules.WorkspaceOverlays
|
import qs.Modules.WorkspaceOverlays
|
||||||
|
import qs.Modules.Settings.DisplayConfig
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -304,6 +305,8 @@ Item {
|
|||||||
dockRecreateDebounce.start();
|
dockRecreateDebounce.start();
|
||||||
// Force PolkitService singleton to initialize
|
// Force PolkitService singleton to initialize
|
||||||
PolkitService.polkitAvailable;
|
PolkitService.polkitAvailable;
|
||||||
|
// Force DisplayConfigState singleton to initialize so auto-config runs at startup
|
||||||
|
DisplayConfigState.hasOutputBackend;
|
||||||
loginSoundTimer.start();
|
loginSoundTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1622,13 +1622,15 @@ Item {
|
|||||||
|
|
||||||
for (const id in profiles) {
|
for (const id in profiles) {
|
||||||
const p = profiles[id];
|
const p = profiles[id];
|
||||||
|
if (!p.name)
|
||||||
|
continue;
|
||||||
const flags = [];
|
const flags = [];
|
||||||
if (id === activeId)
|
if (id === activeId)
|
||||||
flags.push("active");
|
flags.push("active");
|
||||||
if (id === matchedId)
|
if (id === matchedId)
|
||||||
flags.push("matched");
|
flags.push("matched");
|
||||||
const flagStr = flags.length > 0 ? " [" + flags.join(",") + "]" : "";
|
const flagStr = flags.length > 0 ? " [" + flags.join(",") + "]" : "";
|
||||||
lines.push(p.name + flagStr + " -> " + JSON.stringify(p.outputSet));
|
lines.push(p.name + flagStr + " -> " + JSON.stringify(Object.keys(p.outputs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lines.length === 0)
|
if (lines.length === 0)
|
||||||
@@ -1660,13 +1662,16 @@ Item {
|
|||||||
return `PROFILE_SET_SUCCESS: ${profileName}`;
|
return `PROFILE_SET_SUCCESS: ${profileName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! TODO - auto profile switching is buggy on niri and other compositors
|
|
||||||
function toggleAuto(): string {
|
function toggleAuto(): string {
|
||||||
return "ERROR: Auto profile selection is temporarily disabled due to compositor bugs";
|
SettingsData.displayProfileAutoSelect = !SettingsData.displayProfileAutoSelect;
|
||||||
|
SettingsData.saveSettings();
|
||||||
|
if (SettingsData.displayProfileAutoSelect)
|
||||||
|
DisplayConfigState.applyAutoConfig();
|
||||||
|
return `Auto profile selection: ${SettingsData.displayProfileAutoSelect ? "enabled" : "disabled"}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function status(): string {
|
function status(): string {
|
||||||
const auto = "off"; // disabled for now
|
const auto = SettingsData.displayProfileAutoSelect ? "on" : "off";
|
||||||
const activeId = SettingsData.getActiveDisplayProfile(CompositorService.compositor);
|
const activeId = SettingsData.getActiveDisplayProfile(CompositorService.compositor);
|
||||||
const matchedId = DisplayConfigState.matchedProfile;
|
const matchedId = DisplayConfigState.matchedProfile;
|
||||||
const profiles = DisplayConfigState.validatedProfiles;
|
const profiles = DisplayConfigState.validatedProfiles;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,8 @@ Column {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("Disable Output")
|
text: I18n.tr("Disable Output")
|
||||||
|
enabled: checked || DisplayConfigState.canDisableOutput()
|
||||||
|
description: (!checked && !DisplayConfigState.canDisableOutput()) ? (Object.keys(DisplayConfigState.outputs).length <= 1 ? I18n.tr("Cannot disable the only output") : I18n.tr("At least one output must remain enabled")) : ""
|
||||||
checked: DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "disabled", false)
|
checked: DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "disabled", false)
|
||||||
onToggled: checked => DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "disabled", checked)
|
onToggled: checked => DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "disabled", checked)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ Column {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("Disable Output")
|
text: I18n.tr("Disable Output")
|
||||||
|
enabled: checked || DisplayConfigState.canDisableOutput()
|
||||||
|
description: (!checked && !DisplayConfigState.canDisableOutput()) ? (Object.keys(DisplayConfigState.outputs).length <= 1 ? I18n.tr("Cannot disable the only output") : I18n.tr("At least one output must remain enabled")) : ""
|
||||||
checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "disabled", false)
|
checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "disabled", false)
|
||||||
onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "disabled", checked)
|
onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "disabled", checked)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ StyledRect {
|
|||||||
const pendingScale = DisplayConfigState.getPendingValue(root.outputName, "scale");
|
const pendingScale = DisplayConfigState.getPendingValue(root.outputName, "scale");
|
||||||
if (pendingScale !== undefined)
|
if (pendingScale !== undefined)
|
||||||
return parseFloat(pendingScale.toFixed(2)).toString();
|
return parseFloat(pendingScale.toFixed(2)).toString();
|
||||||
const scale = DisplayConfigState.outputs[root.outputName]?.logical?.scale ?? 1.0;
|
const scale = root.outputData?.logical?.scale || 1.0;
|
||||||
return parseFloat(scale.toFixed(2)).toString();
|
return parseFloat(scale.toFixed(2)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +251,7 @@ StyledRect {
|
|||||||
const pendingTransform = DisplayConfigState.getPendingValue(root.outputName, "transform");
|
const pendingTransform = DisplayConfigState.getPendingValue(root.outputName, "transform");
|
||||||
if (pendingTransform)
|
if (pendingTransform)
|
||||||
return DisplayConfigState.getTransformLabel(pendingTransform);
|
return DisplayConfigState.getTransformLabel(pendingTransform);
|
||||||
const data = DisplayConfigState.outputs[root.outputName];
|
return DisplayConfigState.getTransformLabel(root.outputData?.logical?.transform ?? "Normal");
|
||||||
return DisplayConfigState.getTransformLabel(data?.logical?.transform ?? "Normal");
|
|
||||||
}
|
}
|
||||||
options: [I18n.tr("Normal"), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")]
|
options: [I18n.tr("Normal"), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")]
|
||||||
onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value))
|
onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value))
|
||||||
|
|||||||
@@ -15,15 +15,13 @@ Item {
|
|||||||
property bool showNewProfileDialog: false
|
property bool showNewProfileDialog: false
|
||||||
property bool showDeleteConfirmDialog: false
|
property bool showDeleteConfirmDialog: false
|
||||||
property bool showRenameDialog: false
|
property bool showRenameDialog: false
|
||||||
|
property bool showEditMonitorsDialog: false
|
||||||
property string newProfileName: ""
|
property string newProfileName: ""
|
||||||
property string renameProfileName: ""
|
property string renameProfileName: ""
|
||||||
|
property var editMonitorSelection: ({})
|
||||||
|
|
||||||
function getProfileOptions() {
|
function getProfileOptions() {
|
||||||
const profiles = DisplayConfigState.validatedProfiles;
|
return Object.values(DisplayConfigState.validatedProfiles).filter(p => p.name !== "").map(p => p.name);
|
||||||
const options = [];
|
|
||||||
for (const id in profiles)
|
|
||||||
options.push(profiles[id].name);
|
|
||||||
return options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProfileIds() {
|
function getProfileIds() {
|
||||||
@@ -44,6 +42,13 @@ Item {
|
|||||||
return profiles[id]?.name || "";
|
return profiles[id]?.name || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openEditMonitorsDialog() {
|
||||||
|
if (!root.selectedProfileId)
|
||||||
|
return;
|
||||||
|
editMonitorSelection = DisplayConfigState.getProfileMonitorInclusion(root.selectedProfileId);
|
||||||
|
showEditMonitorsDialog = true;
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DisplayConfigState
|
target: DisplayConfigState
|
||||||
function onChangesApplied(changeDescriptions) {
|
function onChangesApplied(changeDescriptions) {
|
||||||
@@ -139,10 +144,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! TODO - auto profile switching is buggy on niri and other compositors
|
|
||||||
Column {
|
Column {
|
||||||
id: autoSelectColumn
|
id: autoSelectColumn
|
||||||
visible: false // disabled for now
|
visible: true
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -156,12 +160,12 @@ Item {
|
|||||||
|
|
||||||
DankToggle {
|
DankToggle {
|
||||||
id: autoSelectToggle
|
id: autoSelectToggle
|
||||||
checked: false // disabled for now
|
checked: SettingsData.displayProfileAutoSelect
|
||||||
enabled: false
|
|
||||||
onToggled: checked => {
|
onToggled: checked => {
|
||||||
// disabled for now
|
SettingsData.displayProfileAutoSelect = checked;
|
||||||
// SettingsData.displayProfileAutoSelect = checked;
|
SettingsData.saveSettings();
|
||||||
// SettingsData.saveSettings();
|
if (checked)
|
||||||
|
DisplayConfigState.applyAutoConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,16 +174,17 @@ Item {
|
|||||||
Row {
|
Row {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
visible: !root.showNewProfileDialog && !root.showDeleteConfirmDialog && !root.showRenameDialog
|
visible: !root.showNewProfileDialog && !root.showDeleteConfirmDialog && !root.showRenameDialog && !root.showEditMonitorsDialog
|
||||||
|
opacity: SettingsData.displayProfileAutoSelect ? 0.4 : 1.0
|
||||||
|
|
||||||
DankDropdown {
|
DankDropdown {
|
||||||
id: profileDropdown
|
id: profileDropdown
|
||||||
width: parent.width - newButton.width - deleteButton.width - Theme.spacingS * 2
|
width: parent.width - newButton.width - editMonitorsButton.width - deleteButton.width - Theme.spacingS * 3
|
||||||
compactMode: true
|
compactMode: true
|
||||||
dropdownWidth: width
|
dropdownWidth: width
|
||||||
options: root.getProfileOptions()
|
options: root.getProfileOptions()
|
||||||
currentValue: root.getProfileNameById(root.selectedProfileId)
|
|
||||||
emptyText: I18n.tr("No profiles")
|
emptyText: I18n.tr("No profiles")
|
||||||
|
enabled: !SettingsData.displayProfileAutoSelect
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
const profileId = root.getProfileIdByName(value);
|
const profileId = root.getProfileIdByName(value);
|
||||||
if (profileId && profileId !== root.selectedProfileId)
|
if (profileId && profileId !== root.selectedProfileId)
|
||||||
@@ -187,6 +192,12 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: profileDropdown
|
||||||
|
property: "currentValue"
|
||||||
|
value: SettingsData.displayProfileAutoSelect ? I18n.tr("Auto") : root.getProfileNameById(root.selectedProfileId)
|
||||||
|
}
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
id: newButton
|
id: newButton
|
||||||
iconName: "add"
|
iconName: "add"
|
||||||
@@ -195,12 +206,25 @@ Item {
|
|||||||
horizontalPadding: Theme.spacingM
|
horizontalPadding: Theme.spacingM
|
||||||
backgroundColor: Theme.surfaceContainer
|
backgroundColor: Theme.surfaceContainer
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
|
enabled: !SettingsData.displayProfileAutoSelect
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.newProfileName = "";
|
root.newProfileName = "";
|
||||||
root.showNewProfileDialog = true;
|
root.showNewProfileDialog = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
id: editMonitorsButton
|
||||||
|
iconName: "edit"
|
||||||
|
text: ""
|
||||||
|
buttonHeight: 40
|
||||||
|
horizontalPadding: Theme.spacingM
|
||||||
|
backgroundColor: Theme.surfaceContainer
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
enabled: root.selectedProfileId !== "" && !SettingsData.displayProfileAutoSelect
|
||||||
|
onClicked: root.openEditMonitorsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
id: deleteButton
|
id: deleteButton
|
||||||
iconName: "delete"
|
iconName: "delete"
|
||||||
@@ -209,7 +233,7 @@ Item {
|
|||||||
horizontalPadding: Theme.spacingM
|
horizontalPadding: Theme.spacingM
|
||||||
backgroundColor: Theme.surfaceContainer
|
backgroundColor: Theme.surfaceContainer
|
||||||
textColor: Theme.error
|
textColor: Theme.error
|
||||||
enabled: root.selectedProfileId !== ""
|
enabled: root.selectedProfileId !== "" && !SettingsData.displayProfileAutoSelect
|
||||||
onClicked: root.showDeleteConfirmDialog = true
|
onClicked: root.showDeleteConfirmDialog = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,23 +331,89 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
height: editMonitorsColumn.height + Theme.spacingM * 2
|
||||||
visible: DisplayConfigState.matchedProfile !== ""
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
visible: root.showEditMonitorsDialog
|
||||||
|
|
||||||
DankIcon {
|
Column {
|
||||||
name: "check_circle"
|
id: editMonitorsColumn
|
||||||
size: 16
|
anchors.centerIn: parent
|
||||||
color: Theme.success
|
width: parent.width - Theme.spacingM * 2
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
spacing: Theme.spacingS
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Matches profile: %1").arg(root.getProfileNameById(DisplayConfigState.matchedProfile))
|
text: I18n.tr("Monitors in \"%1\":").arg(root.getProfileNameById(root.selectedProfileId))
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.success
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Object.keys(DisplayConfigState.allOutputs || {})
|
||||||
|
delegate: Row {
|
||||||
|
required property string modelData
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankToggle {
|
||||||
|
id: monitorToggle
|
||||||
|
checked: root.editMonitorSelection[modelData] ?? false
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onToggled: checked => {
|
||||||
|
const sel = Object.assign({}, root.editMonitorSelection);
|
||||||
|
sel[modelData] = checked;
|
||||||
|
root.editMonitorSelection = sel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
const od = DisplayConfigState.allOutputs[modelData];
|
||||||
|
return DisplayConfigState.getOutputDisplayName(od, modelData);
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: DisplayConfigState.allOutputs[modelData]?.connected
|
||||||
|
? I18n.tr("Connected") : I18n.tr("Disconnected")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: DisplayConfigState.allOutputs[modelData]?.connected
|
||||||
|
? Theme.success : Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Save")
|
||||||
|
enabled: Object.values(root.editMonitorSelection).some(v => v)
|
||||||
|
onClicked: {
|
||||||
|
const enabled = Object.keys(root.editMonitorSelection).filter(k => root.editMonitorSelection[k]);
|
||||||
|
DisplayConfigState.updateProfileMonitors(root.selectedProfileId, enabled);
|
||||||
|
root.showEditMonitorsDialog = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Cancel")
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
onClicked: root.showEditMonitorsDialog = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,9 +297,12 @@ Singleton {
|
|||||||
return Array.from(visibleTags).sort((a, b) => a - b);
|
return Array.from(visibleTags).sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateOutputsConfig(outputsData) {
|
function generateOutputsConfig(outputsData, callback) {
|
||||||
if (!outputsData || Object.keys(outputsData).length === 0)
|
if (!outputsData || Object.keys(outputsData).length === 0) {
|
||||||
|
if (callback)
|
||||||
|
callback(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
let lines = ["# Auto-generated by DMS - do not edit manually", ""];
|
let lines = ["# Auto-generated by DMS - do not edit manually", ""];
|
||||||
|
|
||||||
for (const outputName in outputsData) {
|
for (const outputName in outputsData) {
|
||||||
@@ -336,11 +339,15 @@ Singleton {
|
|||||||
Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
log.warn("Failed to write outputs config:", output);
|
log.warn("Failed to write outputs config:", output);
|
||||||
|
if (callback)
|
||||||
|
callback(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Generated outputs config at", outputsPath);
|
log.info("Generated outputs config at", outputsPath);
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
|
if (callback)
|
||||||
|
callback(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,12 @@ Singleton {
|
|||||||
return outputName;
|
return outputName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateOutputsConfig(outputsData, hyprlandSettings) {
|
function generateOutputsConfig(outputsData, hyprlandSettings, callback) {
|
||||||
if (!outputsData || Object.keys(outputsData).length === 0)
|
if (!outputsData || Object.keys(outputsData).length === 0) {
|
||||||
|
if (callback)
|
||||||
|
callback(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const settings = hyprlandSettings || SettingsData.hyprlandOutputSettings;
|
const settings = hyprlandSettings || SettingsData.hyprlandOutputSettings;
|
||||||
let lines = ["# Auto-generated by DMS - do not edit manually", ""];
|
let lines = ["# Auto-generated by DMS - do not edit manually", ""];
|
||||||
@@ -162,11 +165,15 @@ Singleton {
|
|||||||
Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
log.warn("Failed to write outputs config:", output);
|
log.warn("Failed to write outputs config:", output);
|
||||||
|
if (callback)
|
||||||
|
callback(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Generated outputs config at", outputsPath);
|
log.info("Generated outputs config at", outputsPath);
|
||||||
if (CompositorService.isHyprland)
|
if (CompositorService.isHyprland)
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
|
if (callback)
|
||||||
|
callback(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user