mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
Compare commits
3 Commits
03cfa55e0b
...
displaycon
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9673078a75 | ||
|
|
9e8c93bfd7 | ||
|
|
43d6f4b1d3 |
@@ -238,7 +238,7 @@ func (i *ZwlrOutputManagerV1) Dispatch(opcode uint32, fd int, data []byte) {
|
|||||||
l := 0
|
l := 0
|
||||||
objectID := client.Uint32(data[l : l+4])
|
objectID := client.Uint32(data[l : l+4])
|
||||||
proxy := i.Context().GetProxy(objectID)
|
proxy := i.Context().GetProxy(objectID)
|
||||||
if proxy == nil {
|
if proxy == nil || proxy.IsZombie() {
|
||||||
head := &ZwlrOutputHeadV1{}
|
head := &ZwlrOutputHeadV1{}
|
||||||
head.SetContext(i.Context())
|
head.SetContext(i.Context())
|
||||||
head.SetID(objectID)
|
head.SetID(objectID)
|
||||||
@@ -723,7 +723,7 @@ func (i *ZwlrOutputHeadV1) Dispatch(opcode uint32, fd int, data []byte) {
|
|||||||
l := 0
|
l := 0
|
||||||
objectID := client.Uint32(data[l : l+4])
|
objectID := client.Uint32(data[l : l+4])
|
||||||
proxy := i.Context().GetProxy(objectID)
|
proxy := i.Context().GetProxy(objectID)
|
||||||
if proxy == nil {
|
if proxy == nil || proxy.IsZombie() {
|
||||||
mode := &ZwlrOutputModeV1{}
|
mode := &ZwlrOutputModeV1{}
|
||||||
mode.SetContext(i.Context())
|
mode.SetContext(i.Context())
|
||||||
mode.SetID(objectID)
|
mode.SetID(objectID)
|
||||||
@@ -761,8 +761,8 @@ func (i *ZwlrOutputHeadV1) Dispatch(opcode uint32, fd int, data []byte) {
|
|||||||
l := 0
|
l := 0
|
||||||
objectID := client.Uint32(data[l : l+4])
|
objectID := client.Uint32(data[l : l+4])
|
||||||
proxy := i.Context().GetProxy(objectID)
|
proxy := i.Context().GetProxy(objectID)
|
||||||
if proxy == nil {
|
if proxy == nil || proxy.IsZombie() {
|
||||||
// Mode not yet registered, create it
|
// Mode not yet registered or zombie, create fresh
|
||||||
mode := &ZwlrOutputModeV1{}
|
mode := &ZwlrOutputModeV1{}
|
||||||
mode.SetContext(i.Context())
|
mode.SetContext(i.Context())
|
||||||
mode.SetID(objectID)
|
mode.SetID(objectID)
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ func (m *Manager) handleHead(e wlr_output_management.ZwlrOutputManagerV1HeadEven
|
|||||||
handle.SetNameHandler(func(e wlr_output_management.ZwlrOutputHeadV1NameEvent) {
|
handle.SetNameHandler(func(e wlr_output_management.ZwlrOutputHeadV1NameEvent) {
|
||||||
log.Debugf("WlrOutput: Head %d name: %s", headID, e.Name)
|
log.Debugf("WlrOutput: Head %d name: %s", headID, e.Name)
|
||||||
head.name = e.Name
|
head.name = e.Name
|
||||||
|
head.ready = true
|
||||||
m.post(func() {
|
m.post(func() {
|
||||||
m.updateState()
|
m.updateState()
|
||||||
})
|
})
|
||||||
@@ -251,11 +252,11 @@ func (m *Manager) handleHead(e wlr_output_management.ZwlrOutputManagerV1HeadEven
|
|||||||
|
|
||||||
m.heads.Delete(headID)
|
m.heads.Delete(headID)
|
||||||
|
|
||||||
m.post(func() {
|
m.wlMutex.Lock()
|
||||||
m.wlMutex.Lock()
|
handle.Release()
|
||||||
handle.Release()
|
m.wlMutex.Unlock()
|
||||||
m.wlMutex.Unlock()
|
|
||||||
|
|
||||||
|
m.post(func() {
|
||||||
m.updateState()
|
m.updateState()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -310,11 +311,11 @@ func (m *Manager) handleMode(headID uint32, e wlr_output_management.ZwlrOutputHe
|
|||||||
|
|
||||||
m.modes.Delete(modeID)
|
m.modes.Delete(modeID)
|
||||||
|
|
||||||
m.post(func() {
|
m.wlMutex.Lock()
|
||||||
m.wlMutex.Lock()
|
handle.Release()
|
||||||
handle.Release()
|
m.wlMutex.Unlock()
|
||||||
m.wlMutex.Unlock()
|
|
||||||
|
|
||||||
|
m.post(func() {
|
||||||
m.updateState()
|
m.updateState()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -328,6 +329,10 @@ func (m *Manager) updateState() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !head.ready {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
modes := make([]OutputMode, 0)
|
modes := make([]OutputMode, 0)
|
||||||
var currentMode *OutputMode
|
var currentMode *OutputMode
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ type headState struct {
|
|||||||
modeIDs []uint32
|
modeIDs []uint32
|
||||||
adaptiveSync uint32
|
adaptiveSync uint32
|
||||||
finished bool
|
finished bool
|
||||||
|
ready bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type modeState struct {
|
type modeState struct {
|
||||||
|
|||||||
@@ -273,8 +273,8 @@ Item {
|
|||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
top: true
|
top: true
|
||||||
right: root.useSingleWindow ? true : undefined
|
right: root.useSingleWindow
|
||||||
bottom: root.useSingleWindow ? true : undefined
|
bottom: root.useSingleWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
WlrLayershell.margins {
|
WlrLayershell.margins {
|
||||||
@@ -284,8 +284,8 @@ Item {
|
|||||||
bottom: 0
|
bottom: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitWidth: root.useSingleWindow ? undefined : root.alignedWidth + (shadowBuffer * 2)
|
implicitWidth: root.useSingleWindow ? 0 : root.alignedWidth + (shadowBuffer * 2)
|
||||||
implicitHeight: root.useSingleWindow ? undefined : root.alignedHeight + (shadowBuffer * 2)
|
implicitHeight: root.useSingleWindow ? 0 : root.alignedHeight + (shadowBuffer * 2)
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ DankModal {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string outputName: ""
|
property string outputName: ""
|
||||||
property var position: undefined
|
property var changes: []
|
||||||
property var mode: undefined
|
property int countdown: 10
|
||||||
property var vrr: undefined
|
|
||||||
property int countdown: 15
|
signal confirmed
|
||||||
|
signal reverted
|
||||||
|
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
allowStacking: true
|
allowStacking: true
|
||||||
@@ -23,23 +24,27 @@ DankModal {
|
|||||||
repeat: true
|
repeat: true
|
||||||
running: root.shouldBeVisible
|
running: root.shouldBeVisible
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
countdown--;
|
root.countdown--
|
||||||
if (countdown <= 0) {
|
if (root.countdown <= 0) {
|
||||||
revert();
|
root.reverted()
|
||||||
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
countdown = 15;
|
countdown = 10
|
||||||
countdownTimer.start();
|
countdownTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosed: {
|
onDialogClosed: {
|
||||||
countdownTimer.stop();
|
countdownTimer.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackgroundClicked: revert
|
onBackgroundClicked: {
|
||||||
|
root.reverted()
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
|
||||||
content: Component {
|
content: Component {
|
||||||
FocusScope {
|
FocusScope {
|
||||||
@@ -50,13 +55,15 @@ DankModal {
|
|||||||
implicitHeight: mainColumn.implicitHeight
|
implicitHeight: mainColumn.implicitHeight
|
||||||
|
|
||||||
Keys.onEscapePressed: event => {
|
Keys.onEscapePressed: event => {
|
||||||
revert();
|
root.reverted()
|
||||||
event.accepted = true;
|
root.close()
|
||||||
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onReturnPressed: event => {
|
Keys.onReturnPressed: event => {
|
||||||
confirm();
|
root.confirmed()
|
||||||
event.accepted = true;
|
root.close()
|
||||||
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -69,81 +76,42 @@ DankModal {
|
|||||||
anchors.topMargin: Theme.spacingM
|
anchors.topMargin: Theme.spacingM
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
width: parent.width
|
text: I18n.tr("Confirm Display Changes")
|
||||||
spacing: Theme.spacingXS
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
StyledText {
|
font.weight: Font.Medium
|
||||||
text: I18n.tr("Confirm Display Changes")
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Display settings for ") + outputName
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceTextMedium
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 80
|
height: 70
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceContainerHighest
|
color: Theme.surfaceContainerHighest
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 4
|
text: root.countdown + "s"
|
||||||
|
font.pixelSize: Theme.fontSizeXLarge * 1.5
|
||||||
StyledText {
|
color: Theme.primary
|
||||||
text: I18n.tr("Reverting in:")
|
font.weight: Font.Bold
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceTextMedium
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: countdown + "s"
|
|
||||||
font.pixelSize: Theme.fontSizeXLarge * 1.5
|
|
||||||
color: Theme.primary
|
|
||||||
font.weight: Font.Bold
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
visible: root.changes.length > 0
|
||||||
|
|
||||||
StyledText {
|
Repeater {
|
||||||
text: I18n.tr("Changes:")
|
model: root.changes
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceTextMedium
|
|
||||||
font.weight: Font.Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
visible: position !== undefined && position !== null
|
required property var modelData
|
||||||
text: I18n.tr("Position: ") + (position ? position.x + ", " + position.y : "")
|
text: modelData
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: mode !== undefined && mode !== null && mode !== ""
|
|
||||||
text: I18n.tr("Mode: ") + (mode || "")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: vrr !== undefined && vrr !== null
|
|
||||||
text: I18n.tr("VRR: ") + (vrr ? I18n.tr("Enabled") : I18n.tr("Disabled"))
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +148,10 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: revert
|
onClicked: {
|
||||||
|
root.reverted()
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +177,10 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: confirm
|
onClicked: {
|
||||||
|
root.confirmed()
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
@@ -228,18 +202,11 @@ DankModal {
|
|||||||
iconName: "close"
|
iconName: "close"
|
||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
onClicked: revert
|
onClicked: {
|
||||||
|
root.reverted()
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirm() {
|
|
||||||
displaysTab.confirmChanges();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
function revert() {
|
|
||||||
displaysTab.revertChanges();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,13 +125,45 @@ FocusScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: displaysLoader
|
id: displayConfigLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: root.currentIndex === 6
|
active: root.currentIndex === 24
|
||||||
visible: active
|
visible: active
|
||||||
focus: active
|
focus: active
|
||||||
|
|
||||||
sourceComponent: DisplaysTab {}
|
sourceComponent: DisplayConfigTab {}
|
||||||
|
|
||||||
|
onActiveChanged: {
|
||||||
|
if (active && item) {
|
||||||
|
Qt.callLater(() => item.forceActiveFocus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: gammaControlLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 25
|
||||||
|
visible: active
|
||||||
|
focus: active
|
||||||
|
|
||||||
|
sourceComponent: GammaControlTab {}
|
||||||
|
|
||||||
|
onActiveChanged: {
|
||||||
|
if (active && item) {
|
||||||
|
Qt.callLater(() => item.forceActiveFocus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: displayWidgetsLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 26
|
||||||
|
visible: active
|
||||||
|
focus: active
|
||||||
|
|
||||||
|
sourceComponent: DisplayWidgetsTab {}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (active && item) {
|
if (active && item) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ FloatingWindow {
|
|||||||
objectName: "settingsModal"
|
objectName: "settingsModal"
|
||||||
title: I18n.tr("Settings", "settings window title")
|
title: I18n.tr("Settings", "settings window title")
|
||||||
minimumSize: Qt.size(500, 400)
|
minimumSize: Qt.size(500, 400)
|
||||||
implicitWidth: 800
|
implicitWidth: 900
|
||||||
implicitHeight: screen ? Math.min(940, screen.height - 100) : 940
|
implicitHeight: screen ? Math.min(940, screen.height - 100) : 940
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
visible: false
|
visible: false
|
||||||
|
|||||||
@@ -144,6 +144,32 @@ Rectangle {
|
|||||||
"tabIndex": 2,
|
"tabIndex": 2,
|
||||||
"shortcutsOnly": true
|
"shortcutsOnly": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "displays",
|
||||||
|
"text": I18n.tr("Displays"),
|
||||||
|
"icon": "monitor",
|
||||||
|
"collapsedByDefault": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "display_config",
|
||||||
|
"text": I18n.tr("Configuration") + " (Beta)",
|
||||||
|
"icon": "display_settings",
|
||||||
|
"tabIndex": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "display_gamma",
|
||||||
|
"text": I18n.tr("Gamma Control"),
|
||||||
|
"icon": "brightness_6",
|
||||||
|
"tabIndex": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "display_widgets",
|
||||||
|
"text": I18n.tr("Widgets", "settings_displays"),
|
||||||
|
"icon": "widgets",
|
||||||
|
"tabIndex": 26
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "network",
|
"id": "network",
|
||||||
"text": I18n.tr("Network"),
|
"text": I18n.tr("Network"),
|
||||||
@@ -157,12 +183,6 @@ Rectangle {
|
|||||||
"icon": "computer",
|
"icon": "computer",
|
||||||
"collapsedByDefault": true,
|
"collapsedByDefault": true,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
|
||||||
"id": "displays",
|
|
||||||
"text": I18n.tr("Displays"),
|
|
||||||
"icon": "monitor",
|
|
||||||
"tabIndex": 6
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "printers",
|
"id": "printers",
|
||||||
"text": I18n.tr("Printers"),
|
"text": I18n.tr("Printers"),
|
||||||
|
|||||||
1593
quickshell/Modules/Settings/DisplayConfigTab.qml
Normal file
1593
quickshell/Modules/Settings/DisplayConfigTab.qml
Normal file
File diff suppressed because it is too large
Load Diff
490
quickshell/Modules/Settings/DisplayWidgetsTab.qml
Normal file
490
quickshell/Modules/Settings/DisplayWidgetsTab.qml
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function getBarComponentsFromSettings() {
|
||||||
|
const bars = SettingsData.barConfigs || []
|
||||||
|
return bars.map(bar => ({
|
||||||
|
"id": "bar:" + bar.id,
|
||||||
|
"name": bar.name || "Bar",
|
||||||
|
"description": I18n.tr("Individual bar configuration"),
|
||||||
|
"icon": "toolbar",
|
||||||
|
"barId": bar.id
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
property var variantComponents: getVariantComponentsList()
|
||||||
|
|
||||||
|
function getVariantComponentsList() {
|
||||||
|
return [...getBarComponentsFromSettings(), {
|
||||||
|
"id": "dock",
|
||||||
|
"name": I18n.tr("Application Dock"),
|
||||||
|
"description": I18n.tr("Bottom dock for pinned and running applications"),
|
||||||
|
"icon": "dock"
|
||||||
|
}, {
|
||||||
|
"id": "notifications",
|
||||||
|
"name": I18n.tr("Notification Popups"),
|
||||||
|
"description": I18n.tr("Notification toast popups"),
|
||||||
|
"icon": "notifications"
|
||||||
|
}, {
|
||||||
|
"id": "wallpaper",
|
||||||
|
"name": I18n.tr("Wallpaper"),
|
||||||
|
"description": I18n.tr("Desktop background images"),
|
||||||
|
"icon": "wallpaper"
|
||||||
|
}, {
|
||||||
|
"id": "osd",
|
||||||
|
"name": I18n.tr("On-Screen Displays"),
|
||||||
|
"description": I18n.tr("Volume, brightness, and other system OSDs"),
|
||||||
|
"icon": "picture_in_picture"
|
||||||
|
}, {
|
||||||
|
"id": "toast",
|
||||||
|
"name": I18n.tr("Toast Messages"),
|
||||||
|
"description": I18n.tr("System toast notifications"),
|
||||||
|
"icon": "campaign"
|
||||||
|
}, {
|
||||||
|
"id": "notepad",
|
||||||
|
"name": I18n.tr("Notepad Slideout"),
|
||||||
|
"description": I18n.tr("Quick note-taking slideout panel"),
|
||||||
|
"icon": "sticky_note_2"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onBarConfigsChanged() {
|
||||||
|
variantComponents = getVariantComponentsList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScreenPreferences(componentId) {
|
||||||
|
if (componentId.startsWith("bar:")) {
|
||||||
|
const barId = componentId.substring(4)
|
||||||
|
const barConfig = SettingsData.getBarConfig(barId)
|
||||||
|
return barConfig?.screenPreferences || ["all"]
|
||||||
|
}
|
||||||
|
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]
|
||||||
|
}
|
||||||
|
|
||||||
|
function setScreenPreferences(componentId, screenNames) {
|
||||||
|
if (componentId.startsWith("bar:")) {
|
||||||
|
const barId = componentId.substring(4)
|
||||||
|
SettingsData.updateBarConfig(barId, {
|
||||||
|
"screenPreferences": screenNames
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var prefs = SettingsData.screenPreferences || {}
|
||||||
|
var newPrefs = Object.assign({}, prefs)
|
||||||
|
newPrefs[componentId] = screenNames
|
||||||
|
SettingsData.set("screenPreferences", newPrefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getShowOnLastDisplay(componentId) {
|
||||||
|
if (componentId.startsWith("bar:")) {
|
||||||
|
const barId = componentId.substring(4)
|
||||||
|
const barConfig = SettingsData.getBarConfig(barId)
|
||||||
|
return barConfig?.showOnLastDisplay ?? true
|
||||||
|
}
|
||||||
|
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShowOnLastDisplay(componentId, enabled) {
|
||||||
|
if (componentId.startsWith("bar:")) {
|
||||||
|
const barId = componentId.substring(4)
|
||||||
|
SettingsData.updateBarConfig(barId, {
|
||||||
|
"showOnLastDisplay": enabled
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var prefs = SettingsData.showOnLastDisplay || {}
|
||||||
|
var newPrefs = Object.assign({}, prefs)
|
||||||
|
newPrefs[componentId] = enabled
|
||||||
|
SettingsData.set("showOnLastDisplay", newPrefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
DankFlickable {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentHeight: mainColumn.height + Theme.spacingXL
|
||||||
|
contentWidth: width
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
|
||||||
|
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: Theme.spacingXL
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: screensInfoSection.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: screensInfoSection
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "monitor"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Connected Displays")
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Configure which displays show shell components")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Available Screens (") + Quickshell.screens.length + ")"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Display Name Format")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: displayModeGroup
|
||||||
|
model: [I18n.tr("Name"), I18n.tr("Model")]
|
||||||
|
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return
|
||||||
|
SettingsData.displayNameMode = index === 1 ? "model" : "system"
|
||||||
|
SettingsData.saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onDisplayNameModeChanged() {
|
||||||
|
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: screenRow.implicitHeight + Theme.spacingS * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: screenRow
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "desktop_windows"
|
||||||
|
size: Theme.iconSize - 4
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.iconSize - Theme.spacingM * 2
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingXS / 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: SettingsData.getScreenDisplayName(modelData)
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
property var wlrOutput: WlrOutputService.wlrOutputAvailable ? WlrOutputService.getOutput(modelData.name) : null
|
||||||
|
property var currentMode: wlrOutput?.currentMode
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (parent.currentMode) {
|
||||||
|
return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz"
|
||||||
|
}
|
||||||
|
return modelData.width + "×" + modelData.height
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "•"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.variantComponents
|
||||||
|
|
||||||
|
delegate: StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: componentSection.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: componentSection
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: modelData.icon
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.description
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Show on screens:")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
property string componentId: modelData.id
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
DankToggle {
|
||||||
|
width: parent.width
|
||||||
|
text: I18n.tr("All displays")
|
||||||
|
description: I18n.tr("Show on all connected displays")
|
||||||
|
checked: {
|
||||||
|
var prefs = root.getScreenPreferences(parent.componentId)
|
||||||
|
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||||
|
}
|
||||||
|
onToggled: checked => {
|
||||||
|
if (checked) {
|
||||||
|
root.setScreenPreferences(parent.componentId, ["all"])
|
||||||
|
} else {
|
||||||
|
root.setScreenPreferences(parent.componentId, [])
|
||||||
|
const cid = parent.componentId
|
||||||
|
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
|
||||||
|
root.setShowOnLastDisplay(cid, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankToggle {
|
||||||
|
width: parent.width
|
||||||
|
text: I18n.tr("Show on Last Display")
|
||||||
|
description: I18n.tr("Always show when there's only one connected display")
|
||||||
|
checked: root.getShowOnLastDisplay(parent.componentId)
|
||||||
|
visible: {
|
||||||
|
const prefs = root.getScreenPreferences(parent.componentId)
|
||||||
|
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||||
|
const cid = parent.componentId
|
||||||
|
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:")
|
||||||
|
return !isAll && isRelevantComponent
|
||||||
|
}
|
||||||
|
onToggled: checked => {
|
||||||
|
root.setShowOnLastDisplay(parent.componentId, checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.2
|
||||||
|
visible: {
|
||||||
|
var prefs = root.getScreenPreferences(parent.componentId)
|
||||||
|
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
visible: {
|
||||||
|
var prefs = root.getScreenPreferences(parent.componentId)
|
||||||
|
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
delegate: DankToggle {
|
||||||
|
property var screenData: modelData
|
||||||
|
property string componentId: parent.parent.componentId
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
text: SettingsData.getScreenDisplayName(screenData)
|
||||||
|
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
|
||||||
|
checked: {
|
||||||
|
var prefs = root.getScreenPreferences(componentId)
|
||||||
|
if (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||||
|
return false
|
||||||
|
return SettingsData.isScreenInPreferences(screenData, prefs)
|
||||||
|
}
|
||||||
|
onToggled: checked => {
|
||||||
|
var currentPrefs = root.getScreenPreferences(componentId)
|
||||||
|
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
|
||||||
|
currentPrefs = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const screenModelIndex = SettingsData.getScreenModelIndex(screenData)
|
||||||
|
|
||||||
|
var newPrefs = currentPrefs.filter(pref => {
|
||||||
|
if (typeof pref === "string")
|
||||||
|
return false
|
||||||
|
if (pref.modelIndex !== undefined && screenModelIndex >= 0) {
|
||||||
|
return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex)
|
||||||
|
}
|
||||||
|
return pref.name !== screenData.name || pref.model !== screenData.model
|
||||||
|
})
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
const prefObj = {
|
||||||
|
"name": screenData.name,
|
||||||
|
"model": screenData.model || ""
|
||||||
|
}
|
||||||
|
if (screenModelIndex >= 0) {
|
||||||
|
prefObj.modelIndex = screenModelIndex
|
||||||
|
}
|
||||||
|
newPrefs.push(prefObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
root.setScreenPreferences(componentId, newPrefs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,128 +6,21 @@ import qs.Services
|
|||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: displaysTab
|
id: root
|
||||||
|
|
||||||
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 ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBarComponentsFromSettings() {
|
|
||||||
const bars = SettingsData.barConfigs || [];
|
|
||||||
return bars.map(bar => ({
|
|
||||||
"id": "bar:" + bar.id,
|
|
||||||
"name": bar.name || "Bar",
|
|
||||||
"description": I18n.tr("Individual bar configuration"),
|
|
||||||
"icon": "toolbar",
|
|
||||||
"barId": bar.id
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
property var variantComponents: getVariantComponentsList()
|
|
||||||
|
|
||||||
function getVariantComponentsList() {
|
|
||||||
return [...getBarComponentsFromSettings(),
|
|
||||||
{
|
|
||||||
"id": "dock",
|
|
||||||
"name": I18n.tr("Application Dock"),
|
|
||||||
"description": I18n.tr("Bottom dock for pinned and running applications"),
|
|
||||||
"icon": "dock"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "notifications",
|
|
||||||
"name": I18n.tr("Notification Popups"),
|
|
||||||
"description": I18n.tr("Notification toast popups"),
|
|
||||||
"icon": "notifications"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "wallpaper",
|
|
||||||
"name": I18n.tr("Wallpaper"),
|
|
||||||
"description": I18n.tr("Desktop background images"),
|
|
||||||
"icon": "wallpaper"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "osd",
|
|
||||||
"name": I18n.tr("On-Screen Displays"),
|
|
||||||
"description": I18n.tr("Volume, brightness, and other system OSDs"),
|
|
||||||
"icon": "picture_in_picture"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "toast",
|
|
||||||
"name": I18n.tr("Toast Messages"),
|
|
||||||
"description": I18n.tr("System toast notifications"),
|
|
||||||
"icon": "campaign"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "notepad",
|
|
||||||
"name": I18n.tr("Notepad Slideout"),
|
|
||||||
"description": I18n.tr("Quick note-taking slideout panel"),
|
|
||||||
"icon": "sticky_note_2"
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: SettingsData
|
|
||||||
function onBarConfigsChanged() {
|
|
||||||
variantComponents = getVariantComponentsList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getScreenPreferences(componentId) {
|
|
||||||
if (componentId.startsWith("bar:")) {
|
|
||||||
const barId = componentId.substring(4);
|
|
||||||
const barConfig = SettingsData.getBarConfig(barId);
|
|
||||||
return barConfig?.screenPreferences || ["all"];
|
|
||||||
}
|
|
||||||
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"];
|
|
||||||
}
|
|
||||||
|
|
||||||
function setScreenPreferences(componentId, screenNames) {
|
|
||||||
if (componentId.startsWith("bar:")) {
|
|
||||||
const barId = componentId.substring(4);
|
|
||||||
SettingsData.updateBarConfig(barId, {
|
|
||||||
screenPreferences: screenNames
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var prefs = SettingsData.screenPreferences || {};
|
|
||||||
var newPrefs = Object.assign({}, prefs);
|
|
||||||
newPrefs[componentId] = screenNames;
|
|
||||||
SettingsData.set("screenPreferences", newPrefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getShowOnLastDisplay(componentId) {
|
|
||||||
if (componentId.startsWith("bar:")) {
|
|
||||||
const barId = componentId.substring(4);
|
|
||||||
const barConfig = SettingsData.getBarConfig(barId);
|
|
||||||
return barConfig?.showOnLastDisplay ?? true;
|
|
||||||
}
|
|
||||||
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setShowOnLastDisplay(componentId, enabled) {
|
|
||||||
if (componentId.startsWith("bar:")) {
|
|
||||||
const barId = componentId.substring(4);
|
|
||||||
SettingsData.updateBarConfig(barId, {
|
|
||||||
showOnLastDisplay: enabled
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var prefs = SettingsData.showOnLastDisplay || {};
|
|
||||||
var newPrefs = Object.assign({}, prefs);
|
|
||||||
newPrefs[componentId] = enabled;
|
|
||||||
SettingsData.set("showOnLastDisplay", newPrefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
@@ -181,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
|
||||||
@@ -210,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 {
|
||||||
@@ -232,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +175,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: SessionData
|
target: SessionData
|
||||||
function onNightModeAutoEnabledChanged() {
|
function onNightModeAutoEnabledChanged() {
|
||||||
automaticSettings.visible = SessionData.nightModeAutoEnabled;
|
automaticSettings.visible = SessionData.nightModeAutoEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -525,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,7 +569,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: displaysTab.formatGammaTime(DisplayService.gammaSunriseTime)
|
text: root.formatGammaTime(DisplayService.gammaSunriseTime)
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
@@ -714,7 +605,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: displaysTab.formatGammaTime(DisplayService.gammaSunsetTime)
|
text: root.formatGammaTime(DisplayService.gammaSunsetTime)
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
@@ -761,7 +652,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: displaysTab.formatGammaTime(DisplayService.gammaNextTransition)
|
text: root.formatGammaTime(DisplayService.gammaNextTransition)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
@@ -773,371 +664,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
width: parent.width
|
|
||||||
height: screensInfoSection.implicitHeight + Theme.spacingL * 2
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
|
||||||
border.width: 0
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: screensInfoSection
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingL
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "monitor"
|
|
||||||
size: Theme.iconSize
|
|
||||||
color: Theme.primary
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Connected Displays")
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Configure which displays show shell components")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
width: parent.width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Available Screens (") + Quickshell.screens.length + ")"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: 1
|
|
||||||
height: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Display Name Format")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
id: displayModeGroup
|
|
||||||
model: [I18n.tr("Name"), I18n.tr("Model")]
|
|
||||||
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
SettingsData.displayNameMode = index === 1 ? "model" : "system";
|
|
||||||
SettingsData.saveSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: SettingsData
|
|
||||||
function onDisplayNameModeChanged() {
|
|
||||||
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Quickshell.screens
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: screenRow.implicitHeight + Theme.spacingS * 2
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
|
||||||
border.width: 0
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: screenRow
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "desktop_windows"
|
|
||||||
size: Theme.iconSize - 4
|
|
||||||
color: Theme.primary
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width - Theme.iconSize - Theme.spacingM * 2
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingXS / 2
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: SettingsData.getScreenDisplayName(modelData)
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
property var wlrOutput: WlrOutputService.wlrOutputAvailable ? WlrOutputService.getOutput(modelData.name) : null
|
|
||||||
property var currentMode: wlrOutput?.currentMode
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: {
|
|
||||||
if (parent.currentMode) {
|
|
||||||
return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz";
|
|
||||||
}
|
|
||||||
return modelData.width + "×" + modelData.height;
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: "•"
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: displaysTab.variantComponents
|
|
||||||
|
|
||||||
delegate: StyledRect {
|
|
||||||
width: parent.width
|
|
||||||
height: componentSection.implicitHeight + Theme.spacingL * 2
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
|
||||||
border.width: 0
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: componentSection
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingL
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: modelData.icon
|
|
||||||
size: Theme.iconSize
|
|
||||||
color: Theme.primary
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.name
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.description
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
width: parent.width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Show on screens:")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
property string componentId: modelData.id
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
DankToggle {
|
|
||||||
width: parent.width
|
|
||||||
text: I18n.tr("All displays")
|
|
||||||
description: I18n.tr("Show on all connected displays")
|
|
||||||
checked: {
|
|
||||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
|
||||||
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
|
||||||
}
|
|
||||||
onToggled: checked => {
|
|
||||||
if (checked) {
|
|
||||||
displaysTab.setScreenPreferences(parent.componentId, ["all"]);
|
|
||||||
} else {
|
|
||||||
displaysTab.setScreenPreferences(parent.componentId, []);
|
|
||||||
const cid = parent.componentId;
|
|
||||||
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
|
|
||||||
displaysTab.setShowOnLastDisplay(cid, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankToggle {
|
|
||||||
width: parent.width
|
|
||||||
text: I18n.tr("Show on Last Display")
|
|
||||||
description: I18n.tr("Always show when there's only one connected display")
|
|
||||||
checked: displaysTab.getShowOnLastDisplay(parent.componentId)
|
|
||||||
visible: {
|
|
||||||
const prefs = displaysTab.getScreenPreferences(parent.componentId);
|
|
||||||
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
|
||||||
const cid = parent.componentId;
|
|
||||||
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:");
|
|
||||||
return !isAll && isRelevantComponent;
|
|
||||||
}
|
|
||||||
onToggled: checked => {
|
|
||||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Theme.outline
|
|
||||||
opacity: 0.2
|
|
||||||
visible: {
|
|
||||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
|
||||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
visible: {
|
|
||||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
|
||||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Quickshell.screens
|
|
||||||
|
|
||||||
delegate: DankToggle {
|
|
||||||
property var screenData: modelData
|
|
||||||
property string componentId: parent.parent.componentId
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
text: SettingsData.getScreenDisplayName(screenData)
|
|
||||||
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
|
|
||||||
checked: {
|
|
||||||
var prefs = displaysTab.getScreenPreferences(componentId);
|
|
||||||
if (typeof prefs[0] === "string" && prefs[0] === "all")
|
|
||||||
return false;
|
|
||||||
return SettingsData.isScreenInPreferences(screenData, prefs);
|
|
||||||
}
|
|
||||||
onToggled: checked => {
|
|
||||||
var currentPrefs = displaysTab.getScreenPreferences(componentId);
|
|
||||||
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
|
|
||||||
currentPrefs = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const screenModelIndex = SettingsData.getScreenModelIndex(screenData);
|
|
||||||
|
|
||||||
var newPrefs = currentPrefs.filter(pref => {
|
|
||||||
if (typeof pref === "string")
|
|
||||||
return false;
|
|
||||||
if (pref.modelIndex !== undefined && screenModelIndex >= 0) {
|
|
||||||
return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex);
|
|
||||||
}
|
|
||||||
return pref.name !== screenData.name || pref.model !== screenData.model;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (checked) {
|
|
||||||
const prefObj = {
|
|
||||||
name: screenData.name,
|
|
||||||
model: screenData.model || ""
|
|
||||||
};
|
|
||||||
if (screenModelIndex >= 0) {
|
|
||||||
prefObj.modelIndex = screenModelIndex;
|
|
||||||
}
|
|
||||||
newPrefs.push(prefObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
displaysTab.setScreenPreferences(componentId, newPrefs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,36 +328,21 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
DankButton {
|
||||||
id: fixButton
|
id: fixButton
|
||||||
width: fixButtonText.implicitWidth + Theme.spacingL * 2
|
|
||||||
height: Math.round(Theme.fontSizeMedium * 2.5)
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
visible: warningBox.showError || warningBox.showSetup
|
visible: warningBox.showError || warningBox.showSetup
|
||||||
color: KeybindsService.fixing ? Theme.withAlpha(Theme.error, 0.6) : Theme.error
|
text: {
|
||||||
|
if (KeybindsService.fixing)
|
||||||
|
return I18n.tr("Fixing...")
|
||||||
|
if (warningBox.showSetup)
|
||||||
|
return I18n.tr("Setup")
|
||||||
|
return I18n.tr("Fix Now")
|
||||||
|
}
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
textColor: Theme.primaryText
|
||||||
|
enabled: !KeybindsService.fixing
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: KeybindsService.fixDmsBindsInclude()
|
||||||
StyledText {
|
|
||||||
id: fixButtonText
|
|
||||||
text: {
|
|
||||||
if (KeybindsService.fixing)
|
|
||||||
return I18n.tr("Fixing...");
|
|
||||||
if (warningBox.showSetup)
|
|
||||||
return I18n.tr("Setup");
|
|
||||||
return I18n.tr("Fix Now");
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surface
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: !KeybindsService.fixing
|
|
||||||
onClicked: KeybindsService.fixDmsBindsInclude()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
|
||||||
|
readonly property string mangoDmsDir: configDir + "/mango/dms"
|
||||||
|
readonly property string outputsPath: mangoDmsDir + "/outputs.conf"
|
||||||
|
|
||||||
property bool dwlAvailable: false
|
property bool dwlAvailable: false
|
||||||
property var outputs: ({})
|
property var outputs: ({})
|
||||||
property var tagCount: 9
|
property var tagCount: 9
|
||||||
@@ -263,4 +269,85 @@ Singleton {
|
|||||||
|
|
||||||
return Array.from(visibleTags).sort((a, b) => a - b);
|
return Array.from(visibleTags).sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateOutputsConfig(outputsData) {
|
||||||
|
if (!outputsData || Object.keys(outputsData).length === 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const output = outputsData[outputName]
|
||||||
|
if (!output)
|
||||||
|
continue
|
||||||
|
|
||||||
|
let width = 1920
|
||||||
|
let height = 1080
|
||||||
|
let refreshRate = 60
|
||||||
|
if (output.modes && output.current_mode !== undefined) {
|
||||||
|
const mode = output.modes[output.current_mode]
|
||||||
|
if (mode) {
|
||||||
|
width = mode.width || 1920
|
||||||
|
height = mode.height || 1080
|
||||||
|
refreshRate = Math.round((mode.refresh_rate || 60000) / 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const x = output.logical?.x ?? 0
|
||||||
|
const y = output.logical?.y ?? 0
|
||||||
|
const scale = output.logical?.scale ?? 1.0
|
||||||
|
const transform = transformToMango(output.logical?.transform ?? "Normal")
|
||||||
|
|
||||||
|
const rule = [
|
||||||
|
outputName,
|
||||||
|
"0.55",
|
||||||
|
"1",
|
||||||
|
"tile",
|
||||||
|
transform,
|
||||||
|
scale,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
refreshRate
|
||||||
|
].join(",")
|
||||||
|
|
||||||
|
lines.push("monitorrule=" + rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("")
|
||||||
|
|
||||||
|
const content = lines.join("\n")
|
||||||
|
|
||||||
|
Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("DwlService: Failed to write outputs config:", output)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.info("DwlService: Generated outputs config at", outputsPath)
|
||||||
|
if (CompositorService.isDwl)
|
||||||
|
reloadConfig()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadConfig() {
|
||||||
|
Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0)
|
||||||
|
console.warn("DwlService: mmsg reload_config failed:", output)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformToMango(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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
quickshell/Services/HyprlandService.qml
Normal file
110
quickshell/Services/HyprlandService.qml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
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"
|
||||||
|
|
||||||
|
function getOutputIdentifier(output, outputName) {
|
||||||
|
if (SettingsData.displayNameMode === "model" && output.make && output.model) {
|
||||||
|
return "desc:" + output.make + " " + output.model
|
||||||
|
}
|
||||||
|
return outputName
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOutputsConfig(outputsData) {
|
||||||
|
if (!outputsData || Object.keys(outputsData).length === 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
let lines = ["# Auto-generated by DMS - do not edit manually", ""]
|
||||||
|
|
||||||
|
for (const outputName in outputsData) {
|
||||||
|
const output = outputsData[outputName]
|
||||||
|
if (!output)
|
||||||
|
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
|
||||||
|
|
||||||
|
const identifier = getOutputIdentifier(output, outputName)
|
||||||
|
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"
|
||||||
|
|
||||||
|
lines.push(monitorLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -23,6 +23,8 @@ Singleton {
|
|||||||
property var windows: []
|
property var windows: []
|
||||||
property var displayScales: ({})
|
property var displayScales: ({})
|
||||||
|
|
||||||
|
property var _realOutputs: ({})
|
||||||
|
|
||||||
property bool inOverview: false
|
property bool inOverview: false
|
||||||
|
|
||||||
property int currentKeyboardLayoutIndex: 0
|
property int currentKeyboardLayoutIndex: 0
|
||||||
@@ -214,12 +216,12 @@ Singleton {
|
|||||||
const ws = workspaces[w.workspace_id];
|
const ws = workspaces[w.workspace_id];
|
||||||
if (!ws) {
|
if (!ws) {
|
||||||
return {
|
return {
|
||||||
window: w,
|
"window": w,
|
||||||
outputX: 999999,
|
"outputX": 999999,
|
||||||
outputY: 999999,
|
"outputY": 999999,
|
||||||
wsIdx: 999999,
|
"wsIdx": 999999,
|
||||||
col: 999999,
|
"col": 999999,
|
||||||
row: 999999
|
"row": 999999
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,12 +234,12 @@ Singleton {
|
|||||||
const row = (pos && pos.length >= 2) ? pos[1] : 999999;
|
const row = (pos && pos.length >= 2) ? pos[1] : 999999;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
window: w,
|
"window": w,
|
||||||
outputX: outputX,
|
"outputX": outputX,
|
||||||
outputY: outputY,
|
"outputY": outputY,
|
||||||
wsIdx: ws.idx,
|
"wsIdx": ws.idx,
|
||||||
col: col,
|
"col": col,
|
||||||
row: row
|
"row": row
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -598,7 +600,7 @@ Singleton {
|
|||||||
const editor = Quickshell.env("DMS_SCREENSHOT_EDITOR");
|
const editor = Quickshell.env("DMS_SCREENSHOT_EDITOR");
|
||||||
const command = editor === "satty" ? ["satty", "-f", data.path] : ["swappy", "-f", data.path];
|
const command = editor === "satty" ? ["satty", "-f", data.path] : ["swappy", "-f", data.path];
|
||||||
Quickshell.execDetached({
|
Quickshell.execDetached({
|
||||||
command: command
|
"command": command
|
||||||
});
|
});
|
||||||
pendingScreenshotPath = "";
|
pendingScreenshotPath = "";
|
||||||
}
|
}
|
||||||
@@ -993,35 +995,35 @@ Singleton {
|
|||||||
const gaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
|
const gaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
|
||||||
|
|
||||||
const dmsWarning = `// ! DO NOT EDIT !
|
const dmsWarning = `// ! DO NOT EDIT !
|
||||||
// ! AUTO-GENERATED BY DMS !
|
// ! AUTO-GENERATED BY DMS !
|
||||||
// ! CHANGES WILL BE OVERWRITTEN !
|
// ! CHANGES WILL BE OVERWRITTEN !
|
||||||
// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
|
// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const configContent = dmsWarning + `layout {
|
const configContent = dmsWarning + `layout {
|
||||||
gaps ${gaps}
|
gaps ${gaps}
|
||||||
|
|
||||||
border {
|
border {
|
||||||
width 2
|
width 2
|
||||||
}
|
}
|
||||||
|
|
||||||
focus-ring {
|
focus-ring {
|
||||||
width 2
|
width 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window-rule {
|
window-rule {
|
||||||
geometry-corner-radius ${cornerRadius}
|
geometry-corner-radius ${cornerRadius}
|
||||||
clip-to-geometry true
|
clip-to-geometry true
|
||||||
tiled-state true
|
tiled-state true
|
||||||
draw-border-with-background false
|
draw-border-with-background false
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const alttabContent = dmsWarning + `recent-windows {
|
const alttabContent = dmsWarning + `recent-windows {
|
||||||
highlight {
|
highlight {
|
||||||
corner-radius ${cornerRadius}
|
corner-radius ${cornerRadius}
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
|
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
|
||||||
const niriDmsDir = configDir + "/niri/dms";
|
const niriDmsDir = configDir + "/niri/dms";
|
||||||
@@ -1054,6 +1056,141 @@ window-rule {
|
|||||||
writeBlurruleProcess.running = true;
|
writeBlurruleProcess.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateOutputPosition(outputName, x, y) {
|
||||||
|
if (!outputs || !outputs[outputName])
|
||||||
|
return;
|
||||||
|
const updatedOutputs = {};
|
||||||
|
for (const name in outputs) {
|
||||||
|
const output = outputs[name];
|
||||||
|
if (name === outputName && output.logical) {
|
||||||
|
updatedOutputs[name] = JSON.parse(JSON.stringify(output));
|
||||||
|
updatedOutputs[name].logical.x = x;
|
||||||
|
updatedOutputs[name].logical.y = y;
|
||||||
|
} else {
|
||||||
|
updatedOutputs[name] = output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputs = updatedOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyOutputConfig(outputName, config, callback) {
|
||||||
|
if (!CompositorService.isNiri || !outputName) {
|
||||||
|
if (callback)
|
||||||
|
callback(false, "Invalid config");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commands = [];
|
||||||
|
|
||||||
|
if (config.position !== undefined) {
|
||||||
|
commands.push(`niri msg output "${outputName}" position ${config.position.x} ${config.position.y}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.mode !== undefined) {
|
||||||
|
commands.push(`niri msg output "${outputName}" mode ${config.mode}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.vrr !== undefined) {
|
||||||
|
commands.push(`niri msg output "${outputName}" vrr ${config.vrr ? "on" : "off"}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.scale !== undefined) {
|
||||||
|
commands.push(`niri msg output "${outputName}" scale ${config.scale}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.transform !== undefined) {
|
||||||
|
commands.push(`niri msg output "${outputName}" transform "${config.transform}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commands.length === 0) {
|
||||||
|
if (callback)
|
||||||
|
callback(true, "No changes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullCommand = commands.join(" && ");
|
||||||
|
Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("NiriService: Failed to apply output config:", output);
|
||||||
|
if (callback)
|
||||||
|
callback(false, output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.info("NiriService: Applied output config for", outputName);
|
||||||
|
fetchOutputs();
|
||||||
|
if (callback)
|
||||||
|
callback(true, "Success");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOutputIdentifier(output, outputName) {
|
||||||
|
if (SettingsData.displayNameMode === "model" && output.make && output.model) {
|
||||||
|
const serial = output.serial || "Unknown";
|
||||||
|
return output.make + " " + output.model + " " + serial;
|
||||||
|
}
|
||||||
|
return outputName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOutputsConfig(outputsData) {
|
||||||
|
const data = outputsData || outputs;
|
||||||
|
if (!data || Object.keys(data).length === 0)
|
||||||
|
return;
|
||||||
|
let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`;
|
||||||
|
|
||||||
|
for (const outputName in data) {
|
||||||
|
const output = data[outputName];
|
||||||
|
const identifier = getOutputIdentifier(output, outputName);
|
||||||
|
kdlContent += `output "${identifier}" {\n`;
|
||||||
|
|
||||||
|
if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) {
|
||||||
|
const mode = output.modes[output.current_mode];
|
||||||
|
kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.logical) {
|
||||||
|
if (output.logical.scale && output.logical.scale !== 1.0) {
|
||||||
|
kdlContent += ` scale ${output.logical.scale}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.logical.transform && output.logical.transform !== "Normal") {
|
||||||
|
const transformMap = {
|
||||||
|
"Normal": "normal",
|
||||||
|
"90": "90",
|
||||||
|
"180": "180",
|
||||||
|
"270": "270",
|
||||||
|
"Flipped": "flipped",
|
||||||
|
"Flipped90": "flipped-90",
|
||||||
|
"Flipped180": "flipped-180",
|
||||||
|
"Flipped270": "flipped-270"
|
||||||
|
};
|
||||||
|
kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.logical.x !== undefined && output.logical.y !== undefined) {
|
||||||
|
kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.vrr_enabled) {
|
||||||
|
kdlContent += ` variable-refresh-rate\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdlContent += `}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
|
||||||
|
const niriDmsDir = configDir + "/niri/dms";
|
||||||
|
const outputsPath = niriDmsDir + "/outputs.kdl";
|
||||||
|
|
||||||
|
Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("NiriService: Failed to write outputs config:", output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.info("NiriService: Generated outputs config at", outputsPath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function screenshot(): string {
|
function screenshot(): string {
|
||||||
if (!CompositorService.isNiri) {
|
if (!CompositorService.isNiri) {
|
||||||
|
|||||||
Reference in New Issue
Block a user