1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-15 00:32:47 -04:00

Compare commits

..

3 Commits

Author SHA1 Message Date
bbedward 9673078a75 fix gui 2025-12-15 16:30:35 -05:00
bbedward 9e8c93bfd7 displays: fix hyprland config saving 2025-12-15 16:04:31 -05:00
bbedward 43d6f4b1d3 displays: add configurator (Beta)
- Position, resolution, refresh, orientation, VRR
- niri, Hyprland, MangoWC
- Rely on wlr-output for reading data, compositors to write output
  configurations
- Re-organize display setting group
2025-12-15 15:55:31 -05:00
12 changed files with 844 additions and 979 deletions
-5
View File
@@ -1,11 +1,6 @@
This file is more of a quick reference so I know what to account for before next releases.
# 1.2.0 # 1.2.0
- Added clipboard and clipboard history integration - Added clipboard and clipboard history integration
- Added swipe to dismiss notification popups and from center - Added swipe to dismiss notification popups and from center
- Added paste from clipboard history view - requires wtype - Added paste from clipboard history view - requires wtype
- Optimize surface damage of OSD & Toast - Optimize surface damage of OSD & Toast
- Add monitor configurator (niri, Hyprland, MangoWC)
- **BREAKING** ghostty theme changed to ~/.config/ghostty/themes/danktheme
- requires intervention and doc update
+1 -7
View File
@@ -265,13 +265,7 @@ func (cd *ConfigDeployer) deployGhosttyConfig() ([]DeploymentResult, error) {
colorResult := DeploymentResult{ colorResult := DeploymentResult{
ConfigType: "Ghostty Colors", ConfigType: "Ghostty Colors",
Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "themes", "dankcolors"), Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config-dankcolors"),
}
themesDir := filepath.Dir(colorResult.Path)
if err := os.MkdirAll(themesDir, 0755); err != nil {
mainResult.Error = fmt.Errorf("failed to create themes directory: %w", err)
return []DeploymentResult{mainResult}, mainResult.Error
} }
if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0644); err != nil { if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0644); err != nil {
+1 -1
View File
@@ -468,7 +468,7 @@ func TestHyprlandConfigStructure(t *testing.T) {
func TestGhosttyConfigStructure(t *testing.T) { func TestGhosttyConfigStructure(t *testing.T) {
assert.Contains(t, GhosttyConfig, "window-decoration = false") assert.Contains(t, GhosttyConfig, "window-decoration = false")
assert.Contains(t, GhosttyConfig, "background-opacity = 1.0") assert.Contains(t, GhosttyConfig, "background-opacity = 1.0")
assert.Contains(t, GhosttyConfig, "theme = dankcolors") assert.Contains(t, GhosttyConfig, "config-file = ./config-dankcolors")
} }
func TestGhosttyColorConfigStructure(t *testing.T) { func TestGhosttyColorConfigStructure(t *testing.T) {
+1 -1
View File
@@ -48,4 +48,4 @@ keybind = shift+enter=text:\n
gtk-single-instance = true gtk-single-instance = true
# Dank color generation # Dank color generation
theme = dankcolors config-file = ./config-dankcolors
+1 -2
View File
@@ -918,7 +918,6 @@ Singleton {
function buildMatugenColorsFromTheme(darkTheme, lightTheme) { function buildMatugenColorsFromTheme(darkTheme, lightTheme) {
const colors = {}; const colors = {};
const isLight = SessionData !== "undefined" && SessionData.isLightMode;
function addColor(matugenKey, darkVal, lightVal) { function addColor(matugenKey, darkVal, lightVal) {
if (!darkVal && !lightVal) if (!darkVal && !lightVal)
@@ -931,7 +930,7 @@ Singleton {
"color": String(lightVal || darkVal) "color": String(lightVal || darkVal)
}, },
"default": { "default": {
"color": String((isLight && lightVal) ? lightVal : darkVal) "color": String(darkVal || lightVal)
} }
}; };
} }
+20 -20
View File
@@ -24,26 +24,26 @@ DankModal {
repeat: true repeat: true
running: root.shouldBeVisible running: root.shouldBeVisible
onTriggered: { onTriggered: {
root.countdown--; root.countdown--
if (root.countdown <= 0) { if (root.countdown <= 0) {
root.reverted(); root.reverted()
root.close(); root.close()
} }
} }
} }
onOpened: { onOpened: {
countdown = 10; countdown = 10
countdownTimer.start(); countdownTimer.start()
} }
onDialogClosed: { onDialogClosed: {
countdownTimer.stop(); countdownTimer.stop()
} }
onBackgroundClicked: { onBackgroundClicked: {
root.reverted(); root.reverted()
root.close(); root.close()
} }
content: Component { content: Component {
@@ -55,15 +55,15 @@ DankModal {
implicitHeight: mainColumn.implicitHeight implicitHeight: mainColumn.implicitHeight
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
root.reverted(); root.reverted()
root.close(); root.close()
event.accepted = true; event.accepted = true
} }
Keys.onReturnPressed: event => { Keys.onReturnPressed: event => {
root.confirmed(); root.confirmed()
root.close(); root.close()
event.accepted = true; event.accepted = true
} }
Column { Column {
@@ -149,8 +149,8 @@ DankModal {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.reverted(); root.reverted()
root.close(); root.close()
} }
} }
} }
@@ -178,8 +178,8 @@ DankModal {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.confirmed(); root.confirmed()
root.close(); root.close()
} }
} }
@@ -203,8 +203,8 @@ DankModal {
iconSize: Theme.iconSize - 4 iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: { onClicked: {
root.reverted(); root.reverted()
root.close(); root.close()
} }
} }
} }
File diff suppressed because it is too large Load Diff
+122 -129
View File
@@ -9,110 +9,103 @@ Item {
id: root id: root
function getBarComponentsFromSettings() { function getBarComponentsFromSettings() {
const bars = SettingsData.barConfigs || []; const bars = SettingsData.barConfigs || []
return bars.map(bar => ({ return bars.map(bar => ({
"id": "bar:" + bar.id, "id": "bar:" + bar.id,
"name": bar.name || "Bar", "name": bar.name || "Bar",
"description": I18n.tr("Individual bar configuration"), "description": I18n.tr("Individual bar configuration"),
"icon": "toolbar", "icon": "toolbar",
"barId": bar.id "barId": bar.id
})); }))
} }
property var variantComponents: getVariantComponentsList() property var variantComponents: getVariantComponentsList()
function getVariantComponentsList() { function getVariantComponentsList() {
return [...getBarComponentsFromSettings(), return [...getBarComponentsFromSettings(), {
{ "id": "dock",
"id": "dock", "name": I18n.tr("Application Dock"),
"name": I18n.tr("Application Dock"), "description": I18n.tr("Bottom dock for pinned and running applications"),
"description": I18n.tr("Bottom dock for pinned and running applications"), "icon": "dock"
"icon": "dock" }, {
}, "id": "notifications",
{ "name": I18n.tr("Notification Popups"),
"id": "notifications", "description": I18n.tr("Notification toast popups"),
"name": I18n.tr("Notification Popups"), "icon": "notifications"
"description": I18n.tr("Notification toast popups"), }, {
"icon": "notifications" "id": "wallpaper",
}, "name": I18n.tr("Wallpaper"),
{ "description": I18n.tr("Desktop background images"),
"id": "wallpaper", "icon": "wallpaper"
"name": I18n.tr("Wallpaper"), }, {
"description": I18n.tr("Desktop background images"), "id": "osd",
"icon": "wallpaper" "name": I18n.tr("On-Screen Displays"),
}, "description": I18n.tr("Volume, brightness, and other system OSDs"),
{ "icon": "picture_in_picture"
"id": "osd", }, {
"name": I18n.tr("On-Screen Displays"), "id": "toast",
"description": I18n.tr("Volume, brightness, and other system OSDs"), "name": I18n.tr("Toast Messages"),
"icon": "picture_in_picture" "description": I18n.tr("System toast notifications"),
}, "icon": "campaign"
{ }, {
"id": "toast", "id": "notepad",
"name": I18n.tr("Toast Messages"), "name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("System toast notifications"), "description": I18n.tr("Quick note-taking slideout panel"),
"icon": "campaign" "icon": "sticky_note_2"
}, }]
{
"id": "notepad",
"name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("Quick note-taking slideout panel"),
"icon": "sticky_note_2"
}
];
} }
Connections { Connections {
target: SettingsData target: SettingsData
function onBarConfigsChanged() { function onBarConfigsChanged() {
variantComponents = getVariantComponentsList(); variantComponents = getVariantComponentsList()
} }
} }
function getScreenPreferences(componentId) { function getScreenPreferences(componentId) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4); const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId); const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.screenPreferences || ["all"]; return barConfig?.screenPreferences || ["all"]
} }
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]; return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]
} }
function setScreenPreferences(componentId, screenNames) { function setScreenPreferences(componentId, screenNames) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4); const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { SettingsData.updateBarConfig(barId, {
"screenPreferences": screenNames "screenPreferences": screenNames
}); })
return; return
} }
var prefs = SettingsData.screenPreferences || {}; var prefs = SettingsData.screenPreferences || {}
var newPrefs = Object.assign({}, prefs); var newPrefs = Object.assign({}, prefs)
newPrefs[componentId] = screenNames; newPrefs[componentId] = screenNames
SettingsData.set("screenPreferences", newPrefs); SettingsData.set("screenPreferences", newPrefs)
} }
function getShowOnLastDisplay(componentId) { function getShowOnLastDisplay(componentId) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4); const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId); const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.showOnLastDisplay ?? true; return barConfig?.showOnLastDisplay ?? true
} }
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false; return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false
} }
function setShowOnLastDisplay(componentId, enabled) { function setShowOnLastDisplay(componentId, enabled) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4); const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { SettingsData.updateBarConfig(barId, {
"showOnLastDisplay": enabled "showOnLastDisplay": enabled
}); })
return; return
} }
var prefs = SettingsData.showOnLastDisplay || {}; var prefs = SettingsData.showOnLastDisplay || {}
var newPrefs = Object.assign({}, prefs); var newPrefs = Object.assign({}, prefs)
newPrefs[componentId] = enabled; newPrefs[componentId] = enabled
SettingsData.set("showOnLastDisplay", newPrefs); SettingsData.set("showOnLastDisplay", newPrefs)
} }
DankFlickable { DankFlickable {
@@ -217,16 +210,16 @@ Item {
model: [I18n.tr("Name"), I18n.tr("Model")] model: [I18n.tr("Name"), I18n.tr("Model")]
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
onSelectionChanged: (index, selected) => { onSelectionChanged: (index, selected) => {
if (!selected) if (!selected)
return; return
SettingsData.displayNameMode = index === 1 ? "model" : "system"; SettingsData.displayNameMode = index === 1 ? "model" : "system"
SettingsData.saveSettings(); SettingsData.saveSettings()
} }
Connections { Connections {
target: SettingsData target: SettingsData
function onDisplayNameModeChanged() { function onDisplayNameModeChanged() {
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0; displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0
} }
} }
} }
@@ -280,9 +273,9 @@ Item {
StyledText { StyledText {
text: { text: {
if (parent.currentMode) { if (parent.currentMode) {
return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz"; return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz"
} }
return modelData.width + "×" + modelData.height; return modelData.width + "×" + modelData.height
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
@@ -385,20 +378,20 @@ Item {
text: I18n.tr("All displays") text: I18n.tr("All displays")
description: I18n.tr("Show on all connected displays") description: I18n.tr("Show on all connected displays")
checked: { checked: {
var prefs = root.getScreenPreferences(parent.componentId); var prefs = root.getScreenPreferences(parent.componentId)
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
} }
onToggled: checked => { onToggled: checked => {
if (checked) { if (checked) {
root.setScreenPreferences(parent.componentId, ["all"]); root.setScreenPreferences(parent.componentId, ["all"])
} else { } else {
root.setScreenPreferences(parent.componentId, []); root.setScreenPreferences(parent.componentId, [])
const cid = parent.componentId; const cid = parent.componentId
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) { if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
root.setShowOnLastDisplay(cid, true); root.setShowOnLastDisplay(cid, true)
} }
} }
} }
} }
DankToggle { DankToggle {
@@ -407,15 +400,15 @@ Item {
description: I18n.tr("Always show when there's only one connected display") description: I18n.tr("Always show when there's only one connected display")
checked: root.getShowOnLastDisplay(parent.componentId) checked: root.getShowOnLastDisplay(parent.componentId)
visible: { visible: {
const prefs = root.getScreenPreferences(parent.componentId); const prefs = root.getScreenPreferences(parent.componentId)
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
const cid = parent.componentId; const cid = parent.componentId
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:"); const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:")
return !isAll && isRelevantComponent; return !isAll && isRelevantComponent
} }
onToggled: checked => { onToggled: checked => {
root.setShowOnLastDisplay(parent.componentId, checked); root.setShowOnLastDisplay(parent.componentId, checked)
} }
} }
Rectangle { Rectangle {
@@ -424,8 +417,8 @@ Item {
color: Theme.outline color: Theme.outline
opacity: 0.2 opacity: 0.2
visible: { visible: {
var prefs = root.getScreenPreferences(parent.componentId); var prefs = root.getScreenPreferences(parent.componentId)
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
} }
} }
@@ -433,8 +426,8 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: { visible: {
var prefs = root.getScreenPreferences(parent.componentId); var prefs = root.getScreenPreferences(parent.componentId)
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
} }
Repeater { Repeater {
@@ -448,41 +441,41 @@ Item {
text: SettingsData.getScreenDisplayName(screenData) text: SettingsData.getScreenDisplayName(screenData)
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name) description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
checked: { checked: {
var prefs = root.getScreenPreferences(componentId); var prefs = root.getScreenPreferences(componentId)
if (typeof prefs[0] === "string" && prefs[0] === "all") if (typeof prefs[0] === "string" && prefs[0] === "all")
return false; return false
return SettingsData.isScreenInPreferences(screenData, prefs); return SettingsData.isScreenInPreferences(screenData, prefs)
} }
onToggled: checked => { onToggled: checked => {
var currentPrefs = root.getScreenPreferences(componentId); var currentPrefs = root.getScreenPreferences(componentId)
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") { if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
currentPrefs = []; currentPrefs = []
} }
const screenModelIndex = SettingsData.getScreenModelIndex(screenData); const screenModelIndex = SettingsData.getScreenModelIndex(screenData)
var newPrefs = currentPrefs.filter(pref => { var newPrefs = currentPrefs.filter(pref => {
if (typeof pref === "string") if (typeof pref === "string")
return false; return false
if (pref.modelIndex !== undefined && screenModelIndex >= 0) { if (pref.modelIndex !== undefined && screenModelIndex >= 0) {
return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex); return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex)
} }
return pref.name !== screenData.name || pref.model !== screenData.model; return pref.name !== screenData.name || pref.model !== screenData.model
}); })
if (checked) { if (checked) {
const prefObj = { const prefObj = {
"name": screenData.name, "name": screenData.name,
"model": screenData.model || "" "model": screenData.model || ""
}; }
if (screenModelIndex >= 0) { if (screenModelIndex >= 0) {
prefObj.modelIndex = screenModelIndex; prefObj.modelIndex = screenModelIndex
} }
newPrefs.push(prefObj); newPrefs.push(prefObj)
} }
root.setScreenPreferences(componentId, newPrefs); root.setScreenPreferences(componentId, newPrefs)
} }
} }
} }
} }
+76 -76
View File
@@ -1,4 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -8,14 +10,14 @@ Item {
function formatGammaTime(isoString) { function formatGammaTime(isoString) {
if (!isoString) if (!isoString)
return ""; return ""
try { try {
const date = new Date(isoString); const date = new Date(isoString)
if (isNaN(date.getTime())) if (isNaN(date.getTime()))
return ""; return ""
return date.toLocaleTimeString(Qt.locale(), "HH:mm"); return date.toLocaleTimeString(Qt.locale(), "HH:mm")
} catch (e) { } catch (e) {
return ""; return ""
} }
} }
@@ -72,16 +74,17 @@ Item {
width: parent.width width: parent.width
text: I18n.tr("Night Mode") text: I18n.tr("Night Mode")
description: DisplayService.gammaControlAvailable ? I18n.tr("Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.") : I18n.tr("Gamma control not available. Requires DMS API v6+.") description: DisplayService.gammaControlAvailable ? I18n.tr("Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.") : I18n.tr(
"Gamma control not available. Requires DMS API v6+.")
checked: DisplayService.nightModeEnabled checked: DisplayService.nightModeEnabled
enabled: DisplayService.gammaControlAvailable enabled: DisplayService.gammaControlAvailable
onToggled: checked => { onToggled: checked => {
DisplayService.toggleNightMode(); DisplayService.toggleNightMode()
} }
Connections { Connections {
function onNightModeEnabledChanged() { function onNightModeEnabledChanged() {
nightModeToggle.checked = DisplayService.nightModeEnabled; nightModeToggle.checked = DisplayService.nightModeEnabled
} }
target: DisplayService target: DisplayService
@@ -101,19 +104,19 @@ Item {
description: SessionData.nightModeAutoEnabled ? I18n.tr("Color temperature for night mode") : I18n.tr("Warm color temperature to apply") description: SessionData.nightModeAutoEnabled ? I18n.tr("Color temperature for night mode") : I18n.tr("Warm color temperature to apply")
currentValue: SessionData.nightModeTemperature + "K" currentValue: SessionData.nightModeTemperature + "K"
options: { options: {
var temps = []; var temps = []
for (var i = 2500; i <= 6000; i += 500) { for (var i = 2500; i <= 6000; i += 500) {
temps.push(i + "K"); temps.push(i + "K")
} }
return temps; return temps
} }
onValueChanged: value => { onValueChanged: value => {
var temp = parseInt(value.replace("K", "")); var temp = parseInt(value.replace("K", ""))
SessionData.setNightModeTemperature(temp); SessionData.setNightModeTemperature(temp)
if (SessionData.nightModeHighTemperature < temp) { if (SessionData.nightModeHighTemperature < temp) {
SessionData.setNightModeHighTemperature(temp); SessionData.setNightModeHighTemperature(temp)
} }
} }
} }
DankDropdown { DankDropdown {
@@ -123,19 +126,19 @@ Item {
currentValue: SessionData.nightModeHighTemperature + "K" currentValue: SessionData.nightModeHighTemperature + "K"
visible: SessionData.nightModeAutoEnabled visible: SessionData.nightModeAutoEnabled
options: { options: {
var temps = []; var temps = []
var minTemp = SessionData.nightModeTemperature; var minTemp = SessionData.nightModeTemperature
for (var i = Math.max(2500, minTemp); i <= 10000; i += 500) { for (var i = Math.max(2500, minTemp); i <= 10000; i += 500) {
temps.push(i + "K"); temps.push(i + "K")
} }
return temps; return temps
} }
onValueChanged: value => { onValueChanged: value => {
var temp = parseInt(value.replace("K", "")); var temp = parseInt(value.replace("K", ""))
if (temp >= SessionData.nightModeTemperature) { if (temp >= SessionData.nightModeTemperature) {
SessionData.setNightModeHighTemperature(temp); SessionData.setNightModeHighTemperature(temp)
} }
} }
} }
} }
@@ -147,18 +150,18 @@ Item {
checked: SessionData.nightModeAutoEnabled checked: SessionData.nightModeAutoEnabled
visible: DisplayService.gammaControlAvailable visible: DisplayService.gammaControlAvailable
onToggled: checked => { onToggled: checked => {
if (checked && !DisplayService.nightModeEnabled) { if (checked && !DisplayService.nightModeEnabled) {
DisplayService.toggleNightMode(); DisplayService.toggleNightMode()
} else if (!checked && DisplayService.nightModeEnabled) { } else if (!checked && DisplayService.nightModeEnabled) {
DisplayService.toggleNightMode(); DisplayService.toggleNightMode()
} }
SessionData.setNightModeAutoEnabled(checked); SessionData.setNightModeAutoEnabled(checked)
} }
Connections { Connections {
target: SessionData target: SessionData
function onNightModeAutoEnabledChanged() { function onNightModeAutoEnabledChanged() {
automaticToggle.checked = SessionData.nightModeAutoEnabled; automaticToggle.checked = SessionData.nightModeAutoEnabled
} }
} }
} }
@@ -172,7 +175,7 @@ Item {
Connections { Connections {
target: SessionData target: SessionData
function onNightModeAutoEnabledChanged() { function onNightModeAutoEnabledChanged() {
automaticSettings.visible = SessionData.nightModeAutoEnabled; automaticSettings.visible = SessionData.nightModeAutoEnabled
} }
} }
@@ -185,32 +188,29 @@ Item {
width: 200 width: 200
height: 45 height: 45
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
model: [ model: [{
{
"text": "Time", "text": "Time",
"icon": "access_time" "icon": "access_time"
}, }, {
{
"text": "Location", "text": "Location",
"icon": "place" "icon": "place"
} }]
]
Component.onCompleted: { Component.onCompleted: {
currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
Qt.callLater(updateIndicator); Qt.callLater(updateIndicator)
} }
onTabClicked: index => { onTabClicked: index => {
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time"); DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time")
currentIndex = index; currentIndex = index
} }
Connections { Connections {
target: SessionData target: SessionData
function onNightModeAutoModeChanged() { function onNightModeAutoModeChanged() {
modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
Qt.callLater(modeTabBarNight.updateIndicator); Qt.callLater(modeTabBarNight.updateIndicator)
} }
} }
} }
@@ -267,30 +267,30 @@ Item {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeStartHour.toString() currentValue: SessionData.nightModeStartHour.toString()
options: { options: {
var hours = []; var hours = []
for (var i = 0; i < 24; i++) { for (var i = 0; i < 24; i++) {
hours.push(i.toString()); hours.push(i.toString())
} }
return hours; return hours
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeStartHour(parseInt(value)); SessionData.setNightModeStartHour(parseInt(value))
} }
} }
DankDropdown { DankDropdown {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0') currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0')
options: { options: {
var minutes = []; var minutes = []
for (var i = 0; i < 60; i += 5) { for (var i = 0; i < 60; i += 5) {
minutes.push(i.toString().padStart(2, '0')); minutes.push(i.toString().padStart(2, '0'))
} }
return minutes; return minutes
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeStartMinute(parseInt(value)); SessionData.setNightModeStartMinute(parseInt(value))
} }
} }
} }
@@ -310,30 +310,30 @@ Item {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeEndHour.toString() currentValue: SessionData.nightModeEndHour.toString()
options: { options: {
var hours = []; var hours = []
for (var i = 0; i < 24; i++) { for (var i = 0; i < 24; i++) {
hours.push(i.toString()); hours.push(i.toString())
} }
return hours; return hours
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeEndHour(parseInt(value)); SessionData.setNightModeEndHour(parseInt(value))
} }
} }
DankDropdown { DankDropdown {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0') currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0')
options: { options: {
var minutes = []; var minutes = []
for (var i = 0; i < 60; i += 5) { for (var i = 0; i < 60; i += 5) {
minutes.push(i.toString().padStart(2, '0')); minutes.push(i.toString().padStart(2, '0'))
} }
return minutes; return minutes
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeEndMinute(parseInt(value)); SessionData.setNightModeEndMinute(parseInt(value))
} }
} }
} }
} }
@@ -352,13 +352,13 @@ Item {
description: I18n.tr("Automatically detect location based on IP address") description: I18n.tr("Automatically detect location based on IP address")
checked: SessionData.nightModeUseIPLocation || false checked: SessionData.nightModeUseIPLocation || false
onToggled: checked => { onToggled: checked => {
SessionData.setNightModeUseIPLocation(checked); SessionData.setNightModeUseIPLocation(checked)
} }
Connections { Connections {
target: SessionData target: SessionData
function onNightModeUseIPLocationChanged() { function onNightModeUseIPLocationChanged() {
ipLocationToggle.checked = SessionData.nightModeUseIPLocation; ipLocationToggle.checked = SessionData.nightModeUseIPLocation
} }
} }
} }
@@ -393,9 +393,9 @@ Item {
text: SessionData.latitude.toString() text: SessionData.latitude.toString()
placeholderText: "0.0" placeholderText: "0.0"
onEditingFinished: { onEditingFinished: {
const lat = parseFloat(text); const lat = parseFloat(text)
if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) {
SessionData.setLatitude(lat); SessionData.setLatitude(lat)
} }
} }
} }
@@ -416,9 +416,9 @@ Item {
text: SessionData.longitude.toString() text: SessionData.longitude.toString()
placeholderText: "0.0" placeholderText: "0.0"
onEditingFinished: { onEditingFinished: {
const lon = parseFloat(text); const lon = parseFloat(text)
if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) {
SessionData.setLongitude(lon); SessionData.setLongitude(lon)
} }
} }
} }
+49 -44
View File
@@ -272,77 +272,82 @@ Singleton {
function generateOutputsConfig(outputsData) { function generateOutputsConfig(outputsData) {
if (!outputsData || Object.keys(outputsData).length === 0) if (!outputsData || Object.keys(outputsData).length === 0)
return; return
let lines = ["# Auto-generated by DMS - do not edit manually", "# VRR is global: set adaptive_sync=1 in config.conf", ""];
let lines = ["# Auto-generated by DMS - do not edit manually", "# VRR is global: set adaptive_sync=1 in config.conf", ""]
for (const outputName in outputsData) { for (const outputName in outputsData) {
const output = outputsData[outputName]; const output = outputsData[outputName]
if (!output) if (!output)
continue; continue
let width = 1920;
let height = 1080; let width = 1920
let refreshRate = 60; let height = 1080
let refreshRate = 60
if (output.modes && output.current_mode !== undefined) { if (output.modes && output.current_mode !== undefined) {
const mode = output.modes[output.current_mode]; const mode = output.modes[output.current_mode]
if (mode) { if (mode) {
width = mode.width || 1920; width = mode.width || 1920
height = mode.height || 1080; height = mode.height || 1080
refreshRate = Math.round((mode.refresh_rate || 60000) / 1000); refreshRate = Math.round((mode.refresh_rate || 60000) / 1000)
} }
} }
const x = output.logical?.x ?? 0; const x = output.logical?.x ?? 0
const y = output.logical?.y ?? 0; const y = output.logical?.y ?? 0
const scale = output.logical?.scale ?? 1.0; const scale = output.logical?.scale ?? 1.0
const transform = transformToMango(output.logical?.transform ?? "Normal"); const transform = transformToMango(output.logical?.transform ?? "Normal")
const rule = [outputName, "0.55", "1", "tile", transform, scale, x, y, width, height, refreshRate].join(","); const rule = [
outputName,
"0.55",
"1",
"tile",
transform,
scale,
x,
y,
width,
height,
refreshRate
].join(",")
lines.push("monitorrule=" + rule); lines.push("monitorrule=" + rule)
} }
lines.push(""); lines.push("")
const content = lines.join("\n"); const content = lines.join("\n")
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) {
console.warn("DwlService: Failed to write outputs config:", output); console.warn("DwlService: Failed to write outputs config:", output)
return; return
} }
console.info("DwlService: Generated outputs config at", outputsPath); console.info("DwlService: Generated outputs config at", outputsPath)
if (CompositorService.isDwl) if (CompositorService.isDwl)
reloadConfig(); reloadConfig()
}); })
} }
function reloadConfig() { function reloadConfig() {
Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => { Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("DwlService: mmsg reload_config failed:", output); console.warn("DwlService: mmsg reload_config failed:", output)
}); })
} }
function transformToMango(transform) { function transformToMango(transform) {
switch (transform) { switch (transform) {
case "Normal": case "Normal": return 0
return 0; case "90": return 1
case "90": case "180": return 2
return 1; case "270": return 3
case "180": case "Flipped": return 4
return 2; case "Flipped90": return 5
case "270": case "Flipped180": return 6
return 3; case "Flipped270": return 7
case "Flipped": default: return 0
return 4;
case "Flipped90":
return 5;
case "Flipped180":
return 6;
case "Flipped270":
return 7;
default:
return 0;
} }
} }
} }
+49 -64
View File
@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
import QtCore import QtCore
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland
import qs.Common import qs.Common
Singleton { Singleton {
@@ -15,111 +16,95 @@ Singleton {
function getOutputIdentifier(output, outputName) { function getOutputIdentifier(output, outputName) {
if (SettingsData.displayNameMode === "model" && output.make && output.model) { if (SettingsData.displayNameMode === "model" && output.make && output.model) {
return "desc:" + output.make + " " + output.model; return "desc:" + output.make + " " + output.model
} }
return outputName; return outputName
} }
function generateOutputsConfig(outputsData) { function generateOutputsConfig(outputsData) {
if (!outputsData || Object.keys(outputsData).length === 0) if (!outputsData || Object.keys(outputsData).length === 0)
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) {
const output = outputsData[outputName]; const output = outputsData[outputName]
if (!output) if (!output)
continue; continue
let resolution = "preferred";
let resolution = "preferred"
if (output.modes && output.current_mode !== undefined) { if (output.modes && output.current_mode !== undefined) {
const mode = output.modes[output.current_mode]; const mode = output.modes[output.current_mode]
if (mode) if (mode)
resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3); resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3)
} }
const x = output.logical?.x ?? 0; const x = output.logical?.x ?? 0
const y = output.logical?.y ?? 0; const y = output.logical?.y ?? 0
const position = x + "x" + y; const position = x + "x" + y
const scale = output.logical?.scale ?? 1.0; const scale = output.logical?.scale ?? 1.0
const identifier = getOutputIdentifier(output, outputName); const identifier = getOutputIdentifier(output, outputName)
let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale; let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale
const transform = transformToHyprland(output.logical?.transform ?? "Normal"); const transform = transformToHyprland(output.logical?.transform ?? "Normal")
if (transform !== 0) if (transform !== 0)
monitorLine += ", transform, " + transform; monitorLine += ", transform, " + transform
if (output.vrr_supported && output.vrr_enabled) if (output.vrr_supported && output.vrr_enabled)
monitorLine += ", vrr, 1"; monitorLine += ", vrr, 1"
lines.push(monitorLine); lines.push(monitorLine)
} }
lines.push(""); lines.push("")
const content = lines.join("\n"); const content = lines.join("\n")
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) {
console.warn("HyprlandService: Failed to write outputs config:", output); console.warn("HyprlandService: Failed to write outputs config:", output)
return; return
} }
console.info("HyprlandService: Generated outputs config at", outputsPath); console.info("HyprlandService: Generated outputs config at", outputsPath)
if (CompositorService.isHyprland) if (CompositorService.isHyprland)
reloadConfig(); reloadConfig()
}); })
} }
function reloadConfig() { function reloadConfig() {
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => { Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: hyprctl reload failed:", output); console.warn("HyprlandService: hyprctl reload failed:", output)
}); })
} }
function transformToHyprland(transform) { function transformToHyprland(transform) {
switch (transform) { switch (transform) {
case "Normal": case "Normal": return 0
return 0; case "90": return 1
case "90": case "180": return 2
return 1; case "270": return 3
case "180": case "Flipped": return 4
return 2; case "Flipped90": return 5
case "270": case "Flipped180": return 6
return 3; case "Flipped270": return 7
case "Flipped": default: return 0
return 4;
case "Flipped90":
return 5;
case "Flipped180":
return 6;
case "Flipped270":
return 7;
default:
return 0;
} }
} }
function hyprlandToTransform(value) { function hyprlandToTransform(value) {
switch (value) { switch (value) {
case 0: case 0: return "Normal"
return "Normal"; case 1: return "90"
case 1: case 2: return "180"
return "90"; case 3: return "270"
case 2: case 4: return "Flipped"
return "180"; case 5: return "Flipped90"
case 3: case 6: return "Flipped180"
return "270"; case 7: return "Flipped270"
case 4: default: return "Normal"
return "Flipped";
case 5:
return "Flipped90";
case 6:
return "Flipped180";
case 7:
return "Flipped270";
default:
return "Normal";
} }
} }
} }
+1 -1
View File
@@ -1,3 +1,3 @@
[templates.dmsghostty] [templates.dmsghostty]
input_path = 'SHELL_DIR/matugen/templates/ghostty.conf' input_path = 'SHELL_DIR/matugen/templates/ghostty.conf'
output_path = '~/.config/ghostty/themes/dankcolors' output_path = '~/.config/ghostty/config-dankcolors'