mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-22 03:04:01 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47c9d8d89b | ||
|
|
d8786eaaf7 | ||
|
|
4f969c8e10 | ||
|
|
1b59a474dd | ||
|
|
28f921fa02 | ||
|
|
8f2a486006 | ||
|
|
27a703367f | ||
|
|
8e851b3dc4 | ||
|
|
112d05901f | ||
|
|
afeea489c9 | ||
|
|
90d3c9731c | ||
|
|
b81954454a | ||
|
|
479b1434de | ||
|
|
203b1369b3 | ||
|
|
5ffc581ecf | ||
|
|
3284acab28 | ||
|
|
1fb9f5271a |
@@ -26,6 +26,11 @@ jobs:
|
|||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: core/go.mod
|
go-version-file: core/go.mod
|
||||||
|
cache-dependency-path: core/go.sum
|
||||||
|
|
||||||
|
- name: Download Go modules
|
||||||
|
working-directory: core
|
||||||
|
run: for attempt in 1 2 3; do go mod download && exit 0; sleep 15; done; exit 1
|
||||||
|
|
||||||
- name: run pre-commit hooks
|
- name: run pre-commit hooks
|
||||||
uses: j178/prek-action@v2
|
uses: j178/prek-action@v2
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ jobs:
|
|||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: ./core/go.mod
|
go-version-file: ./core/go.mod
|
||||||
|
cache-dependency-path: core/go.sum
|
||||||
|
|
||||||
- name: Format check
|
- name: Format check
|
||||||
if: matrix.goos == 'linux'
|
if: matrix.goos == 'linux'
|
||||||
@@ -247,6 +248,7 @@ jobs:
|
|||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: ./core/go.mod
|
go-version-file: ./core/go.mod
|
||||||
|
cache-dependency-path: core/go.sum
|
||||||
|
|
||||||
- name: Download core artifacts
|
- name: Download core artifacts
|
||||||
uses: actions/download-artifact@v5
|
uses: actions/download-artifact@v5
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ jobs:
|
|||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: ./core/go.mod
|
go-version-file: ./core/go.mod
|
||||||
|
cache-dependency-path: core/go.sum
|
||||||
|
|
||||||
- name: Install OSC
|
- name: Install OSC
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ jobs:
|
|||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: ./core/go.mod
|
go-version-file: ./core/go.mod
|
||||||
|
cache-dependency-path: core/go.sum
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ Notification center with grouping, rich text support, and keyboard navigation.
|
|||||||
MPRIS player controls, calendar sync, weather widgets, and clipboard history with image previews.
|
MPRIS player controls, calendar sync, weather widgets, and clipboard history with image previews.
|
||||||
|
|
||||||
**Session Management**
|
**Session Management**
|
||||||
Lock screen, idle detection, auto-lock/suspend with separate AC/battery settings, and a settings front-end for [dank-greeter](https://github.com/duxlabs-dev/dux-greeter).
|
Lock screen, idle detection, auto-lock/suspend with separate AC/battery settings, and a settings front-end for [dux-greeter](https://github.com/duxlabs-dev/dux-greeter).
|
||||||
|
|
||||||
**Plugin System**
|
**Plugin System**
|
||||||
Extend functionality with the [plugin registry](https://plugins.duxlabs.dev). DMS keeps
|
Extend functionality with the [plugin registry](https://plugins.duxlabs.dev). DMS keeps
|
||||||
@@ -138,16 +138,16 @@ dms plugins restore ~/plugins.lock.json
|
|||||||
- **Plugins:** [Development guide](https://duxlabs.dev/docs/dms/plugins-overview)
|
- **Plugins:** [Development guide](https://duxlabs.dev/docs/dms/plugins-overview)
|
||||||
- **Support:** [Ko-fi](https://ko-fi.com/duxlabs)
|
- **Support:** [Ko-fi](https://ko-fi.com/duxlabs)
|
||||||
|
|
||||||
## Dank Projects
|
## Dux Projects
|
||||||
|
|
||||||
DMS is one piece of the suite. The rest lives in its own repos:
|
DMS is one piece of the suite. The rest lives in its own repos:
|
||||||
|
|
||||||
- [dank-greeter](https://github.com/duxlabs-dev/dux-greeter) - greetd login screen with the Dux Shell aesthetic. The Greeter tab in DMS settings is the front-end for it.
|
- [dux-greeter](https://github.com/duxlabs-dev/dux-greeter) - greetd login screen with the Dux Shell aesthetic. The Greeter tab in DMS settings is the front-end for it.
|
||||||
- [dankcalendar](https://github.com/duxlabs-dev/dux-calendar) - Local, Google, Microsoft, and CalDAV calendars for the Dux desktop.
|
- [dux-calendar](https://github.com/duxlabs-dev/dux-calendar) - Local, Google, Microsoft, and CalDAV calendars for the Dux desktop.
|
||||||
- [dgop](https://github.com/duxlabs-dev/dux-gop) - System monitoring TUI and Go library; its library powers the process list and dashboard widgets inside the dms daemon.
|
- [dgop](https://github.com/duxlabs-dev/dux-gop) - System monitoring TUI and Go library; its library powers the process list and dashboard widgets inside the dms daemon.
|
||||||
- [dsearch](https://github.com/duxlabs-dev/dux-search) - Fast file search that powers file results in the launcher.
|
- [dsearch](https://github.com/duxlabs-dev/dux-search) - Fast file search that powers file results in the launcher.
|
||||||
- [dux-qml-common](https://github.com/duxlabs-dev/dux-qml-common) - Shared QML widgets and components used by DMS, dank-greeter, and dankcalendar.
|
- [dux-qml-common](https://github.com/duxlabs-dev/dux-qml-common) - Shared QML widgets and components used by DMS, dux-greeter, and dux-calendar.
|
||||||
- [dankgo](https://github.com/duxlabs-dev/dux-go) - Common Go modules behind the single binary apps.
|
- [dux-go](https://github.com/duxlabs-dev/dux-go) - Common Go modules behind the single binary apps.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ Contributions welcome. Bug fixes, widgets, features, documentation, and plugins
|
|||||||
3. Test thoroughly
|
3. Test thoroughly
|
||||||
4. Open a pull request
|
4. Open a pull request
|
||||||
|
|
||||||
For documentation contributions, see [DankLinux-Docs](https://github.com/duxlabs-dev/dux-docs).
|
For documentation contributions, see [dux-docs](https://github.com/duxlabs-dev/dux-docs).
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/duxlabs-dev/dux-go/shellapp"
|
"github.com/duxlabs-dev/dux-go/shellapp"
|
||||||
@@ -83,12 +85,36 @@ func preLaunch() {
|
|||||||
ensureFontCache()
|
ensureFontCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The elapsed-timer driver keeps the scrolling wallpaper spring in step above 60 Hz,
|
||||||
|
// but it makes every other animation jump after a dropped frame (#3837).
|
||||||
|
func scrollingWallpaperConfigured() bool {
|
||||||
|
configDir, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(filepath.Join(configDir, "dms", "settings.json"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return wantsSimpleAnimationDriver(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wantsSimpleAnimationDriver(settings []byte) bool {
|
||||||
|
var parsed struct {
|
||||||
|
WallpaperFillMode string `json:"wallpaperFillMode"`
|
||||||
|
}
|
||||||
|
if json.Unmarshal(settings, &parsed) != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return parsed.WallpaperFillMode == "Scrolling"
|
||||||
|
}
|
||||||
|
|
||||||
func dmsExtraEnv(string) []string {
|
func dmsExtraEnv(string) []string {
|
||||||
var env []string
|
var env []string
|
||||||
if selfPath, err := os.Executable(); err == nil {
|
if selfPath, err := os.Executable(); err == nil {
|
||||||
env = append(env, "DMS_EXECUTABLE="+selfPath)
|
env = append(env, "DMS_EXECUTABLE="+selfPath)
|
||||||
}
|
}
|
||||||
if os.Getenv("QSG_USE_SIMPLE_ANIMATION_DRIVER") == "" {
|
if os.Getenv("QSG_USE_SIMPLE_ANIMATION_DRIVER") == "" && scrollingWallpaperConfigured() {
|
||||||
env = append(env, "QSG_USE_SIMPLE_ANIMATION_DRIVER=1")
|
env = append(env, "QSG_USE_SIMPLE_ANIMATION_DRIVER=1")
|
||||||
}
|
}
|
||||||
if _, set := os.LookupEnv("MALLOC_CONF"); !set {
|
if _, set := os.LookupEnv("MALLOC_CONF"); !set {
|
||||||
|
|||||||
@@ -965,6 +965,7 @@ var vscodeEditors = []vscodeEditor{
|
|||||||
{"cursor", ".cursor"},
|
{"cursor", ".cursor"},
|
||||||
{"windsurf", ".windsurf"},
|
{"windsurf", ".windsurf"},
|
||||||
{"positron", ".positron"},
|
{"positron", ".positron"},
|
||||||
|
{"antigravity", ".antigravity-ide"},
|
||||||
{"vscode-insiders", ".vscode-insiders"},
|
{"vscode-insiders", ".vscode-insiders"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule dux-qml-common updated: ebf5e6c002...5715e8ea86
Generated
+3
-3
@@ -3,11 +3,11 @@
|
|||||||
"dank-qml-common": {
|
"dank-qml-common": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1792513666,
|
"lastModified": 1792597131,
|
||||||
"narHash": "sha256-RDqPdPrM5lnwRrfFGLz3IwgTjCV2Ie+nrTD3ldj1t/s=",
|
"narHash": "sha256-2t9btOQ2owoRv/fgeonlr8cHVt2NUvUu9iXdZd9+QFc=",
|
||||||
"owner": "duxlabs-dev",
|
"owner": "duxlabs-dev",
|
||||||
"repo": "dux-qml-common",
|
"repo": "dux-qml-common",
|
||||||
"rev": "ebf5e6c002da1bdaa4aaa2f319fea7b8507abc42",
|
"rev": "5715e8ea868f3a131a0f54c7a5875e9a95f2f253",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ Singleton {
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "dock_general",
|
"id": "dock_general",
|
||||||
|
"hidden": true,
|
||||||
"text": I18n.tr("General"),
|
"text": I18n.tr("General"),
|
||||||
"icon": "tune",
|
"icon": "tune",
|
||||||
"tabIndex": 5,
|
"tabIndex": 5,
|
||||||
@@ -167,6 +168,7 @@ Singleton {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "dock_widgets",
|
"id": "dock_widgets",
|
||||||
|
"hidden": true,
|
||||||
"text": I18n.tr("Apps & widgets"),
|
"text": I18n.tr("Apps & widgets"),
|
||||||
"icon": "widgets",
|
"icon": "widgets",
|
||||||
"tabIndex": 57,
|
"tabIndex": 57,
|
||||||
@@ -174,6 +176,7 @@ Singleton {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "dock_appearance",
|
"id": "dock_appearance",
|
||||||
|
"hidden": true,
|
||||||
"text": I18n.tr("Appearance"),
|
"text": I18n.tr("Appearance"),
|
||||||
"icon": "palette",
|
"icon": "palette",
|
||||||
"tabIndex": 58,
|
"tabIndex": 58,
|
||||||
|
|||||||
@@ -1876,9 +1876,9 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const runKey = Qt.md5(JSON.stringify(args));
|
const runKey = Qt.md5(JSON.stringify(args));
|
||||||
const skipUnchanged = !_matugenRunKey && !colorsFileLoadFailed && typeof SettingsData !== "undefined" && !SettingsData.generateThemeAtStartup;
|
const startupRun = !_matugenRunKey && typeof SettingsData !== "undefined" && SettingsData.generateThemeAtStartup;
|
||||||
if (skipUnchanged && runKey === CacheData.matugenAppliedKey) {
|
if (!startupRun && !colorsFileLoadFailed && runKey === CacheData.matugenAppliedKey) {
|
||||||
log.info("Theme inputs unchanged since the last run, skipping startup generation");
|
log.info("Theme inputs unchanged since the last run, skipping generation");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2496,6 +2496,36 @@ Singleton {
|
|||||||
onTriggered: dynamicColorsFileView.reload()
|
onTriggered: dynamicColorsFileView.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property bool publishTypography: typeof SettingsData !== "undefined" && SettingsData._hasLoaded && !SessionData.isGreeterMode
|
||||||
|
readonly property string typographyJson: JSON.stringify({
|
||||||
|
"fontFamily": fontFamily,
|
||||||
|
"monoFontFamily": monoFontFamily,
|
||||||
|
"displayFontFamily": displayFontFamily,
|
||||||
|
"fontWeight": fontWeight,
|
||||||
|
"fontScale": fontScale
|
||||||
|
}, null, 2)
|
||||||
|
|
||||||
|
onPublishTypographyChanged: typographyPublishDebounce.restart()
|
||||||
|
onTypographyJsonChanged: typographyPublishDebounce.restart()
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: typographyFileView
|
||||||
|
path: root.publishTypography ? root.stateDir + "/dms-typography.json" : ""
|
||||||
|
blockLoading: false
|
||||||
|
printErrors: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: typographyPublishDebounce
|
||||||
|
interval: 250
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
if (!root.publishTypography)
|
||||||
|
return;
|
||||||
|
typographyFileView.setText(root.typographyJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
target: "theme"
|
target: "theme"
|
||||||
|
|
||||||
|
|||||||
@@ -439,7 +439,7 @@ function mangoActiveWorkspace(raw, screenName) {
|
|||||||
|
|
||||||
function mangoWindowsOnWorkspace(windows, workspace) {
|
function mangoWindowsOnWorkspace(windows, workspace) {
|
||||||
// mangoTags are 1-based; workspace.id is 0-based.
|
// mangoTags are 1-based; workspace.id is 0-based.
|
||||||
return windows.filter(win => win && (win.mangoTags || []).includes(workspace.id + 1));
|
return windows.filter(win => win && win.mangoMonitor === workspace.output && (win.mangoTags || []).includes(workspace.id + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function i3Key(ws) {
|
function i3Key(ws) {
|
||||||
|
|||||||
@@ -744,8 +744,12 @@ Item {
|
|||||||
readonly property real barSurfaceThickness: Theme.px(effectiveBarThickness + surfaceSpacing + ((renderBarConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel && spansEdge ? _wingR : 0), _dpr) + _shadowBuffer
|
readonly property real barSurfaceThickness: Theme.px(effectiveBarThickness + surfaceSpacing + ((renderBarConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel && spansEdge ? _wingR : 0), _dpr) + _shadowBuffer
|
||||||
readonly property bool islandSheetOut: islandHost?.sheetOut ?? false
|
readonly property bool islandSheetOut: islandHost?.sheetOut ?? false
|
||||||
readonly property real islandSatelliteShadowBuffer: isIsland && islandSatellitesEnabled && !islandSatelliteBackground ? _shadowBuffer : 0
|
readonly property real islandSatelliteShadowBuffer: isIsland && islandSatellitesEnabled && !islandSatelliteBackground ? _shadowBuffer : 0
|
||||||
readonly property real hostThickness: isIsland ? Math.max(islandHost?.hostThickness ?? 0, islandStripThickness + islandSatelliteShadowBuffer) : Math.max(barSurfaceThickness, islandSheetOut ? islandHost.hostThickness : 0)
|
// A grown layer surface jumps to its new origin before the client draws at the new size, so a far-edge host never grows for the sheet.
|
||||||
readonly property real hideSlideThickness: isIsland ? hostThickness : barSurfaceThickness
|
readonly property bool islandReservesSheet: !!islandHost && (axis.edge === "bottom" || axis.edge === "right")
|
||||||
|
readonly property real hostThickness: isIsland ? Math.max(islandHost?.hostThickness ?? 0, islandStripThickness + islandSatelliteShadowBuffer) : Math.max(barSurfaceThickness, islandSheetOut || islandReservesSheet ? islandHost.hostThickness : 0)
|
||||||
|
// The host reserves the expanded island's height, so sliding by it would move a compact island off-screen within a frame.
|
||||||
|
readonly property real islandCompactThickness: Math.max(islandStripThickness + islandSatelliteShadowBuffer, (islandHost?.outerGap ?? 0) + (islandHost?.compactThickness ?? 0) + (islandHost?.shadowPadding ?? 0))
|
||||||
|
readonly property real hideSlideThickness: isIsland ? islandCompactThickness : barSurfaceThickness
|
||||||
readonly property real surfaceImplicitHeight: !isVertical ? hostThickness : 0
|
readonly property real surfaceImplicitHeight: !isVertical ? hostThickness : 0
|
||||||
readonly property real surfaceImplicitWidth: isVertical ? hostThickness : 0
|
readonly property real surfaceImplicitWidth: isVertical ? hostThickness : 0
|
||||||
|
|
||||||
|
|||||||
@@ -39,26 +39,20 @@ BasePill {
|
|||||||
return Qt.rgba(from.r + (to.r - from.r) * progress, from.g + (to.g - from.g) * progress, from.b + (to.b - from.b) * progress, from.a + (to.a - from.a) * progress);
|
return Qt.rgba(from.r + (to.r - from.r) * progress, from.g + (to.g - from.g) * progress, from.b + (to.b - from.b) * progress, from.a + (to.a - from.a) * progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
SequentialAnimation on criticalPulse {
|
property int criticalTick: 0
|
||||||
|
|
||||||
|
// Stepped on purpose: an Animation repaints the bar at the full refresh rate.
|
||||||
|
Timer {
|
||||||
|
interval: 50
|
||||||
|
repeat: true
|
||||||
running: battery.critical && battery.surfaceLive && !SettingsData.reduceMotion
|
running: battery.critical && battery.surfaceLive && !SettingsData.reduceMotion
|
||||||
loops: Animation.Infinite
|
|
||||||
onRunningChanged: {
|
onRunningChanged: {
|
||||||
if (!running)
|
battery.criticalTick = 0;
|
||||||
battery.criticalPulse = 0;
|
battery.criticalPulse = 0;
|
||||||
}
|
}
|
||||||
|
onTriggered: {
|
||||||
NumberAnimation {
|
battery.criticalTick = (battery.criticalTick + 1) % 40;
|
||||||
from: 0
|
battery.criticalPulse = 1 - Math.abs(20 - battery.criticalTick) / 20;
|
||||||
to: 1
|
|
||||||
duration: 1000
|
|
||||||
easing.type: Easing.Linear
|
|
||||||
}
|
|
||||||
|
|
||||||
NumberAnimation {
|
|
||||||
from: 1
|
|
||||||
to: 0
|
|
||||||
duration: 1000
|
|
||||||
easing.type: Easing.Linear
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ BasePill {
|
|||||||
}
|
}
|
||||||
property bool isOccupied: root.useNativeWorkspaces && CompositorService.workspaceOccupied(record)
|
property bool isOccupied: root.useNativeWorkspaces && CompositorService.workspaceOccupied(record)
|
||||||
property bool isPlaceholder: !!(record && record.placeholder)
|
property bool isPlaceholder: !!(record && record.placeholder)
|
||||||
property bool isHovered: mouseArea.containsMouse
|
property bool isHovered: pillHover.hovered
|
||||||
|
|
||||||
property bool loadedIsUrgent: false
|
property bool loadedIsUrgent: false
|
||||||
property bool isUrgent: root.useNativeWorkspaces ? CompositorService.workspaceUrgent(record, loadedIsUrgent) : (modelData?.urgent ?? false)
|
property bool isUrgent: root.useNativeWorkspaces ? CompositorService.workspaceUrgent(record, loadedIsUrgent) : (modelData?.urgent ?? false)
|
||||||
@@ -615,6 +615,11 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: pillHover
|
||||||
|
enabled: !isPlaceholder
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -680,6 +680,8 @@ DPopout {
|
|||||||
readonly property bool ready: targetHeight >= 0 && settledHeight === targetHeight
|
readonly property bool ready: targetHeight >= 0 && settledHeight === targetHeight
|
||||||
readonly property real availableHeight: root.screen ? root.screen.height - mainContainer.horizontalChromeHeight - DashMetrics.contentPadding * 2 - Theme.barHeight - Theme.spacingL * 2 : contentHeight
|
readonly property real availableHeight: root.screen ? root.screen.height - mainContainer.horizontalChromeHeight - DashMetrics.contentPadding * 2 - Theme.barHeight - Theme.spacingL * 2 : contentHeight
|
||||||
readonly property int rowBudget: DashMetrics.rowCapFor(availableHeight)
|
readonly property int rowBudget: DashMetrics.rowCapFor(availableHeight)
|
||||||
|
// Growing a panel not hung from a top bar moves the grid under a held card, which retargets the drop.
|
||||||
|
readonly property bool heightHeld: (currentItem?.cardInteracting ?? false) && root.effectiveBarPosition % 4 !== SettingsData.Top
|
||||||
|
|
||||||
x: (root.verticalNavigation && root.navigationEdge === SettingsData.Left ? root.navigationWidth : 0) - root.editGutter
|
x: (root.verticalNavigation && root.navigationEdge === SettingsData.Left ? root.navigationWidth : 0) - root.editGutter
|
||||||
y: (!root.verticalNavigation && root.navigationEdge !== SettingsData.Bottom ? mainContainer.horizontalChromeHeight : 0) - root.editGutter
|
y: (!root.verticalNavigation && root.navigationEdge !== SettingsData.Bottom ? mainContainer.horizontalChromeHeight : 0) - root.editGutter
|
||||||
@@ -691,12 +693,13 @@ DPopout {
|
|||||||
clip: contentHeight > height
|
clip: contentHeight > height
|
||||||
|
|
||||||
function updateContentHeight() {
|
function updateContentHeight() {
|
||||||
if (targetHeight < 0)
|
if (targetHeight < 0 || heightHeld)
|
||||||
return;
|
return;
|
||||||
settledHeight = targetHeight;
|
settledHeight = targetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
onTargetHeightChanged: Qt.callLater(updateContentHeight)
|
onTargetHeightChanged: Qt.callLater(updateContentHeight)
|
||||||
|
onHeightHeldChanged: Qt.callLater(updateContentHeight)
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: emptyContent
|
id: emptyContent
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ Singleton {
|
|||||||
readonly property int mediaLyricsRequestTimeout: 16000
|
readonly property int mediaLyricsRequestTimeout: 16000
|
||||||
readonly property int mediaLyricsLoadingDelay: 300
|
readonly property int mediaLyricsLoadingDelay: 300
|
||||||
readonly property real mediaLyricsPositionTolerance: 0.05
|
readonly property real mediaLyricsPositionTolerance: 0.05
|
||||||
|
readonly property real mediaLyricsWholeSecondSlack: 0.005
|
||||||
readonly property int mediaLyricsPositionProbeInterval: 5000
|
readonly property int mediaLyricsPositionProbeInterval: 5000
|
||||||
readonly property real mediaLyricsPositionProbeDrift: 1.5
|
readonly property real mediaLyricsPositionProbeDrift: 1.5
|
||||||
readonly property real mediaLyricsPositionProbeThreshold: 1
|
readonly property real mediaLyricsPositionProbeThreshold: 1
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Item {
|
|||||||
readonly property Item focusTarget: grid
|
readonly property Item focusTarget: grid
|
||||||
readonly property bool blocksTabNavigation: editMode || addMenu.open || optionsSheet.shown
|
readonly property bool blocksTabNavigation: editMode || addMenu.open || optionsSheet.shown
|
||||||
readonly property bool cardResizing: grid.sizePreview !== null
|
readonly property bool cardResizing: grid.sizePreview !== null
|
||||||
|
readonly property bool cardInteracting: grid.interacting
|
||||||
|
|
||||||
implicitHeight: Math.max(DashMetrics.tabMinHeight, grid.implicitHeight)
|
implicitHeight: Math.max(DashMetrics.tabMinHeight, grid.implicitHeight)
|
||||||
LayoutMirroring.enabled: I18n.isRtl
|
LayoutMirroring.enabled: I18n.isRtl
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ Item {
|
|||||||
interval: DashMetrics.mediaPositionPollInterval
|
interval: DashMetrics.mediaPositionPollInterval
|
||||||
running: root.live && root.activePlayer?.playbackState === MprisPlaybackState.Playing && !root.isSeeking
|
running: root.live && root.activePlayer?.playbackState === MprisPlaybackState.Playing && !root.isSeeking
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: root.activePlayer?.positionChanged()
|
onTriggered: MprisController.refreshPosition(root.activePlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncAudioRef(wanted) {
|
function syncAudioRef(wanted) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Card {
|
|||||||
interval: DashMetrics.mediaPositionPollInterval
|
interval: DashMetrics.mediaPositionPollInterval
|
||||||
running: root.live && root.visible && root.interactive && root.showSeekbar && root.playing && !root.isSeeking
|
running: root.live && root.visible && root.interactive && root.showSeekbar && root.playing && !root.isSeeking
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: root.activePlayer?.positionSupported && root.activePlayer.positionChanged()
|
onTriggered: MprisController.refreshPosition(root.activePlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ FocusScope {
|
|||||||
readonly property var addable: grid.addableEntries
|
readonly property var addable: grid.addableEntries
|
||||||
readonly property int usedColumns: grid.usedColumns
|
readonly property int usedColumns: grid.usedColumns
|
||||||
readonly property bool cardResizing: grid.sizePreview !== null
|
readonly property bool cardResizing: grid.sizePreview !== null
|
||||||
|
readonly property bool cardInteracting: grid.interacting
|
||||||
readonly property bool blocksTabNavigation: grid.blocksTabNavigation || detailSheet.shown || editorSheet.shown || optionsSheet.shown || addMenu.open
|
readonly property bool blocksTabNavigation: grid.blocksTabNavigation || detailSheet.shown || editorSheet.shown || optionsSheet.shown || addMenu.open
|
||||||
|
|
||||||
implicitWidth: DashMetrics.contentWidthFor(SettingsData.showWeekNumber)
|
implicitWidth: DashMetrics.contentWidthFor(SettingsData.showWeekNumber)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ Item {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
readonly property bool blocksTabNavigation: widgets.blocksTabNavigation
|
readonly property bool blocksTabNavigation: widgets.blocksTabNavigation
|
||||||
|
readonly property bool cardInteracting: widgets.cardInteracting
|
||||||
readonly property var forecastOptions: [DashRegistry.choice("forecast", I18n.tr("Forecast", "weather widget option label for forecast display type"), "chart", [
|
readonly property var forecastOptions: [DashRegistry.choice("forecast", I18n.tr("Forecast", "weather widget option label for forecast display type"), "chart", [
|
||||||
{
|
{
|
||||||
"value": "chart",
|
"value": "chart",
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Rectangle {
|
|||||||
|
|
||||||
function saveDisplayImage() {
|
function saveDisplayImage() {
|
||||||
const data = root.notificationData;
|
const data = root.notificationData;
|
||||||
if (!root.persistImage || !data?.hasDisplayImage || data.persistedImagePath)
|
if (!root.persistImage || !data?.notification || !data.hasDisplayImage || data.persistedImagePath)
|
||||||
return;
|
return;
|
||||||
const image = data.image || "";
|
const image = data.image || "";
|
||||||
if (!image.startsWith("image://qsimage/") && !NotificationService.notificationIconFromImage(image).startsWith("/"))
|
if (!image.startsWith("image://qsimage/") && !NotificationService.notificationIconFromImage(image).startsWith("/"))
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ PanelWindow {
|
|||||||
readonly property bool cardShown: presenting && (presentationProgress > 0 || !exiting)
|
readonly property bool cardShown: presenting && (presentationProgress > 0 || !exiting)
|
||||||
readonly property bool layoutPinned: !exiting && (hovered || contextMenuActive || swipeActive)
|
readonly property bool layoutPinned: !exiting && (hovered || contextMenuActive || swipeActive)
|
||||||
property bool exiting: false
|
property bool exiting: false
|
||||||
|
property var exitSnapshot: null
|
||||||
property bool exitStarted: false
|
property bool exitStarted: false
|
||||||
property bool collapseChromeOnExit: false
|
property bool collapseChromeOnExit: false
|
||||||
property bool _isDestroying: false
|
property bool _isDestroying: false
|
||||||
@@ -124,6 +125,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
enterAnimation.stop();
|
enterAnimation.stop();
|
||||||
enterDelay.stop();
|
enterDelay.stop();
|
||||||
|
exitSnapshot = snapshotNotification(notificationData);
|
||||||
exiting = true;
|
exiting = true;
|
||||||
if (NotificationService.removeFromVisibleNotifications)
|
if (NotificationService.removeFromVisibleNotifications)
|
||||||
NotificationService.removeFromVisibleNotifications(win.notificationData);
|
NotificationService.removeFromVisibleNotifications(win.notificationData);
|
||||||
@@ -172,6 +174,29 @@ PanelWindow {
|
|||||||
win.exitFinished();
|
win.exitFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The wrapper is destroyed as soon as its notification closes, which would blank the card mid-exit.
|
||||||
|
function snapshotNotification(data) {
|
||||||
|
if (!data)
|
||||||
|
return null;
|
||||||
|
return {
|
||||||
|
"appName": data.appName,
|
||||||
|
"appIcon": data.appIcon,
|
||||||
|
"desktopEntry": data.desktopEntry,
|
||||||
|
"summary": data.summary,
|
||||||
|
"body": data.body,
|
||||||
|
"htmlBody": data.htmlBody,
|
||||||
|
"image": data.image,
|
||||||
|
"hasDisplayImage": data.hasDisplayImage,
|
||||||
|
"displayImage": data.displayImage,
|
||||||
|
"persistedImagePath": data.persistedImagePath,
|
||||||
|
"timeStr": data.timeStr,
|
||||||
|
"urgency": data.urgency,
|
||||||
|
"actions": Array.from(data.actions || [], action => ({
|
||||||
|
"text": action.text
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function closeTransientUi() {
|
function closeTransientUi() {
|
||||||
transientSurfaces.closeAll();
|
transientSurfaces.closeAll();
|
||||||
popupContextMenuLoader.active = false;
|
popupContextMenuLoader.active = false;
|
||||||
@@ -719,7 +744,7 @@ PanelWindow {
|
|||||||
chipColor: Theme.notificationChipSurface
|
chipColor: Theme.notificationChipSurface
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: win.inlineHeightAnimating ? Math.min(targetHeight, cardSurface.height - win.timeoutRailClearance) : targetHeight
|
height: win.inlineHeightAnimating ? Math.min(targetHeight, cardSurface.height - win.timeoutRailClearance) : targetHeight
|
||||||
notificationData: win.notificationData
|
notificationData: win.exitSnapshot ?? win.notificationData
|
||||||
descriptionExpanded: win.descriptionExpanded
|
descriptionExpanded: win.descriptionExpanded
|
||||||
privacyMode: SettingsData.notificationPopupPrivacyMode
|
privacyMode: SettingsData.notificationPopupPrivacyMode
|
||||||
bodyInvokesAction: win.bodyClickInvokesAction
|
bodyInvokesAction: win.bodyClickInvokesAction
|
||||||
|
|||||||
@@ -557,6 +557,13 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: _sync(NotificationService.visibleNotifications)
|
Component.onCompleted: _sync(NotificationService.visibleNotifications)
|
||||||
|
Component.onDestruction: {
|
||||||
|
for (const p of popupWindows)
|
||||||
|
p?.destroy();
|
||||||
|
const screenName = manager.modelData?.name || "";
|
||||||
|
if (screenName)
|
||||||
|
ConnectedModeState.releaseSurface(screenName, "notification", "notification:" + screenName);
|
||||||
|
}
|
||||||
onPopupSpacingChanged: _repositionAll()
|
onPopupSpacingChanged: _repositionAll()
|
||||||
onNotificationConnectedModeChanged: _scheduleNotificationChromeSync()
|
onNotificationConnectedModeChanged: _scheduleNotificationChromeSync()
|
||||||
onCloseGapNotificationsChanged: _scheduleNotificationChromeSync()
|
onCloseGapNotificationsChanged: _scheduleNotificationChromeSync()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Column {
|
|||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
property string editingDockId: ""
|
property string editingDockId: ""
|
||||||
property string renameDraft: ""
|
property string renameDraft: ""
|
||||||
|
readonly property var dockPages: ["dock_general", "dock_widgets", "dock_appearance"].map(id => SettingsTabs.page(id)).filter(page => page)
|
||||||
|
|
||||||
function finishRename(value) {
|
function finishRename(value) {
|
||||||
const id = editingDockId;
|
const id = editingDockId;
|
||||||
@@ -44,11 +45,10 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
|
||||||
iconName: "dock_to_bottom"
|
iconName: "dock_to_bottom"
|
||||||
title: I18n.tr("Docks", "noun plural, settings card title listing configured docks")
|
title: I18n.tr("Docks", "noun plural, settings card title listing configured docks")
|
||||||
settingKey: "dockConfiguration"
|
settingKey: "dockConfiguration"
|
||||||
tags: ["dock", "configuration", "add", "remove", "name", "show", "enable"]
|
tags: ["dock", "configuration", "add", "remove", "show", "enable"]
|
||||||
headerActions: DButton {
|
headerActions: DButton {
|
||||||
text: I18n.tr("Add", "verb, button that adds a new item to a list")
|
text: I18n.tr("Add", "verb, button that adds a new item to a list")
|
||||||
iconName: "add"
|
iconName: "add"
|
||||||
@@ -75,11 +75,18 @@ Column {
|
|||||||
onDeleteRequested: root.removeDock(modelData.id)
|
onDeleteRequested: root.removeDock(modelData.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
iconName: "dock_to_bottom"
|
||||||
|
title: dock.config?.name ?? ""
|
||||||
|
settingKey: "dockPlacement"
|
||||||
|
tags: ["dock", "layout", "placement", "position", "edge", "name", "rename"]
|
||||||
|
visible: dock.hasConfig
|
||||||
|
|
||||||
SettingsRow {
|
SettingsRow {
|
||||||
title: I18n.tr("Name")
|
title: I18n.tr("Name")
|
||||||
subtitle: root.editingDockId ? "" : dock.config?.name ?? ""
|
subtitle: root.editingDockId ? "" : dock.config?.name ?? ""
|
||||||
visible: dock.hasConfig
|
|
||||||
|
|
||||||
DActionButton {
|
DActionButton {
|
||||||
iconName: root.editingDockId ? "check" : "edit"
|
iconName: root.editingDockId ? "check" : "edit"
|
||||||
@@ -120,25 +127,33 @@ Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SettingsCard {
|
SettingsRow {
|
||||||
width: parent.width
|
title: I18n.tr("Layout", "noun, settings section title for arrangement options")
|
||||||
visible: dock.hasConfig
|
|
||||||
iconName: "dock_to_bottom"
|
|
||||||
title: I18n.tr("Layout")
|
|
||||||
settingKey: "dockPlacement"
|
|
||||||
tags: ["dock", "layout", "placement", "position", "edge"]
|
|
||||||
|
|
||||||
SettingsLayoutPicker {
|
body: SettingsLayoutPicker {
|
||||||
edgePlacement: true
|
edgePlacement: true
|
||||||
choices: [SettingsData.Position.Top, SettingsData.Position.Bottom, SettingsData.Position.Left, SettingsData.Position.Right].map(position => ({
|
choices: [SettingsData.Position.Top, SettingsData.Position.Bottom, SettingsData.Position.Left, SettingsData.Position.Right].map(position => ({
|
||||||
key: String(position),
|
key: String(position),
|
||||||
label: dock.positionLabel(position),
|
label: dock.positionLabel(position),
|
||||||
enabled: dock.positionChoices.includes(position)
|
enabled: dock.positionChoices.includes(position)
|
||||||
}))
|
}))
|
||||||
selectedKey: String(dock.config?.position ?? SettingsData.Position.Bottom)
|
selectedKey: String(dock.config?.position ?? SettingsData.Position.Bottom)
|
||||||
onSelected: key => dock.setEnabled(true, Number(key))
|
onSelected: key => dock.setEnabled(true, Number(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.dockPages
|
||||||
|
|
||||||
|
delegate: SettingsNavRow {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
iconName: modelData.icon
|
||||||
|
title: modelData.text
|
||||||
|
hint: modelData.hint ?? ""
|
||||||
|
onClicked: keyboard => root.parentModal?.navigateTo(modelData.id, keyboard)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -399,12 +399,16 @@ Column {
|
|||||||
|
|
||||||
readonly property var fillModes: ["Stretch", "Fit", "Fill", "Scrolling", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
readonly property var fillModes: ["Stretch", "Fit", "Fill", "Scrolling", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
||||||
readonly property var fillModeLabels: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Scroll", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile Vertically", "wallpaper fill mode"), I18n.tr("Tile Horizontally", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")]
|
readonly property var fillModeLabels: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Scroll", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile Vertically", "wallpaper fill mode"), I18n.tr("Tile Horizontally", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")]
|
||||||
|
// dms picks the animation driver at launch from this setting
|
||||||
|
readonly property bool simpleAnimationDriver: Quickshell.env("QSG_USE_SIMPLE_ANIMATION_DRIVER") === "1"
|
||||||
|
readonly property bool driverMismatch: (SettingsData.wallpaperFillMode === "Scrolling") !== simpleAnimationDriver
|
||||||
|
|
||||||
tab: "wallpaper"
|
tab: "wallpaper"
|
||||||
tags: ["background", "fill", "fit", "stretch", "tile", "scale"]
|
tags: ["background", "fill", "fit", "stretch", "tile", "scale"]
|
||||||
settingKey: "wallpaperFillMode"
|
settingKey: "wallpaperFillMode"
|
||||||
resetKeys: root.perMonitor ? [] : ["wallpaperFillMode"]
|
resetKeys: root.perMonitor ? [] : ["wallpaperFillMode"]
|
||||||
text: I18n.tr("Fill mode")
|
text: I18n.tr("Fill mode")
|
||||||
|
description: driverMismatch ? I18n.tr("Requires restart") : ""
|
||||||
visible: root.wallpaperIsImage
|
visible: root.wallpaperIsImage
|
||||||
dropdownWidth: 190
|
dropdownWidth: 190
|
||||||
options: fillModeLabels
|
options: fillModeLabels
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ SettingsDropdownRow {
|
|||||||
function _enumerate() {
|
function _enumerate() {
|
||||||
if (_enumerated)
|
if (_enumerated)
|
||||||
return;
|
return;
|
||||||
const bundled = DCommon.Fonts.bundledFamilies.filter(f => f !== root.defaultFamily);
|
_families = ["Default"].concat(DCommon.Fonts.selectableFamilies(root.defaultFamily));
|
||||||
const system = Qt.fontFamilies().filter(f => !f.startsWith(".") && f !== root.defaultFamily && !bundled.includes(f));
|
|
||||||
system.sort();
|
|
||||||
_families = ["Default"].concat(bundled, system);
|
|
||||||
_enumerated = true;
|
_enumerated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ Singleton {
|
|||||||
const yKey = y.niriWindowId !== undefined ? y.niriWindowId : y.mangoWindowId;
|
const yKey = y.niriWindowId !== undefined ? y.niriWindowId : y.mangoWindowId;
|
||||||
if (xKey === undefined || yKey === undefined)
|
if (xKey === undefined || yKey === undefined)
|
||||||
return false;
|
return false;
|
||||||
if (xKey !== yKey || x.niriWorkspaceId !== y.niriWorkspaceId || x.appId !== y.appId || x.title !== y.title || !!x.activated !== !!y.activated || !!x.fullscreen !== !!y.fullscreen || !!x.maximized !== !!y.maximized || !!x.minimized !== !!y.minimized)
|
if (xKey !== yKey || x.niriWorkspaceId !== y.niriWorkspaceId || x.mangoMonitor !== y.mangoMonitor || x.appId !== y.appId || x.title !== y.title || !!x.activated !== !!y.activated || !!x.fullscreen !== !!y.fullscreen || !!x.maximized !== !!y.maximized || !!x.minimized !== !!y.minimized)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -90,7 +90,11 @@ QtObject {
|
|||||||
if (enabled && (state === "none" || state === "error"))
|
if (enabled && (state === "none" || state === "error"))
|
||||||
useEmbeddedText(state);
|
useEmbeddedText(state);
|
||||||
}
|
}
|
||||||
onPositionChanged: scheduleAnchor()
|
onPositionChanged: {
|
||||||
|
if (MprisController.refreshingPosition || flooredEcho())
|
||||||
|
return;
|
||||||
|
scheduleAnchor();
|
||||||
|
}
|
||||||
onRateChanged: updatePlaybackClock()
|
onRateChanged: updatePlaybackClock()
|
||||||
onPlayingChanged: {
|
onPlayingChanged: {
|
||||||
probe = null;
|
probe = null;
|
||||||
@@ -379,6 +383,7 @@ QtObject {
|
|||||||
if (!line || !Number.isFinite(line.t))
|
if (!line || !Number.isFinite(line.t))
|
||||||
return false;
|
return false;
|
||||||
player.position = Math.max(0.1, Math.min(line.t, duration * 0.99));
|
player.position = Math.max(0.1, Math.min(line.t, duration * 0.99));
|
||||||
|
reanchor();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +439,13 @@ QtObject {
|
|||||||
resync();
|
resync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pear-desktop floors Position to whole seconds on pause, resume and track events.
|
||||||
|
function flooredEcho() {
|
||||||
|
const lead = currentTime() - position;
|
||||||
|
const whole = Math.abs(position - Math.round(position)) < DashMetrics.mediaLyricsWholeSecondSlack;
|
||||||
|
return whole && lead >= 0 && lead < 1 + DashMetrics.mediaLyricsPositionTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
function scheduleAnchor() {
|
function scheduleAnchor() {
|
||||||
positionWall = Date.now();
|
positionWall = Date.now();
|
||||||
if (enabled && synced && !stopped && !anchorUpdate.running)
|
if (enabled && synced && !stopped && !anchorUpdate.running)
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ Singleton {
|
|||||||
property bool _mprisPublishDirty: false
|
property bool _mprisPublishDirty: false
|
||||||
property int _mprisConnectionEpoch: 0
|
property int _mprisConnectionEpoch: 0
|
||||||
property int positionConsumers: 0
|
property int positionConsumers: 0
|
||||||
|
property bool refreshingPosition: false
|
||||||
|
|
||||||
|
function refreshPosition(player) {
|
||||||
|
if (!player?.positionSupported)
|
||||||
|
return;
|
||||||
|
refreshingPosition = true;
|
||||||
|
player.positionChanged();
|
||||||
|
refreshingPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
function addPositionRef() {
|
function addPositionRef() {
|
||||||
positionConsumers++;
|
positionConsumers++;
|
||||||
@@ -398,7 +407,7 @@ Singleton {
|
|||||||
interval: 1000
|
interval: 1000
|
||||||
running: root.positionConsumers > 0 && root.activePlayer?.playbackState === MprisPlaybackState.Playing
|
running: root.positionConsumers > 0 && root.activePlayer?.playbackState === MprisPlaybackState.Playing
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: root.activePlayer?.positionChanged()
|
onTriggered: root.refreshPosition(root.activePlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
function _hasMPRISSubscription(): bool {
|
function _hasMPRISSubscription(): bool {
|
||||||
|
|||||||
@@ -334,9 +334,18 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sameScales(displayScales, scales))
|
||||||
|
return;
|
||||||
displayScales = scales;
|
displayScales = scales;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sameScales(a, b) {
|
||||||
|
const names = Object.keys(a);
|
||||||
|
if (names.length !== Object.keys(b).length)
|
||||||
|
return false;
|
||||||
|
return names.every(name => a[name] === b[name]);
|
||||||
|
}
|
||||||
|
|
||||||
function sortWindowsByLayout(windowList) {
|
function sortWindowsByLayout(windowList) {
|
||||||
const enriched = windowList.map(w => {
|
const enriched = windowList.map(w => {
|
||||||
const ws = workspaces[w.workspace_id];
|
const ws = workspaces[w.workspace_id];
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ Item {
|
|||||||
isPlaying: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing
|
isPlaying: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing
|
||||||
onFrameTicked: {
|
onFrameTicked: {
|
||||||
if (!root.isSeeking)
|
if (!root.isSeeking)
|
||||||
activePlayer.positionChanged();
|
MprisController.refreshPosition(activePlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ local config_home = vim.env.XDG_CONFIG_HOME
|
|||||||
if config_home == nil or #config_home == 0 then
|
if config_home == nil or #config_home == 0 then
|
||||||
config_home = vim.fs.joinpath(vim.env.HOME, ".config")
|
config_home = vim.fs.joinpath(vim.env.HOME, ".config")
|
||||||
end
|
end
|
||||||
local settings_file_path = vim.fs.joinpath(config_home, "Dux Shell", "settings.json")
|
local settings_file_path = vim.fs.joinpath(config_home, "dms", "settings.json")
|
||||||
local settings_file = io.open(settings_file_path, "r")
|
local settings_file = io.open(settings_file_path, "r")
|
||||||
if settings_file == nil then
|
if settings_file == nil then
|
||||||
vim.notify(
|
vim.notify(
|
||||||
|
|||||||
+2
-2
@@ -36,8 +36,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"windows": [
|
"windows": [
|
||||||
{ "appId": "alacritty", "mangoTags": [3] },
|
{ "appId": "alacritty", "mangoMonitor": "DP-1", "mangoTags": [3] },
|
||||||
{ "appId": "firefox", "mangoTags": [2, 3] },
|
{ "appId": "firefox", "mangoMonitor": "DP-1", "mangoTags": [2, 3] },
|
||||||
{ "appId": "untagged" }
|
{ "appId": "untagged" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ const aqueousService = source("../Services/AqueousService.qml");
|
|||||||
const model = vm.createContext({});
|
const model = vm.createContext({});
|
||||||
vm.runInContext(source("../Common/WindowModel.js").replace(/^\.pragma.*$/m, ""), model);
|
vm.runInContext(source("../Common/WindowModel.js").replace(/^\.pragma.*$/m, ""), model);
|
||||||
|
|
||||||
|
test("mango monitor changes invalidate cached toplevels", () => {
|
||||||
|
const context = vm.createContext({});
|
||||||
|
lift(compositorService, "_toplevelListEquivalent", context);
|
||||||
|
const window = { mangoWindowId: 1, appId: "app1", mangoMonitor: "DP-1", mangoTags: [1] };
|
||||||
|
assert.equal(context._toplevelListEquivalent([window], [{ ...window }]), true);
|
||||||
|
assert.equal(context._toplevelListEquivalent([window], [{ ...window, mangoMonitor: "HDMI-A-1" }]), false);
|
||||||
|
});
|
||||||
|
|
||||||
function niriState(scenario) {
|
function niriState(scenario) {
|
||||||
const s = fixture("niri")[scenario];
|
const s = fixture("niri")[scenario];
|
||||||
const toplevels = s.toplevels.map(t => ({ ...t }));
|
const toplevels = s.toplevels.map(t => ({ ...t }));
|
||||||
|
|||||||
@@ -291,8 +291,23 @@ test("mango scroll targets, active tag and windows", () => {
|
|||||||
assert.deepEqual(plain(model.mangoActiveWorkspace(dp1, "DP-1")), { id: 2, idx: 3, name: "", output: "DP-1", active: true, placeholder: false });
|
assert.deepEqual(plain(model.mangoActiveWorkspace(dp1, "DP-1")), { id: 2, idx: 3, name: "", output: "DP-1", active: true, placeholder: false });
|
||||||
assert.equal(model.mangoActiveWorkspace(mango("available", "HDMI-A-1"), "HDMI-A-1").id, 0);
|
assert.equal(model.mangoActiveWorkspace(mango("available", "HDMI-A-1"), "HDMI-A-1").id, 0);
|
||||||
assert.equal(model.mangoActiveWorkspace(mango("available", "DP-2"), "DP-2"), null);
|
assert.equal(model.mangoActiveWorkspace(mango("available", "DP-2"), "DP-2"), null);
|
||||||
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(dp1.windows, { id: 2 }), "appId"), ["alacritty", "firefox"]);
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(dp1.windows, { id: 2, output: "DP-1" }), "appId"), ["alacritty", "firefox"]);
|
||||||
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(dp1.windows, { id: 1 }), "appId"), ["firefox"]);
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(dp1.windows, { id: 1, output: "DP-1" }), "appId"), ["firefox"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mango workspace apps follow their output when windows share a tag", () => {
|
||||||
|
const windows = [
|
||||||
|
{ appId: "app1", mangoMonitor: "DP-1", mangoTags: [1] },
|
||||||
|
{ appId: "app2", mangoMonitor: "HDMI-A-1", mangoTags: [1] }
|
||||||
|
];
|
||||||
|
const dp1 = model.mangoRecord(0, {}, "DP-1");
|
||||||
|
const hdmi = model.mangoRecord(0, {}, "HDMI-A-1");
|
||||||
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(windows, dp1), "appId"), ["app1"]);
|
||||||
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(windows, hdmi), "appId"), ["app2"]);
|
||||||
|
|
||||||
|
windows[0].mangoMonitor = "HDMI-A-1";
|
||||||
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(windows, dp1), "appId"), []);
|
||||||
|
assert.deepEqual(pick(model.mangoWindowsOnWorkspace(windows, hdmi), "appId"), ["app1", "app2"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("i3 lists order numbered before named and strip the number prefix", () => {
|
test("i3 lists order numbered before named and strip the number prefix", () => {
|
||||||
|
|||||||
@@ -286,6 +286,11 @@ def extract_i18n_string(value):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_status_notice(value):
|
||||||
|
"""A description with an empty branch only shows while some state holds; it is not searchable text."""
|
||||||
|
return re.search(r"""\?\s*(""|'')\s*:|:\s*(""|'')\s*$""", value.strip()) is not None
|
||||||
|
|
||||||
|
|
||||||
def extract_tags(value):
|
def extract_tags(value):
|
||||||
match = re.search(r"\[([^\]]+)\]", value)
|
match = re.search(r"\[([^\]]+)\]", value)
|
||||||
if not match:
|
if not match:
|
||||||
@@ -489,7 +494,7 @@ def find_settings_components(content, filename, wrappers, tab_meta, hub_meta):
|
|||||||
|
|
||||||
desc_raw = extract_property(own, "description") or extract_property(own, "summary") or defaults.get("description") or borrowed_description(block, setting_key)
|
desc_raw = extract_property(own, "description") or extract_property(own, "summary") or defaults.get("description") or borrowed_description(block, setting_key)
|
||||||
description = None
|
description = None
|
||||||
if desc_raw:
|
if desc_raw and not is_status_notice(desc_raw):
|
||||||
description = extract_i18n_string(desc_raw)
|
description = extract_i18n_string(desc_raw)
|
||||||
|
|
||||||
visible_raw = extract_property(own_scope(block), "visible")
|
visible_raw = extract_property(own_scope(block), "visible")
|
||||||
|
|||||||
@@ -941,6 +941,26 @@
|
|||||||
"icon": "dock_to_bottom",
|
"icon": "dock_to_bottom",
|
||||||
"description": "Position, pinned apps, trash"
|
"description": "Position, pinned apps, trash"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "dockPlacement",
|
||||||
|
"label": "Dock",
|
||||||
|
"tabIndex": -1,
|
||||||
|
"category": "Dock",
|
||||||
|
"keywords": [
|
||||||
|
"dock",
|
||||||
|
"edge",
|
||||||
|
"launcher bar",
|
||||||
|
"layout",
|
||||||
|
"name",
|
||||||
|
"panel",
|
||||||
|
"placement",
|
||||||
|
"position",
|
||||||
|
"rename",
|
||||||
|
"taskbar"
|
||||||
|
],
|
||||||
|
"page": "dock",
|
||||||
|
"icon": "dock_to_bottom"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "dockConfiguration",
|
"section": "dockConfiguration",
|
||||||
"label": "Docks",
|
"label": "Docks",
|
||||||
@@ -953,7 +973,6 @@
|
|||||||
"docks",
|
"docks",
|
||||||
"enable",
|
"enable",
|
||||||
"launcher bar",
|
"launcher bar",
|
||||||
"name",
|
|
||||||
"panel",
|
"panel",
|
||||||
"remove",
|
"remove",
|
||||||
"show",
|
"show",
|
||||||
@@ -1407,24 +1426,6 @@
|
|||||||
"page": "theme_surfaces",
|
"page": "theme_surfaces",
|
||||||
"description": "Faint edge on cards, pills and widgets"
|
"description": "Faint edge on cards, pills and widgets"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"section": "dockPlacement",
|
|
||||||
"label": "Layout",
|
|
||||||
"tabIndex": -1,
|
|
||||||
"category": "Dock",
|
|
||||||
"keywords": [
|
|
||||||
"dock",
|
|
||||||
"edge",
|
|
||||||
"launcher bar",
|
|
||||||
"layout",
|
|
||||||
"panel",
|
|
||||||
"placement",
|
|
||||||
"position",
|
|
||||||
"taskbar"
|
|
||||||
],
|
|
||||||
"page": "dock",
|
|
||||||
"icon": "dock_to_bottom"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"section": "iconThemeLight",
|
"section": "iconThemeLight",
|
||||||
"label": "Light mode theme",
|
"label": "Light mode theme",
|
||||||
@@ -11275,7 +11276,6 @@
|
|||||||
"tabIndex": 25,
|
"tabIndex": 25,
|
||||||
"category": "Gamma control",
|
"category": "Gamma control",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"available",
|
|
||||||
"blue light",
|
"blue light",
|
||||||
"color",
|
"color",
|
||||||
"color temperature",
|
"color temperature",
|
||||||
@@ -11290,15 +11290,13 @@
|
|||||||
"output",
|
"output",
|
||||||
"outputs",
|
"outputs",
|
||||||
"redshift",
|
"redshift",
|
||||||
"requires",
|
|
||||||
"resolution",
|
"resolution",
|
||||||
"screen",
|
"screen",
|
||||||
"screens",
|
"screens",
|
||||||
"temperature",
|
"temperature",
|
||||||
"warm"
|
"warm"
|
||||||
],
|
],
|
||||||
"parentLabel": "Displays",
|
"parentLabel": "Displays"
|
||||||
"description": "Gamma control not available. Requires DMS API v6+."
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "nightModeTransitionMinutes",
|
"section": "nightModeTransitionMinutes",
|
||||||
@@ -15896,12 +15894,10 @@
|
|||||||
"schedule",
|
"schedule",
|
||||||
"settings",
|
"settings",
|
||||||
"share",
|
"share",
|
||||||
"shared",
|
|
||||||
"tint",
|
"tint",
|
||||||
"wallpaper"
|
"wallpaper"
|
||||||
],
|
],
|
||||||
"parentLabel": "Wallpaper & colors",
|
"parentLabel": "Wallpaper & colors"
|
||||||
"description": "Using shared settings from Gamma Control"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "wallpaperCycling",
|
"section": "wallpaperCycling",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ if [[ -n "${QS_ARGS:-}" ]]; then
|
|||||||
# shellcheck disable=SC2206
|
# shellcheck disable=SC2206
|
||||||
qs_args=($QS_ARGS)
|
qs_args=($QS_ARGS)
|
||||||
else
|
else
|
||||||
state_file="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/danklinux.path"
|
state_file="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/dms.path"
|
||||||
config_path="$(cat "$state_file" 2>/dev/null || true)"
|
config_path="$(cat "$state_file" 2>/dev/null || true)"
|
||||||
[[ -n "$config_path" ]] || { echo "no running dms shell ($state_file missing)" >&2; exit 1; }
|
[[ -n "$config_path" ]] || { echo "no running dms shell ($state_file missing)" >&2; exit 1; }
|
||||||
qs_args=(-p "$config_path")
|
qs_args=(-p "$config_path")
|
||||||
|
|||||||
Reference in New Issue
Block a user