1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-13 07:42:46 -04:00

Compare commits

..

15 Commits

Author SHA1 Message Date
purian23 2947ff4131 distro: Revise server side file handling 2025-12-16 01:08:12 -05:00
purian23 b8fca10896 Remove auto run on tags 2025-12-16 00:17:13 -05:00
purian23 33e45794d2 No run on push 2025-12-15 23:29:36 -05:00
purian23 42cc88ca65 Workflow update 2025-12-15 23:24:16 -05:00
purian23 0b7f2416ca distro: Bring up Stable 2025-12-15 23:10:24 -05:00
purian23 5d5c745ee5 Push the logs 2025-12-15 22:18:35 -05:00
purian23 e0429e4c60 distro: Re-add suffix 2025-12-15 21:31:13 -05:00
bbedward 0bece5287e dock: improve pinned app re-ordering feedback, fix vertical dock
ordering
fixes #1046
fixes #938
2025-12-15 20:46:36 -05:00
purian23 60b5e47836 update gitignore env 2025-12-15 19:06:43 -05:00
purian23 aa75b44790 distro: OBS version matching 2025-12-15 18:03:58 -05:00
bbedward 769f58caa9 displays: fix reverted state for position 2025-12-15 17:43:52 -05:00
bbedward e7facf740d update CHANGELOG 2025-12-15 17:18:59 -05:00
Austin Farmer 04921eef62 Move Ghostty Application Theming (#1047)
* Moved ghostty config

First test. Seems to work but probably broke something.

* Updated test
2025-12-15 17:16:46 -05:00
Oliver Portee 8863c42879 fix light mode/dark mode switch for stock themes (#1057) 2025-12-15 17:16:23 -05:00
bbedward 2745116ac5 displays: add configurator for niri, Hyprland, and MangoWC
- Configure position, VRR, orientation, resolution, refresh rate
- Split Display section into Configuration, Gamma, and Widgets
- MangoWC omits VRR because it doesnt have per-display VRR
- HDR configuration not present for Hyprland
2025-12-15 16:36:14 -05:00
22 changed files with 1460 additions and 1175 deletions
+57 -14
View File
@@ -7,13 +7,14 @@ on:
description: "Package to update (dms, dms-git, or all)" description: "Package to update (dms, dms-git, or all)"
required: false required: false
default: "all" default: "all"
tag_version:
description: "Specific tag version for dms stable (e.g., v1.0.2). Leave empty to auto-detect latest release."
required: false
default: ""
rebuild_release: rebuild_release:
description: "Release number for rebuilds (e.g., 2, 3, 4 to increment spec Release)" description: "Release number for rebuilds (e.g., 2, 3, 4 to increment spec Release)"
required: false required: false
default: "" default: ""
push:
tags:
- "v*"
schedule: schedule:
- cron: "0 */3 * * *" # Every 3 hours for dms-git builds - cron: "0 */3 * * *" # Every 3 hours for dms-git builds
@@ -97,7 +98,7 @@ jobs:
# Rebuild requested - always proceed # Rebuild requested - always proceed
echo "packages=$PKG" >> $GITHUB_OUTPUT echo "packages=$PKG" >> $GITHUB_OUTPUT
echo "has_updates=true" >> $GITHUB_OUTPUT echo "has_updates=true" >> $GITHUB_OUTPUT
echo "🔄 Manual rebuild requested: $PKG (ppa$REBUILD)" echo "🔄 Manual rebuild requested: $PKG (db$REBUILD)"
elif [[ "$PKG" == "all" ]]; then elif [[ "$PKG" == "all" ]]; then
# Check each package and build list of those needing updates # Check each package and build list of those needing updates
@@ -161,16 +162,51 @@ jobs:
id: packages id: packages
run: | run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then
# Tag push event - use the pushed tag
echo "packages=dms" >> $GITHUB_OUTPUT echo "packages=dms" >> $GITHUB_OUTPUT
VERSION="${GITHUB_REF#refs/tags/}" VERSION="${GITHUB_REF#refs/tags/}"
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Triggered by tag: $VERSION" echo "Triggered by tag: $VERSION"
elif [[ "${{ github.event_name }}" == "schedule" ]]; then elif [[ "${{ github.event_name }}" == "schedule" ]]; then
# Scheduled run - dms-git only
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
echo "Triggered by schedule: updating git package" echo "Triggered by schedule: updating git package"
elif [[ -n "${{ github.event.inputs.package }}" ]]; then elif [[ -n "${{ github.event.inputs.package }}" ]]; then
# Use filtered packages from check-updates when package="all" and no rebuild requested # Manual workflow dispatch
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]]; then
# Determine version for dms stable
if [[ "${{ github.event.inputs.package }}" == "dms" ]]; then
# For explicit dms selection, require tag_version
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
VERSION="${{ github.event.inputs.tag_version }}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Using specified tag: $VERSION"
else
echo "ERROR: tag_version is required when package=dms"
echo "Please specify a tag version (e.g., v1.0.2) or use package=all for auto-detection"
exit 1
fi
elif [[ "${{ github.event.inputs.package }}" == "all" ]]; then
# For "all", auto-detect if tag_version not specified
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
VERSION="${{ github.event.inputs.tag_version }}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Using specified tag: $VERSION"
else
# Auto-detect latest release for "all"
LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "")
if [[ -n "$LATEST_TAG" ]]; then
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "Auto-detected latest release: $LATEST_TAG"
else
echo "ERROR: Could not auto-detect latest release"
exit 1
fi
fi
fi
# Use filtered packages from check-updates when package="all" and no rebuild/tag specified
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]] && [[ -z "${{ github.event.inputs.tag_version }}" ]]; then
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
echo "Manual trigger: all (filtered to: ${{ needs.check-updates.outputs.packages }})" echo "Manual trigger: all (filtered to: ${{ needs.check-updates.outputs.packages }})"
else else
@@ -186,7 +222,7 @@ jobs:
run: | run: |
COMMIT_HASH=$(git rev-parse --short=8 HEAD) COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD) COMMIT_COUNT=$(git rev-list --count HEAD)
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2") BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "1.0.2")
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}" NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
echo "📦 Updating dms-git.spec to version: $NEW_VERSION" echo "📦 Updating dms-git.spec to version: $NEW_VERSION"
@@ -207,14 +243,14 @@ jobs:
run: | run: |
COMMIT_HASH=$(git rev-parse --short=8 HEAD) COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD) COMMIT_COUNT=$(git rev-list --count HEAD)
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2") BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "1.0.2")
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}" NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
echo "📦 Updating Debian dms-git changelog to version: $NEW_VERSION" echo "📦 Updating Debian dms-git changelog to version: $NEW_VERSION"
# Single changelog entry (git snapshots don't need history) # Single changelog entry (git snapshots don't need history)
CHANGELOG_DATE=$(date -R) CHANGELOG_DATE=$(date -R)
{ {
echo "dms-git ($NEW_VERSION) nightly; urgency=medium" echo "dms-git (${NEW_VERSION}db1) nightly; urgency=medium"
echo "" echo ""
echo " * Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)" echo " * Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)"
echo "" echo ""
@@ -226,10 +262,15 @@ jobs:
run: | run: |
VERSION="${{ steps.packages.outputs.version }}" VERSION="${{ steps.packages.outputs.version }}"
VERSION_NO_V="${VERSION#v}" VERSION_NO_V="${VERSION#v}"
echo "Updating packaging to version $VERSION_NO_V" echo "==> Updating packaging files to version: $VERSION_NO_V"
# Update spec file
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
# Verify the update
UPDATED_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1)
echo "✓ Spec file now shows Version: $UPDATED_VERSION"
# Single changelog entry (full history on OBS website) # Single changelog entry (full history on OBS website)
DATE_STR=$(date "+%a %b %d %Y") DATE_STR=$(date "+%a %b %d %Y")
LOCAL_SPEC_HEAD=$(sed -n '1,/%changelog/{ /%changelog/d; p }' distro/opensuse/dms.spec) LOCAL_SPEC_HEAD=$(sed -n '1,/%changelog/{ /%changelog/d; p }' distro/opensuse/dms.spec)
@@ -256,13 +297,13 @@ jobs:
if [[ -f "distro/debian/dms/debian/changelog" ]]; then if [[ -f "distro/debian/dms/debian/changelog" ]]; then
CHANGELOG_DATE=$(date -R) CHANGELOG_DATE=$(date -R)
{ {
echo "dms ($VERSION_NO_V) stable; urgency=medium" echo "dms (${VERSION_NO_V}db1) stable; urgency=medium"
echo "" echo ""
echo " * Update to $VERSION stable release" echo " * Update to $VERSION stable release"
echo "" echo ""
echo " -- Avenge Media <AvengeMedia.US@gmail.com> $CHANGELOG_DATE" echo " -- Avenge Media <AvengeMedia.US@gmail.com> $CHANGELOG_DATE"
} > "distro/debian/dms/debian/changelog" } > "distro/debian/dms/debian/changelog"
echo "✓ Updated Debian changelog to $VERSION_NO_V" echo "✓ Updated Debian changelog to ${VERSION_NO_V}db1"
fi fi
- name: Install Go - name: Install Go
@@ -289,6 +330,7 @@ jobs:
- name: Upload to OBS - name: Upload to OBS
env: env:
REBUILD_RELEASE: ${{ github.event.inputs.rebuild_release }} REBUILD_RELEASE: ${{ github.event.inputs.rebuild_release }}
TAG_VERSION: ${{ steps.packages.outputs.version }}
run: | run: |
PACKAGES="${{ steps.packages.outputs.packages }}" PACKAGES="${{ steps.packages.outputs.packages }}"
@@ -300,6 +342,7 @@ jobs:
MESSAGE="Automated update from GitHub Actions" MESSAGE="Automated update from GitHub Actions"
if [[ -n "${{ steps.packages.outputs.version }}" ]]; then if [[ -n "${{ steps.packages.outputs.version }}" ]]; then
MESSAGE="Update to ${{ steps.packages.outputs.version }}" MESSAGE="Update to ${{ steps.packages.outputs.version }}"
echo "==> Version being uploaded: ${{ steps.packages.outputs.version }}"
fi fi
# PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check) # PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check)
@@ -309,7 +352,7 @@ jobs:
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Uploading $PKG to OBS..." echo "Uploading $PKG to OBS..."
if [[ -n "$REBUILD_RELEASE" ]]; then if [[ -n "$REBUILD_RELEASE" ]]; then
echo "🔄 Using rebuild release number: ppa$REBUILD_RELEASE" echo "🔄 Using rebuild release number: db$REBUILD_RELEASE"
fi fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@@ -350,7 +393,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
if [[ -n "${{ github.event.inputs.rebuild_release }}" ]]; then if [[ -n "${{ github.event.inputs.rebuild_release }}" ]]; then
echo "**Rebuild Number:** ppa${{ github.event.inputs.rebuild_release }}" >> $GITHUB_STEP_SUMMARY echo "**Rebuild Number:** db${{ github.event.inputs.rebuild_release }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
fi fi
+1 -1
View File
@@ -96,7 +96,7 @@ go.work
go.work.sum go.work.sum
# env file # env file
.env .env*
# Editor/IDE # Editor/IDE
# .idea/ # .idea/
+5
View File
@@ -1,6 +1,11 @@
This file is more of a quick reference so I know what to account for before next releases.
# 1.2.0 # 1.2.0
- Added clipboard and clipboard history integration - Added clipboard and clipboard history integration
- Added swipe to dismiss notification popups and from center - Added swipe to dismiss notification popups and from center
- Added paste from clipboard history view - requires wtype - Added paste from clipboard history view - requires wtype
- Optimize surface damage of OSD & Toast - Optimize surface damage of OSD & Toast
- Add monitor configurator (niri, Hyprland, MangoWC)
- **BREAKING** ghostty theme changed to ~/.config/ghostty/themes/danktheme
- requires intervention and doc update
+1 -1
View File
@@ -220,7 +220,7 @@ func getBaseVersion() string {
} }
// Fallback // Fallback
return "0.6.2" return "1.0.2"
} }
func startDebugServer() error { func startDebugServer() error {
+7 -1
View File
@@ -265,7 +265,13 @@ func (cd *ConfigDeployer) deployGhosttyConfig() ([]DeploymentResult, error) {
colorResult := DeploymentResult{ colorResult := DeploymentResult{
ConfigType: "Ghostty Colors", ConfigType: "Ghostty Colors",
Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config-dankcolors"), Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "themes", "dankcolors"),
}
themesDir := filepath.Dir(colorResult.Path)
if err := os.MkdirAll(themesDir, 0755); err != nil {
mainResult.Error = fmt.Errorf("failed to create themes directory: %w", err)
return []DeploymentResult{mainResult}, mainResult.Error
} }
if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0644); err != nil { if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0644); err != nil {
+1 -1
View File
@@ -468,7 +468,7 @@ func TestHyprlandConfigStructure(t *testing.T) {
func TestGhosttyConfigStructure(t *testing.T) { func TestGhosttyConfigStructure(t *testing.T) {
assert.Contains(t, GhosttyConfig, "window-decoration = false") assert.Contains(t, GhosttyConfig, "window-decoration = false")
assert.Contains(t, GhosttyConfig, "background-opacity = 1.0") assert.Contains(t, GhosttyConfig, "background-opacity = 1.0")
assert.Contains(t, GhosttyConfig, "config-file = ./config-dankcolors") assert.Contains(t, GhosttyConfig, "theme = dankcolors")
} }
func TestGhosttyColorConfigStructure(t *testing.T) { func TestGhosttyColorConfigStructure(t *testing.T) {
+1 -1
View File
@@ -48,4 +48,4 @@ keybind = shift+enter=text:\n
gtk-single-instance = true gtk-single-instance = true
# Dank color generation # Dank color generation
config-file = ./config-dankcolors theme = dankcolors
+1 -18
View File
@@ -1,4 +1,4 @@
dms-git (1.0.2+git2528.d336866f) nightly; urgency=medium dms-git (1.0.2+git2528.d336866fdb1) nightly; urgency=medium
* Git snapshot (commit 2528: d336866f) * Git snapshot (commit 2528: d336866f)
@@ -16,23 +16,6 @@ dms-git (1.0.2+git2518.a783d650) nightly; urgency=medium
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 15:11:40 +0000 -- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 15:11:40 +0000
dms-git (1.0.2+git2510.0f89886c) nightly; urgency=medium
* Git snapshot (commit 2510: 0f89886c)
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:46:43 +0000
dms-git (1.0.2+git2507.b2ac9c6c) nightly; urgency=medium
* Git snapshot (commit 2507: b2ac9c6c)
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:18:05 +0000
dms-git (1.0.2+git2505.82f881af) nightly; urgency=medium
* Git snapshot (commit 2505: 82f881af)
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 05:55:03 +0000
dms-git (1.0.0+git2419.993f14a3) nightly; urgency=medium dms-git (1.0.0+git2419.993f14a3) nightly; urgency=medium
+3 -3
View File
@@ -3,19 +3,19 @@
<service name="download_url"> <service name="download_url">
<param name="protocol">https</param> <param name="protocol">https</param>
<param name="host">github.com</param> <param name="host">github.com</param>
<param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.2.tar.gz</param> <param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.3.tar.gz</param>
<param name="filename">dms-source.tar.gz</param> <param name="filename">dms-source.tar.gz</param>
</service> </service>
<!-- Download amd64 binary --> <!-- Download amd64 binary -->
<service name="download_url"> <service name="download_url">
<param name="protocol">https</param> <param name="protocol">https</param>
<param name="host">github.com</param> <param name="host">github.com</param>
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-amd64.gz</param> <param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.3/dms-distropkg-amd64.gz</param>
</service> </service>
<!-- Download arm64 binary --> <!-- Download arm64 binary -->
<service name="download_url"> <service name="download_url">
<param name="protocol">https</param> <param name="protocol">https</param>
<param name="host">github.com</param> <param name="host">github.com</param>
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-arm64.gz</param> <param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.3/dms-distropkg-arm64.gz</param>
</service> </service>
</services> </services>
+8 -2
View File
@@ -1,6 +1,12 @@
dms (1.0.2ppa6) unstable; urgency=medium dms (1.0.3db1) unstable; urgency=medium
* Rebuild to fix repository metadata issues * Update to v1.0.3 stable release
-- Avenge Media <AvengeMedia.US@gmail.com> Mon, 16 Dec 2025 10:00:00 +0000
dms (1.0.2db1) unstable; urgency=medium
* Update to v1.0.2 stable release
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:47:39 +0000 -- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:47:39 +0000
+5 -2
View File
@@ -3,8 +3,8 @@
%global debug_package %{nil} %global debug_package %{nil}
Name: dms Name: dms
Version: 1.0.2 Version: 1.0.3
Release: 7%{?dist} Release: 1%{?dist}
Summary: DankMaterialShell - Material 3 inspired shell for Wayland compositors Summary: DankMaterialShell - Material 3 inspired shell for Wayland compositors
License: MIT License: MIT
@@ -105,6 +105,9 @@ pkill -USR1 -x dms >/dev/null 2>&1 || :
%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg %{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
%changelog %changelog
* Mon Dec 16 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.3-1
- Update to stable v1.0.3 release
* Fri Dec 12 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.2-1 * Fri Dec 12 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.2-1
- Update to stable v1.0.2 release - Update to stable v1.0.2 release
- Bug fixes and improvements - Bug fixes and improvements
+62 -29
View File
@@ -7,8 +7,8 @@
# ./distro/scripts/obs-upload.sh dms "Update to v1.0.2" # ./distro/scripts/obs-upload.sh dms "Update to v1.0.2"
# ./distro/scripts/obs-upload.sh debian dms # ./distro/scripts/obs-upload.sh debian dms
# ./distro/scripts/obs-upload.sh opensuse dms-git # ./distro/scripts/obs-upload.sh opensuse dms-git
# ./distro/scripts/obs-upload.sh debian dms-git 2 # Rebuild with ppa2 suffix # ./distro/scripts/obs-upload.sh debian dms-git 2 # Rebuild with db2 suffix
# ./distro/scripts/obs-upload.sh dms-git --rebuild=2 # Rebuild with ppa2 suffix (flag syntax) # ./distro/scripts/obs-upload.sh dms-git --rebuild=2 # Rebuild with db2 suffix (flag syntax)
set -e set -e
@@ -126,8 +126,8 @@ check_obs_version_exists() {
OBS_VERSION=$(echo "$OBS_SPEC" | grep "^Version:" | awk '{print $2}' | xargs) OBS_VERSION=$(echo "$OBS_SPEC" | grep "^Version:" | awk '{print $2}' | xargs)
# Commit hash check for -git packages # Commit hash check for -git packages
if [[ "$CHECK_MODE" == "commit" ]] && [[ "$PACKAGE" == *"-git" ]]; then if [[ "$CHECK_MODE" == "commit" ]] && [[ "$PACKAGE" == *"-git" ]]; then
OBS_COMMIT=$(echo "$OBS_VERSION" | grep -oP '\.([a-f0-9]{8})(ppa[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "") OBS_COMMIT=$(echo "$OBS_VERSION" | grep -oP '\.([a-f0-9]{8})(db[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
NEW_COMMIT=$(echo "$VERSION" | grep -oP '\.([a-f0-9]{8})(ppa[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "") NEW_COMMIT=$(echo "$VERSION" | grep -oP '\.([a-f0-9]{8})(db[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
if [[ -n "$OBS_COMMIT" && -n "$NEW_COMMIT" && "$OBS_COMMIT" == "$NEW_COMMIT" ]]; then if [[ -n "$OBS_COMMIT" && -n "$NEW_COMMIT" && "$OBS_COMMIT" == "$NEW_COMMIT" ]]; then
echo "⚠️ Commit $NEW_COMMIT already exists in OBS (current version: $OBS_VERSION)" echo "⚠️ Commit $NEW_COMMIT already exists in OBS (current version: $OBS_VERSION)"
@@ -279,7 +279,8 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
# Apply rebuild suffix if specified (must happen before API check) # Apply rebuild suffix if specified (must happen before API check)
if [[ -n "$REBUILD_RELEASE" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then if [[ -n "$REBUILD_RELEASE" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then
CHANGELOG_VERSION="${CHANGELOG_VERSION}ppa${REBUILD_RELEASE}" BASE_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/db[0-9]*$//')
CHANGELOG_VERSION="${BASE_VERSION}db${REBUILD_RELEASE}"
echo " - Applied rebuild suffix: $CHANGELOG_VERSION" echo " - Applied rebuild suffix: $CHANGELOG_VERSION"
fi fi
@@ -307,12 +308,16 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
else else
# Rebuild number specified - check if this exact version already exists (exact mode) # Rebuild number specified - check if this exact version already exists (exact mode)
if check_obs_version_exists "$OBS_PROJECT" "$PACKAGE" "$CHANGELOG_VERSION" "exact"; then if check_obs_version_exists "$OBS_PROJECT" "$PACKAGE" "$CHANGELOG_VERSION" "exact"; then
echo "==> Error: Version $CHANGELOG_VERSION already exists in OBS" echo "==> Version $CHANGELOG_VERSION already exists in OBS"
echo " This exact version (including ppa${REBUILD_RELEASE}) is already uploaded." echo " This exact version (including db${REBUILD_RELEASE}) is already uploaded."
echo " To rebuild with a different release number, try incrementing:" echo " Skipping upload - nothing to do."
echo ""
echo " 💡 To rebuild with a different release number, try incrementing:"
NEXT_NUM=$((REBUILD_RELEASE + 1)) NEXT_NUM=$((REBUILD_RELEASE + 1))
echo " ./distro/scripts/obs-upload.sh $PACKAGE $NEXT_NUM" echo " REBUILD_RELEASE=$NEXT_NUM"
exit 1 echo ""
echo "✓ Exiting gracefully (no changes needed)"
exit 0
fi fi
fi fi
fi fi
@@ -511,7 +516,7 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
if [[ -n "$URL_PROTOCOL" && -n "$URL_HOST" && -n "$URL_PATH" ]]; then if [[ -n "$URL_PROTOCOL" && -n "$URL_HOST" && -n "$URL_PATH" ]]; then
SOURCE_URL="${URL_PROTOCOL}://${URL_HOST}${URL_PATH}" SOURCE_URL="${URL_PROTOCOL}://${URL_HOST}${URL_PATH}"
echo " Downloading source from: $SOURCE_URL" echo "==> Downloading source from: $SOURCE_URL"
if wget -q -O "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null || if wget -q -O "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null ||
curl -L -f -s -o "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null; then curl -L -f -s -o "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null; then
@@ -534,9 +539,17 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
fi fi
SOURCE_DIR=$(cd "$SOURCE_DIR" && pwd) SOURCE_DIR=$(cd "$SOURCE_DIR" && pwd)
cd "$REPO_ROOT" cd "$REPO_ROOT"
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
echo "ERROR: Failed to return to REPO_ROOT. Expected: $REPO_ROOT, Got: $(pwd)"
exit 1
fi
else else
echo "Error: Failed to download source from $SOURCE_URL" echo "ERROR: Failed to download source from $SOURCE_URL"
echo "Tried both wget and curl. Please check the URL and network connectivity." echo "Attempted both wget and curl"
echo "Please check:"
echo " 1. URL is accessible: $SOURCE_URL"
echo " 2. _service file has correct version"
echo " 3. GitHub releases are available"
exit 1 exit 1
fi fi
fi fi
@@ -553,7 +566,7 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
exit 1 exit 1
fi fi
echo " Found source directory: $SOURCE_DIR" echo "==> Found source directory: $SOURCE_DIR"
# Vendor Go dependencies for dms-git # Vendor Go dependencies for dms-git
if [[ "$PACKAGE" == "dms-git" ]] && [[ -d "$SOURCE_DIR/core" ]]; then if [[ "$PACKAGE" == "dms-git" ]] && [[ -d "$SOURCE_DIR/core" ]]; then
@@ -712,6 +725,10 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
TARBALL_BASE=$(basename "$SOURCE_DIR") TARBALL_BASE=$(basename "$SOURCE_DIR")
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE" tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
cd "$REPO_ROOT" cd "$REPO_ROOT"
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
echo "ERROR: Failed to return to REPO_ROOT after tarball creation"
exit 1
fi
if [[ "$PACKAGE" == "dms" ]]; then if [[ "$PACKAGE" == "dms" ]]; then
TARBALL_DIR=$(tar -tzf "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null | head -1 | cut -d'/' -f1) TARBALL_DIR=$(tar -tzf "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null | head -1 | cut -d'/' -f1)
@@ -723,6 +740,10 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
rm -f "$WORK_DIR/$COMBINED_TARBALL" rm -f "$WORK_DIR/$COMBINED_TARBALL"
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE" tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
cd "$REPO_ROOT" cd "$REPO_ROOT"
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
echo "ERROR: Failed to return to REPO_ROOT after tarball recreation"
exit 1
fi
fi fi
fi fi
@@ -796,23 +817,29 @@ EOF
fi fi
fi fi
cd "$WORK_DIR" echo "==> Ensuring we're in the OSC working directory"
cd "$WORK_DIR" || {
echo "ERROR: Cannot cd to WORK_DIR: $WORK_DIR"
echo "DEBUG: Current directory: $(pwd)"
echo "DEBUG: WORK_DIR exists: $(test -d "$WORK_DIR" && echo "yes" || echo "no")"
exit 1
}
echo "DEBUG: Successfully entered WORK_DIR: $(pwd)"
# Server-side cleanup via API # Server-side cleanup via API
echo "==> Cleaning old tarballs from OBS server (prevents downloading 100+ old versions)" echo "==> Cleaning old tarballs from OBS server (prevents downloading 100+ old versions)"
OBS_FILES=$(osc api "/source/$OBS_PROJECT/$PACKAGE" 2>/dev/null || echo "") OBS_FILES=$(osc api "/source/$OBS_PROJECT/$PACKAGE" 2>/dev/null || echo "")
if [[ -n "$OBS_FILES" ]]; then if [[ -n "$OBS_FILES" ]]; then
DELETED_COUNT=0 DELETED_COUNT=0
KEEP_PATTERN="" KEEP_CURRENT=""
if [[ -n "$CHANGELOG_VERSION" ]]; then if [[ -n "$CHANGELOG_VERSION" ]]; then
BASE_KEEP_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/ppa[0-9]*$//') KEEP_CURRENT="${PACKAGE}_${CHANGELOG_VERSION}.tar.gz"
KEEP_PATTERN="${PACKAGE}_${BASE_KEEP_VERSION}" echo " Keeping only current version: ${KEEP_CURRENT}"
echo " Keeping tarballs matching: ${KEEP_PATTERN}*"
fi fi
for old_file in $(echo "$OBS_FILES" | grep -oP '(?<=name=")[^"]*\.(tar\.gz|tar\.xz|tar\.bz2)(?=")' || true); do for old_file in $(echo "$OBS_FILES" | grep -oP '(?<=name=")[^"]*\.(tar\.gz|tar\.xz|tar\.bz2)(?=")' || true); do
if [[ -n "$KEEP_PATTERN" ]] && [[ "$old_file" == ${KEEP_PATTERN}* ]]; then if [[ "$old_file" == "$KEEP_CURRENT" ]]; then
echo " - Keeping current version: $old_file" echo " - Keeping: $old_file"
continue continue
fi fi
@@ -835,14 +862,11 @@ else
echo " ⚠️ Could not fetch file list from server, skipping cleanup" echo " ⚠️ Could not fetch file list from server, skipping cleanup"
fi fi
# Fallback update with --server-side-source-service-files flag only syncs metadata (spec, dsc, _service) # Update working copy to latest revision (without expanding service files to avoid revision conflicts)
echo "==> Updating working copy" echo "==> Updating working copy"
if ! osc up --server-side-source-service-files 2>/dev/null; then if ! osc up 2>/dev/null; then
echo " Note: Using regular update (--server-side-source-service-files not supported)" echo "Error: Failed to update working copy"
if ! osc up; then exit 1
echo "Error: Failed to update working copy"
exit 1
fi
fi fi
# Ensure we're in WORK_DIR and it exists # Ensure we're in WORK_DIR and it exists
@@ -882,6 +906,15 @@ elif [[ "$UPLOAD_OPENSUSE" == true ]]; then
fi fi
echo "" echo ""
if [[ "$(pwd)" != "$WORK_DIR" ]]; then
echo "ERROR: Lost directory context. Expected: $WORK_DIR, Got: $(pwd)"
cd "$WORK_DIR" || {
echo "FATAL: Cannot recover - unable to cd to WORK_DIR"
exit 1
}
echo "WARNING: Recovered directory context"
fi
osc addremove 2>&1 | grep -v "Git SCM package" || true osc addremove 2>&1 | grep -v "Git SCM package" || true
SOURCE_TARBALL="${PACKAGE}-source.tar.gz" SOURCE_TARBALL="${PACKAGE}-source.tar.gz"
@@ -908,7 +941,7 @@ if ! osc status 2>/dev/null | grep -qE '^[MAD]|^[?]'; then
else else
echo "==> Committing to OBS" echo "==> Committing to OBS"
set +e set +e
osc commit -m "$MESSAGE" 2>&1 | grep -v "Git SCM package" | grep -v "apiurl\|project\|_ObsPrj\|_manifest\|git-obs" osc commit --skip-local-service-run -m "$MESSAGE" 2>&1 | grep -v "Git SCM package" | grep -v "apiurl\|project\|_ObsPrj\|_manifest\|git-obs"
COMMIT_EXIT=${PIPESTATUS[0]} COMMIT_EXIT=${PIPESTATUS[0]}
set -e set -e
if [[ $COMMIT_EXIT -ne 0 ]]; then if [[ $COMMIT_EXIT -ne 0 ]]; then
+2 -1
View File
@@ -918,6 +918,7 @@ Singleton {
function buildMatugenColorsFromTheme(darkTheme, lightTheme) { function buildMatugenColorsFromTheme(darkTheme, lightTheme) {
const colors = {}; const colors = {};
const isLight = SessionData !== "undefined" && SessionData.isLightMode;
function addColor(matugenKey, darkVal, lightVal) { function addColor(matugenKey, darkVal, lightVal) {
if (!darkVal && !lightVal) if (!darkVal && !lightVal)
@@ -930,7 +931,7 @@ Singleton {
"color": String(lightVal || darkVal) "color": String(lightVal || darkVal)
}, },
"default": { "default": {
"color": String(darkVal || lightVal) "color": String((isLight && lightVal) ? lightVal : darkVal)
} }
}; };
} }
+20 -20
View File
@@ -24,26 +24,26 @@ DankModal {
repeat: true repeat: true
running: root.shouldBeVisible running: root.shouldBeVisible
onTriggered: { onTriggered: {
root.countdown-- root.countdown--;
if (root.countdown <= 0) { if (root.countdown <= 0) {
root.reverted() root.reverted();
root.close() root.close();
} }
} }
} }
onOpened: { onOpened: {
countdown = 10 countdown = 10;
countdownTimer.start() countdownTimer.start();
} }
onDialogClosed: { onDialogClosed: {
countdownTimer.stop() countdownTimer.stop();
} }
onBackgroundClicked: { onBackgroundClicked: {
root.reverted() root.reverted();
root.close() root.close();
} }
content: Component { content: Component {
@@ -55,15 +55,15 @@ DankModal {
implicitHeight: mainColumn.implicitHeight implicitHeight: mainColumn.implicitHeight
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
root.reverted() root.reverted();
root.close() root.close();
event.accepted = true event.accepted = true;
} }
Keys.onReturnPressed: event => { Keys.onReturnPressed: event => {
root.confirmed() root.confirmed();
root.close() root.close();
event.accepted = true event.accepted = true;
} }
Column { Column {
@@ -149,8 +149,8 @@ DankModal {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.reverted() root.reverted();
root.close() root.close();
} }
} }
} }
@@ -178,8 +178,8 @@ DankModal {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.confirmed() root.confirmed();
root.close() root.close();
} }
} }
@@ -203,8 +203,8 @@ DankModal {
iconSize: Theme.iconSize - 4 iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: { onClicked: {
root.reverted() root.reverted();
root.close() root.close();
} }
} }
} }
+132 -98
View File
@@ -19,9 +19,10 @@ Item {
property bool longPressing: false property bool longPressing: false
property bool dragging: false property bool dragging: false
property point dragStartPos: Qt.point(0, 0) property point dragStartPos: Qt.point(0, 0)
property point dragOffset: Qt.point(0, 0) property real dragAxisOffset: 0
property int targetIndex: -1 property int targetIndex: -1
property int originalIndex: -1 property int originalIndex: -1
property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
property bool showWindowTitle: false property bool showWindowTitle: false
property string windowTitle: "" property string windowTitle: ""
property bool isHovered: mouseArea.containsMouse && !dragging property bool isHovered: mouseArea.containsMouse && !dragging
@@ -95,7 +96,7 @@ Item {
return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []; return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || [];
} }
onIsHoveredChanged: { onIsHoveredChanged: {
if (mouseArea.pressed) if (mouseArea.pressed || dragging)
return; return;
if (isHovered) { if (isHovered) {
exitAnimation.stop(); exitAnimation.stop();
@@ -128,8 +129,8 @@ Item {
running: false running: false
NumberAnimation { NumberAnimation {
target: iconTransform target: root
property: animateX ? "x" : "y" property: "hoverAnimOffset"
to: animationDirection * animationDistance * 0.25 to: animationDirection * animationDistance * 0.25
duration: Anims.durShort duration: Anims.durShort
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
@@ -137,8 +138,8 @@ Item {
} }
NumberAnimation { NumberAnimation {
target: iconTransform target: root
property: animateX ? "x" : "y" property: "hoverAnimOffset"
to: animationDirection * animationDistance * 0.2 to: animationDirection * animationDistance * 0.2
duration: Anims.durShort duration: Anims.durShort
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
@@ -150,8 +151,8 @@ Item {
id: exitAnimation id: exitAnimation
running: false running: false
target: iconTransform target: root
property: animateX ? "x" : "y" property: "hoverAnimOffset"
to: 0 to: 0
duration: Anims.durShort duration: Anims.durShort
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
@@ -187,16 +188,79 @@ Item {
} }
onReleased: mouse => { onReleased: mouse => {
longPressTimer.stop(); longPressTimer.stop();
if (longPressing) {
if (dragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps) {
dockApps.movePinnedApp(originalIndex, targetIndex);
}
longPressing = false; const wasDragging = dragging;
dragging = false; const didReorder = wasDragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps;
dragOffset = Qt.point(0, 0);
targetIndex = -1; if (didReorder)
originalIndex = -1; dockApps.movePinnedApp(originalIndex, targetIndex);
longPressing = false;
dragging = false;
dragAxisOffset = 0;
targetIndex = -1;
originalIndex = -1;
if (dockApps && !didReorder) {
dockApps.draggedIndex = -1;
dockApps.dropTargetIndex = -1;
}
if (wasDragging || mouse.button !== Qt.LeftButton)
return;
handleLeftClick();
}
function handleLeftClick() {
if (!appData)
return;
switch (appData.type) {
case "pinned":
if (!appData.appId)
return;
const pinnedEntry = cachedDesktopEntry;
if (pinnedEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": pinnedEntry.name || appData.appId,
"icon": pinnedEntry.icon || "",
"exec": pinnedEntry.exec || "",
"comment": pinnedEntry.comment || ""
});
}
SessionService.launchDesktopEntry(pinnedEntry);
break;
case "window":
const windowToplevel = getToplevelObject();
if (windowToplevel)
windowToplevel.activate();
break;
case "grouped":
if (appData.windowCount === 0) {
if (!appData.appId)
return;
const groupedEntry = cachedDesktopEntry;
if (groupedEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": groupedEntry.name || appData.appId,
"icon": groupedEntry.icon || "",
"exec": groupedEntry.exec || "",
"comment": groupedEntry.comment || ""
});
}
SessionService.launchDesktopEntry(groupedEntry);
} else if (appData.windowCount === 1) {
const groupedToplevel = getToplevelObject();
if (groupedToplevel)
groupedToplevel.activate();
} else if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
}
break;
} }
} }
onPositionChanged: mouse => { onPositionChanged: mouse => {
@@ -206,90 +270,47 @@ Item {
dragging = true; dragging = true;
targetIndex = index; targetIndex = index;
originalIndex = index; originalIndex = index;
if (dockApps) {
dockApps.draggedIndex = index;
dockApps.dropTargetIndex = index;
}
} }
} }
if (dragging) {
dragOffset = Qt.point(mouse.x - dragStartPos.x, mouse.y - dragStartPos.y); if (!dragging || !dockApps)
if (dockApps) { return;
const threshold = actualIconSize;
let newTargetIndex = targetIndex; const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x);
if (dragOffset.x > threshold && targetIndex < dockApps.pinnedAppCount - 1) { dragAxisOffset = axisOffset;
newTargetIndex = targetIndex + 1;
} else if (dragOffset.x < -threshold && targetIndex > 0) { const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08));
newTargetIndex = targetIndex - 1; const itemSize = actualIconSize * 1.2 + spacing;
} const slotOffset = Math.round(axisOffset / itemSize);
if (newTargetIndex !== targetIndex) { const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount - 1, originalIndex + slotOffset));
targetIndex = newTargetIndex;
dragStartPos = Qt.point(mouse.x, mouse.y); if (newTargetIndex !== targetIndex) {
} targetIndex = newTargetIndex;
} dockApps.dropTargetIndex = newTargetIndex;
} }
} }
onClicked: mouse => { onClicked: mouse => {
if (!appData || longPressing) { if (!appData)
return; return;
}
if (mouse.button === Qt.LeftButton) { if (mouse.button === Qt.MiddleButton) {
if (appData.type === "pinned") { switch (appData.type) {
if (appData && appData.appId) { case "window":
const desktopEntry = cachedDesktopEntry; appData.toplevel?.close();
if (desktopEntry) { break;
AppUsageHistoryData.addAppUsage({ case "grouped":
"id": appData.appId,
"name": desktopEntry.name || appData.appId,
"icon": desktopEntry.icon || "",
"exec": desktopEntry.exec || "",
"comment": desktopEntry.comment || ""
});
}
SessionService.launchDesktopEntry(desktopEntry);
}
} else if (appData.type === "window") {
const toplevel = getToplevelObject();
if (toplevel) {
toplevel.activate();
}
} else if (appData.type === "grouped") {
if (appData.windowCount === 0) {
if (appData && appData.appId) {
const desktopEntry = cachedDesktopEntry;
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": desktopEntry.name || appData.appId,
"icon": desktopEntry.icon || "",
"exec": desktopEntry.exec || "",
"comment": desktopEntry.comment || ""
});
}
SessionService.launchDesktopEntry(desktopEntry);
}
} else if (appData.windowCount === 1) {
// For single window, activate directly
const toplevel = getToplevelObject();
if (toplevel) {
console.log("Activating grouped app window:", appData.windowTitle);
toplevel.activate();
} else {
console.warn("No toplevel found for grouped app");
}
} else {
if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
}
}
}
} else if (mouse.button === Qt.MiddleButton) {
if (appData?.type === "window") {
appData?.toplevel?.close();
} else if (appData?.type === "grouped") {
if (contextMenu) { if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell"; const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen); contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
} }
} else if (appData && appData.appId) { break;
default:
if (!appData.appId)
return;
const desktopEntry = cachedDesktopEntry; const desktopEntry = cachedDesktopEntry;
if (desktopEntry) { if (desktopEntry) {
AppUsageHistoryData.addAppUsage({ AppUsageHistoryData.addAppUsage({
@@ -301,26 +322,39 @@ Item {
}); });
} }
SessionService.launchDesktopEntry(desktopEntry); SessionService.launchDesktopEntry(desktopEntry);
break;
} }
} else if (mouse.button === Qt.RightButton) { } else if (mouse.button === Qt.RightButton) {
if (contextMenu && appData) { if (!contextMenu)
const shouldHidePin = appData.appId === "org.quickshell"; return;
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen); const shouldHidePin = appData.appId === "org.quickshell";
} else { contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
console.warn("No context menu or appData available");
}
} }
} }
} }
property real hoverAnimOffset: 0
Item { Item {
id: visualContent id: visualContent
anchors.fill: parent anchors.fill: parent
transform: Translate { transform: Translate {
id: iconTransform id: iconTransform
x: 0 x: {
y: 0 if (dragging && !isVertical)
return dragAxisOffset;
if (!dragging && isVertical)
return hoverAnimOffset;
return 0;
}
y: {
if (dragging && isVertical)
return dragAxisOffset;
if (!dragging && !isVertical)
return hoverAnimOffset;
return 0;
}
} }
Rectangle { Rectangle {
+211 -163
View File
@@ -1,11 +1,8 @@
import QtQuick import QtQuick
import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland import Quickshell.Hyprland
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
@@ -17,6 +14,9 @@ Item {
property bool isVertical: false property bool isVertical: false
property var dockScreen: null property var dockScreen: null
property real iconSize: 40 property real iconSize: 40
property int draggedIndex: -1
property int dropTargetIndex: -1
property bool suppressShiftAnimation: false
clip: false clip: false
implicitWidth: isVertical ? appLayout.height : appLayout.width implicitWidth: isVertical ? appLayout.height : appLayout.width
@@ -24,18 +24,18 @@ Item {
function movePinnedApp(fromIndex, toIndex) { function movePinnedApp(fromIndex, toIndex) {
if (fromIndex === toIndex) { if (fromIndex === toIndex) {
return return;
} }
const currentPinned = [...(SessionData.pinnedApps || [])] const currentPinned = [...(SessionData.pinnedApps || [])];
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) { if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) {
return return;
} }
const movedApp = currentPinned.splice(fromIndex, 1)[0] const movedApp = currentPinned.splice(fromIndex, 1)[0];
currentPinned.splice(toIndex, 0, movedApp) currentPinned.splice(toIndex, 0, movedApp);
SessionData.setPinnedApps(currentPinned) SessionData.setPinnedApps(currentPinned);
} }
Item { Item {
@@ -53,202 +53,250 @@ Item {
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
spacing: Math.min(8, Math.max(4, root.iconSize * 0.08)) spacing: Math.min(8, Math.max(4, root.iconSize * 0.08))
Repeater { Repeater {
id: repeater id: repeater
property var dockItems: [] property var dockItems: []
model: ScriptModel { model: ScriptModel {
values: repeater.dockItems values: repeater.dockItems
objectProp: "uniqueKey" objectProp: "uniqueKey"
} }
Component.onCompleted: updateModel() Component.onCompleted: updateModel()
function updateModel() { function updateModel() {
const items = [] const items = [];
const pinnedApps = [...(SessionData.pinnedApps || [])] const pinnedApps = [...(SessionData.pinnedApps || [])];
const sortedToplevels = CompositorService.sortedToplevels const sortedToplevels = CompositorService.sortedToplevels;
if (root.groupByApp) { if (root.groupByApp) {
const appGroups = new Map() const appGroups = new Map();
pinnedApps.forEach(rawAppId => { pinnedApps.forEach(rawAppId => {
const appId = Paths.moddedAppId(rawAppId) const appId = Paths.moddedAppId(rawAppId);
appGroups.set(appId, {
appId: appId,
isPinned: true,
windows: []
})
})
sortedToplevels.forEach((toplevel, index) => {
const rawAppId = toplevel.appId || "unknown"
const appId = Paths.moddedAppId(rawAppId)
if (!appGroups.has(appId)) {
appGroups.set(appId, { appGroups.set(appId, {
appId: appId, appId: appId,
isPinned: false, isPinned: true,
windows: [] windows: []
}) });
});
sortedToplevels.forEach((toplevel, index) => {
const rawAppId = toplevel.appId || "unknown";
const appId = Paths.moddedAppId(rawAppId);
if (!appGroups.has(appId)) {
appGroups.set(appId, {
appId: appId,
isPinned: false,
windows: []
});
}
appGroups.get(appId).windows.push({
toplevel: toplevel,
index: index
});
});
const pinnedGroups = [];
const unpinnedGroups = [];
Array.from(appGroups.entries()).forEach(([appId, group]) => {
const firstWindow = group.windows.length > 0 ? group.windows[0] : null;
const item = {
uniqueKey: "grouped_" + appId,
type: "grouped",
appId: appId,
toplevel: firstWindow ? firstWindow.toplevel : null,
isPinned: group.isPinned,
isRunning: group.windows.length > 0,
windowCount: group.windows.length,
allWindows: group.windows
};
if (group.isPinned) {
pinnedGroups.push(item);
} else {
unpinnedGroups.push(item);
}
});
pinnedGroups.forEach(item => items.push(item));
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
items.push({
uniqueKey: "separator_grouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
});
} }
appGroups.get(appId).windows.push({ unpinnedGroups.forEach(item => items.push(item));
toplevel: toplevel, root.pinnedAppCount = pinnedGroups.length;
index: index } else {
}) pinnedApps.forEach(rawAppId => {
}) const appId = Paths.moddedAppId(rawAppId);
items.push({
uniqueKey: "pinned_" + appId,
type: "pinned",
appId: appId,
toplevel: null,
isPinned: true,
isRunning: false
});
});
const pinnedGroups = [] root.pinnedAppCount = pinnedApps.length;
const unpinnedGroups = []
Array.from(appGroups.entries()).forEach(([appId, group]) => { if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
const firstWindow = group.windows.length > 0 ? group.windows[0] : null items.push({
uniqueKey: "separator_ungrouped",
const item = { type: "separator",
uniqueKey: "grouped_" + appId, appId: "__SEPARATOR__",
type: "grouped", toplevel: null,
appId: appId, isPinned: false,
toplevel: firstWindow ? firstWindow.toplevel : null, isRunning: false
isPinned: group.isPinned, });
isRunning: group.windows.length > 0,
windowCount: group.windows.length,
allWindows: group.windows
} }
if (group.isPinned) { sortedToplevels.forEach((toplevel, index) => {
pinnedGroups.push(item) let uniqueKey = "window_" + index;
} else { if (CompositorService.isHyprland && Hyprland.toplevels) {
unpinnedGroups.push(item) const hyprlandToplevels = Array.from(Hyprland.toplevels.values);
} for (let i = 0; i < hyprlandToplevels.length; i++) {
}) if (hyprlandToplevels[i].wayland === toplevel) {
uniqueKey = "window_" + hyprlandToplevels[i].address;
pinnedGroups.forEach(item => items.push(item)) break;
}
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
items.push({
uniqueKey: "separator_grouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
})
}
unpinnedGroups.forEach(item => items.push(item))
root.pinnedAppCount = pinnedGroups.length
} else {
pinnedApps.forEach(rawAppId => {
const appId = Paths.moddedAppId(rawAppId)
items.push({
uniqueKey: "pinned_" + appId,
type: "pinned",
appId: appId,
toplevel: null,
isPinned: true,
isRunning: false
})
})
root.pinnedAppCount = pinnedApps.length
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
items.push({
uniqueKey: "separator_ungrouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
})
}
sortedToplevels.forEach((toplevel, index) => {
let uniqueKey = "window_" + index
if (CompositorService.isHyprland && Hyprland.toplevels) {
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
for (let i = 0; i < hyprlandToplevels.length; i++) {
if (hyprlandToplevels[i].wayland === toplevel) {
uniqueKey = "window_" + hyprlandToplevels[i].address
break
} }
} }
items.push({
uniqueKey: uniqueKey,
type: "window",
appId: Paths.moddedAppId(toplevel.appId),
toplevel: toplevel,
isPinned: false,
isRunning: true
});
});
}
dockItems = items;
}
delegate: Item {
id: delegateItem
property alias dockButton: button
property var itemData: modelData
clip: false
z: button.dragging ? 100 : 0
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
property real shiftOffset: {
if (root.draggedIndex < 0 || !itemData.isPinned || itemData.type === "separator")
return 0;
if (model.index === root.draggedIndex)
return 0;
const dragIdx = root.draggedIndex;
const dropIdx = root.dropTargetIndex;
const myIdx = model.index;
const shiftAmount = root.iconSize * 1.2 + layoutFlow.spacing;
if (dropIdx < 0)
return 0;
if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx)
return -shiftAmount;
if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx)
return shiftAmount;
return 0;
}
transform: Translate {
x: root.isVertical ? 0 : delegateItem.shiftOffset
y: root.isVertical ? delegateItem.shiftOffset : 0
Behavior on x {
enabled: !root.suppressShiftAnimation
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
} }
items.push({ Behavior on y {
uniqueKey: uniqueKey, enabled: !root.suppressShiftAnimation
type: "window", NumberAnimation {
appId: Paths.moddedAppId(toplevel.appId), duration: 150
toplevel: toplevel, easing.type: Easing.OutCubic
isPinned: false, }
isRunning: true }
}) }
})
}
dockItems = items Rectangle {
} visible: itemData.type === "separator"
width: root.isVertical ? root.iconSize * 0.5 : 2
height: root.isVertical ? 2 : root.iconSize * 0.5
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
radius: 1
anchors.centerIn: parent
}
delegate: Item { DockAppButton {
id: delegateItem id: button
property alias dockButton: button visible: itemData.type !== "separator"
property var itemData: modelData anchors.centerIn: parent
clip: false
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2) width: delegateItem.width
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize) height: delegateItem.height
actualIconSize: root.iconSize
Rectangle { appData: itemData
visible: itemData.type === "separator" contextMenu: root.contextMenu
width: root.isVertical ? root.iconSize * 0.5 : 2 dockApps: root
height: root.isVertical ? 2 : root.iconSize * 0.5 index: model.index
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) parentDockScreen: root.dockScreen
radius: 1
anchors.centerIn: parent
}
DockAppButton { showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
id: button windowTitle: {
visible: itemData.type !== "separator" const title = itemData?.toplevel?.title || "(Unnamed)";
anchors.centerIn: parent return title.length > 50 ? title.substring(0, 47) + "..." : title;
}
width: delegateItem.width
height: delegateItem.height
actualIconSize: root.iconSize
appData: itemData
contextMenu: root.contextMenu
dockApps: root
index: model.index
parentDockScreen: root.dockScreen
showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
windowTitle: {
const title = itemData?.toplevel?.title || "(Unnamed)"
return title.length > 50 ? title.substring(0, 47) + "..." : title
} }
} }
} }
} }
}
} }
Connections { Connections {
target: CompositorService target: CompositorService
function onToplevelsChanged() { function onToplevelsChanged() {
repeater.updateModel() repeater.updateModel();
} }
} }
Connections { Connections {
target: SessionData target: SessionData
function onPinnedAppsChanged() { function onPinnedAppsChanged() {
repeater.updateModel() root.suppressShiftAnimation = true;
root.draggedIndex = -1;
root.dropTargetIndex = -1;
repeater.updateModel();
Qt.callLater(() => {
root.suppressShiftAnimation = false;
});
} }
} }
onGroupByAppChanged: { onGroupByAppChanged: {
repeater.updateModel() repeater.updateModel();
} }
} }
File diff suppressed because it is too large Load Diff
+129 -122
View File
@@ -9,103 +9,110 @@ Item {
id: root id: root
function getBarComponentsFromSettings() { function getBarComponentsFromSettings() {
const bars = SettingsData.barConfigs || [] const bars = SettingsData.barConfigs || [];
return bars.map(bar => ({ return bars.map(bar => ({
"id": "bar:" + bar.id, "id": "bar:" + bar.id,
"name": bar.name || "Bar", "name": bar.name || "Bar",
"description": I18n.tr("Individual bar configuration"), "description": I18n.tr("Individual bar configuration"),
"icon": "toolbar", "icon": "toolbar",
"barId": bar.id "barId": bar.id
})) }));
} }
property var variantComponents: getVariantComponentsList() property var variantComponents: getVariantComponentsList()
function getVariantComponentsList() { function getVariantComponentsList() {
return [...getBarComponentsFromSettings(), { return [...getBarComponentsFromSettings(),
"id": "dock", {
"name": I18n.tr("Application Dock"), "id": "dock",
"description": I18n.tr("Bottom dock for pinned and running applications"), "name": I18n.tr("Application Dock"),
"icon": "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"), "id": "notifications",
"icon": "notifications" "name": I18n.tr("Notification Popups"),
}, { "description": I18n.tr("Notification toast popups"),
"id": "wallpaper", "icon": "notifications"
"name": I18n.tr("Wallpaper"), },
"description": I18n.tr("Desktop background images"), {
"icon": "wallpaper" "id": "wallpaper",
}, { "name": I18n.tr("Wallpaper"),
"id": "osd", "description": I18n.tr("Desktop background images"),
"name": I18n.tr("On-Screen Displays"), "icon": "wallpaper"
"description": I18n.tr("Volume, brightness, and other system OSDs"), },
"icon": "picture_in_picture" {
}, { "id": "osd",
"id": "toast", "name": I18n.tr("On-Screen Displays"),
"name": I18n.tr("Toast Messages"), "description": I18n.tr("Volume, brightness, and other system OSDs"),
"description": I18n.tr("System toast notifications"), "icon": "picture_in_picture"
"icon": "campaign" },
}, { {
"id": "notepad", "id": "toast",
"name": I18n.tr("Notepad Slideout"), "name": I18n.tr("Toast Messages"),
"description": I18n.tr("Quick note-taking slideout panel"), "description": I18n.tr("System toast notifications"),
"icon": "sticky_note_2" "icon": "campaign"
}] },
{
"id": "notepad",
"name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("Quick note-taking slideout panel"),
"icon": "sticky_note_2"
}
];
} }
Connections { Connections {
target: SettingsData target: SettingsData
function onBarConfigsChanged() { function onBarConfigsChanged() {
variantComponents = getVariantComponentsList() variantComponents = getVariantComponentsList();
} }
} }
function getScreenPreferences(componentId) { function getScreenPreferences(componentId) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4) const barId = componentId.substring(4);
const barConfig = SettingsData.getBarConfig(barId) const barConfig = SettingsData.getBarConfig(barId);
return barConfig?.screenPreferences || ["all"] return barConfig?.screenPreferences || ["all"];
} }
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"] return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"];
} }
function setScreenPreferences(componentId, screenNames) { function setScreenPreferences(componentId, screenNames) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4) const barId = componentId.substring(4);
SettingsData.updateBarConfig(barId, { SettingsData.updateBarConfig(barId, {
"screenPreferences": screenNames "screenPreferences": screenNames
}) });
return return;
} }
var prefs = SettingsData.screenPreferences || {} var prefs = SettingsData.screenPreferences || {};
var newPrefs = Object.assign({}, prefs) var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = screenNames newPrefs[componentId] = screenNames;
SettingsData.set("screenPreferences", newPrefs) SettingsData.set("screenPreferences", newPrefs);
} }
function getShowOnLastDisplay(componentId) { function getShowOnLastDisplay(componentId) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4) const barId = componentId.substring(4);
const barConfig = SettingsData.getBarConfig(barId) const barConfig = SettingsData.getBarConfig(barId);
return barConfig?.showOnLastDisplay ?? true return barConfig?.showOnLastDisplay ?? true;
} }
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false;
} }
function setShowOnLastDisplay(componentId, enabled) { function setShowOnLastDisplay(componentId, enabled) {
if (componentId.startsWith("bar:")) { if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4) const barId = componentId.substring(4);
SettingsData.updateBarConfig(barId, { SettingsData.updateBarConfig(barId, {
"showOnLastDisplay": enabled "showOnLastDisplay": enabled
}) });
return return;
} }
var prefs = SettingsData.showOnLastDisplay || {} var prefs = SettingsData.showOnLastDisplay || {};
var newPrefs = Object.assign({}, prefs) var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = enabled newPrefs[componentId] = enabled;
SettingsData.set("showOnLastDisplay", newPrefs) SettingsData.set("showOnLastDisplay", newPrefs);
} }
DankFlickable { DankFlickable {
@@ -210,16 +217,16 @@ Item {
model: [I18n.tr("Name"), I18n.tr("Model")] model: [I18n.tr("Name"), I18n.tr("Model")]
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
onSelectionChanged: (index, selected) => { onSelectionChanged: (index, selected) => {
if (!selected) if (!selected)
return return;
SettingsData.displayNameMode = index === 1 ? "model" : "system" SettingsData.displayNameMode = index === 1 ? "model" : "system";
SettingsData.saveSettings() SettingsData.saveSettings();
} }
Connections { Connections {
target: SettingsData target: SettingsData
function onDisplayNameModeChanged() { function onDisplayNameModeChanged() {
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0 displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0;
} }
} }
} }
@@ -273,9 +280,9 @@ Item {
StyledText { StyledText {
text: { text: {
if (parent.currentMode) { if (parent.currentMode) {
return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz" return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz";
} }
return modelData.width + "×" + modelData.height return modelData.width + "×" + modelData.height;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
@@ -378,20 +385,20 @@ Item {
text: I18n.tr("All displays") text: I18n.tr("All displays")
description: I18n.tr("Show on all connected displays") description: I18n.tr("Show on all connected displays")
checked: { checked: {
var prefs = root.getScreenPreferences(parent.componentId) var prefs = root.getScreenPreferences(parent.componentId);
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all") return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
} }
onToggled: checked => { onToggled: checked => {
if (checked) { if (checked) {
root.setScreenPreferences(parent.componentId, ["all"]) root.setScreenPreferences(parent.componentId, ["all"]);
} else { } else {
root.setScreenPreferences(parent.componentId, []) root.setScreenPreferences(parent.componentId, []);
const cid = parent.componentId const cid = parent.componentId;
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) { if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
root.setShowOnLastDisplay(cid, true) root.setShowOnLastDisplay(cid, true);
} }
} }
} }
} }
DankToggle { DankToggle {
@@ -400,15 +407,15 @@ Item {
description: I18n.tr("Always show when there's only one connected display") description: I18n.tr("Always show when there's only one connected display")
checked: root.getShowOnLastDisplay(parent.componentId) checked: root.getShowOnLastDisplay(parent.componentId)
visible: { visible: {
const prefs = root.getScreenPreferences(parent.componentId) const prefs = root.getScreenPreferences(parent.componentId);
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all") const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
const cid = parent.componentId const cid = parent.componentId;
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:") const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:");
return !isAll && isRelevantComponent return !isAll && isRelevantComponent;
} }
onToggled: checked => { onToggled: checked => {
root.setShowOnLastDisplay(parent.componentId, checked) root.setShowOnLastDisplay(parent.componentId, checked);
} }
} }
Rectangle { Rectangle {
@@ -417,8 +424,8 @@ Item {
color: Theme.outline color: Theme.outline
opacity: 0.2 opacity: 0.2
visible: { visible: {
var prefs = root.getScreenPreferences(parent.componentId) var prefs = root.getScreenPreferences(parent.componentId);
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all") return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
} }
} }
@@ -426,8 +433,8 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: { visible: {
var prefs = root.getScreenPreferences(parent.componentId) var prefs = root.getScreenPreferences(parent.componentId);
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all") return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
} }
Repeater { Repeater {
@@ -441,41 +448,41 @@ Item {
text: SettingsData.getScreenDisplayName(screenData) text: SettingsData.getScreenDisplayName(screenData)
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name) description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
checked: { checked: {
var prefs = root.getScreenPreferences(componentId) var prefs = root.getScreenPreferences(componentId);
if (typeof prefs[0] === "string" && prefs[0] === "all") if (typeof prefs[0] === "string" && prefs[0] === "all")
return false return false;
return SettingsData.isScreenInPreferences(screenData, prefs) return SettingsData.isScreenInPreferences(screenData, prefs);
} }
onToggled: checked => { onToggled: checked => {
var currentPrefs = root.getScreenPreferences(componentId) var currentPrefs = root.getScreenPreferences(componentId);
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") { if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
currentPrefs = [] currentPrefs = [];
} }
const screenModelIndex = SettingsData.getScreenModelIndex(screenData) const screenModelIndex = SettingsData.getScreenModelIndex(screenData);
var newPrefs = currentPrefs.filter(pref => { var newPrefs = currentPrefs.filter(pref => {
if (typeof pref === "string") if (typeof pref === "string")
return false return false;
if (pref.modelIndex !== undefined && screenModelIndex >= 0) { if (pref.modelIndex !== undefined && screenModelIndex >= 0) {
return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex) return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex);
} }
return pref.name !== screenData.name || pref.model !== screenData.model return pref.name !== screenData.name || pref.model !== screenData.model;
}) });
if (checked) { if (checked) {
const prefObj = { const prefObj = {
"name": screenData.name, "name": screenData.name,
"model": screenData.model || "" "model": screenData.model || ""
} };
if (screenModelIndex >= 0) { if (screenModelIndex >= 0) {
prefObj.modelIndex = screenModelIndex prefObj.modelIndex = screenModelIndex;
} }
newPrefs.push(prefObj) newPrefs.push(prefObj);
} }
root.setScreenPreferences(componentId, newPrefs) root.setScreenPreferences(componentId, newPrefs);
} }
} }
} }
} }
+76 -76
View File
@@ -1,6 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -10,14 +8,14 @@ Item {
function formatGammaTime(isoString) { function formatGammaTime(isoString) {
if (!isoString) if (!isoString)
return "" return "";
try { try {
const date = new Date(isoString) const date = new Date(isoString);
if (isNaN(date.getTime())) if (isNaN(date.getTime()))
return "" return "";
return date.toLocaleTimeString(Qt.locale(), "HH:mm") return date.toLocaleTimeString(Qt.locale(), "HH:mm");
} catch (e) { } catch (e) {
return "" return "";
} }
} }
@@ -74,17 +72,16 @@ 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( 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+.")
"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
@@ -104,19 +101,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 {
@@ -126,19 +123,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);
} }
} }
} }
} }
@@ -150,18 +147,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;
} }
} }
} }
@@ -175,7 +172,7 @@ Item {
Connections { Connections {
target: SessionData target: SessionData
function onNightModeAutoEnabledChanged() { function onNightModeAutoEnabledChanged() {
automaticSettings.visible = SessionData.nightModeAutoEnabled automaticSettings.visible = SessionData.nightModeAutoEnabled;
} }
} }
@@ -188,29 +185,32 @@ Item {
width: 200 width: 200
height: 45 height: 45
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
model: [{ model: [
{
"text": "Time", "text": "Time",
"icon": "access_time" "icon": "access_time"
}, { },
{
"text": "Location", "text": "Location",
"icon": "place" "icon": "place"
}] }
]
Component.onCompleted: { Component.onCompleted: {
currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0 currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0;
Qt.callLater(updateIndicator) Qt.callLater(updateIndicator);
} }
onTabClicked: index => { onTabClicked: index => {
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time") DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time");
currentIndex = index currentIndex = index;
} }
Connections { Connections {
target: SessionData target: SessionData
function onNightModeAutoModeChanged() { function onNightModeAutoModeChanged() {
modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0 modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0;
Qt.callLater(modeTabBarNight.updateIndicator) Qt.callLater(modeTabBarNight.updateIndicator);
} }
} }
} }
@@ -267,30 +267,30 @@ Item {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeStartHour.toString() currentValue: SessionData.nightModeStartHour.toString()
options: { options: {
var hours = [] var hours = [];
for (var i = 0; i < 24; i++) { for (var i = 0; i < 24; i++) {
hours.push(i.toString()) hours.push(i.toString());
} }
return hours return hours;
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeStartHour(parseInt(value)) SessionData.setNightModeStartHour(parseInt(value));
} }
} }
DankDropdown { DankDropdown {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0') currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0')
options: { options: {
var minutes = [] var minutes = [];
for (var i = 0; i < 60; i += 5) { for (var i = 0; i < 60; i += 5) {
minutes.push(i.toString().padStart(2, '0')) minutes.push(i.toString().padStart(2, '0'));
} }
return minutes return minutes;
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeStartMinute(parseInt(value)) SessionData.setNightModeStartMinute(parseInt(value));
} }
} }
} }
@@ -310,30 +310,30 @@ Item {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeEndHour.toString() currentValue: SessionData.nightModeEndHour.toString()
options: { options: {
var hours = [] var hours = [];
for (var i = 0; i < 24; i++) { for (var i = 0; i < 24; i++) {
hours.push(i.toString()) hours.push(i.toString());
} }
return hours return hours;
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeEndHour(parseInt(value)) SessionData.setNightModeEndHour(parseInt(value));
} }
} }
DankDropdown { DankDropdown {
dropdownWidth: 70 dropdownWidth: 70
currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0') currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0')
options: { options: {
var minutes = [] var minutes = [];
for (var i = 0; i < 60; i += 5) { for (var i = 0; i < 60; i += 5) {
minutes.push(i.toString().padStart(2, '0')) minutes.push(i.toString().padStart(2, '0'));
} }
return minutes return minutes;
} }
onValueChanged: value => { onValueChanged: value => {
SessionData.setNightModeEndMinute(parseInt(value)) SessionData.setNightModeEndMinute(parseInt(value));
} }
} }
} }
} }
@@ -352,13 +352,13 @@ Item {
description: I18n.tr("Automatically detect location based on IP address") description: I18n.tr("Automatically detect location based on IP address")
checked: SessionData.nightModeUseIPLocation || false checked: SessionData.nightModeUseIPLocation || false
onToggled: checked => { onToggled: checked => {
SessionData.setNightModeUseIPLocation(checked) SessionData.setNightModeUseIPLocation(checked);
} }
Connections { Connections {
target: SessionData target: SessionData
function onNightModeUseIPLocationChanged() { function onNightModeUseIPLocationChanged() {
ipLocationToggle.checked = SessionData.nightModeUseIPLocation ipLocationToggle.checked = SessionData.nightModeUseIPLocation;
} }
} }
} }
@@ -393,9 +393,9 @@ Item {
text: SessionData.latitude.toString() text: SessionData.latitude.toString()
placeholderText: "0.0" placeholderText: "0.0"
onEditingFinished: { onEditingFinished: {
const lat = parseFloat(text) const lat = parseFloat(text);
if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) {
SessionData.setLatitude(lat) SessionData.setLatitude(lat);
} }
} }
} }
@@ -416,9 +416,9 @@ Item {
text: SessionData.longitude.toString() text: SessionData.longitude.toString()
placeholderText: "0.0" placeholderText: "0.0"
onEditingFinished: { onEditingFinished: {
const lon = parseFloat(text) const lon = parseFloat(text);
if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) {
SessionData.setLongitude(lon) SessionData.setLongitude(lon);
} }
} }
} }
+44 -49
View File
@@ -272,82 +272,77 @@ Singleton {
function generateOutputsConfig(outputsData) { function generateOutputsConfig(outputsData) {
if (!outputsData || Object.keys(outputsData).length === 0) if (!outputsData || Object.keys(outputsData).length === 0)
return return;
let lines = ["# Auto-generated by DMS - do not edit manually", "# VRR is global: set adaptive_sync=1 in config.conf", ""];
let lines = ["# Auto-generated by DMS - do not edit manually", "# VRR is global: set adaptive_sync=1 in config.conf", ""]
for (const outputName in outputsData) { for (const outputName in outputsData) {
const output = outputsData[outputName] const output = outputsData[outputName];
if (!output) if (!output)
continue continue;
let width = 1920;
let width = 1920 let height = 1080;
let height = 1080 let refreshRate = 60;
let refreshRate = 60
if (output.modes && output.current_mode !== undefined) { if (output.modes && output.current_mode !== undefined) {
const mode = output.modes[output.current_mode] const mode = output.modes[output.current_mode];
if (mode) { if (mode) {
width = mode.width || 1920 width = mode.width || 1920;
height = mode.height || 1080 height = mode.height || 1080;
refreshRate = Math.round((mode.refresh_rate || 60000) / 1000) refreshRate = Math.round((mode.refresh_rate || 60000) / 1000);
} }
} }
const x = output.logical?.x ?? 0 const x = output.logical?.x ?? 0;
const y = output.logical?.y ?? 0 const y = output.logical?.y ?? 0;
const scale = output.logical?.scale ?? 1.0 const scale = output.logical?.scale ?? 1.0;
const transform = transformToMango(output.logical?.transform ?? "Normal") const transform = transformToMango(output.logical?.transform ?? "Normal");
const rule = [ const rule = [outputName, "0.55", "1", "tile", transform, scale, x, y, width, height, refreshRate].join(",");
outputName,
"0.55",
"1",
"tile",
transform,
scale,
x,
y,
width,
height,
refreshRate
].join(",")
lines.push("monitorrule=" + rule) lines.push("monitorrule=" + rule);
} }
lines.push("") lines.push("");
const content = lines.join("\n") const content = lines.join("\n");
Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("DwlService: Failed to write outputs config:", output) console.warn("DwlService: Failed to write outputs config:", output);
return return;
} }
console.info("DwlService: Generated outputs config at", outputsPath) console.info("DwlService: Generated outputs config at", outputsPath);
if (CompositorService.isDwl) if (CompositorService.isDwl)
reloadConfig() reloadConfig();
}) });
} }
function reloadConfig() { function reloadConfig() {
Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => { Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("DwlService: mmsg reload_config failed:", output) console.warn("DwlService: mmsg reload_config failed:", output);
}) });
} }
function transformToMango(transform) { function transformToMango(transform) {
switch (transform) { switch (transform) {
case "Normal": return 0 case "Normal":
case "90": return 1 return 0;
case "180": return 2 case "90":
case "270": return 3 return 1;
case "Flipped": return 4 case "180":
case "Flipped90": return 5 return 2;
case "Flipped180": return 6 case "270":
case "Flipped270": return 7 return 3;
default: return 0 case "Flipped":
return 4;
case "Flipped90":
return 5;
case "Flipped180":
return 6;
case "Flipped270":
return 7;
default:
return 0;
} }
} }
} }
+64 -49
View File
@@ -4,7 +4,6 @@ pragma ComponentBehavior: Bound
import QtCore import QtCore
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland
import qs.Common import qs.Common
Singleton { Singleton {
@@ -16,95 +15,111 @@ Singleton {
function getOutputIdentifier(output, outputName) { function getOutputIdentifier(output, outputName) {
if (SettingsData.displayNameMode === "model" && output.make && output.model) { if (SettingsData.displayNameMode === "model" && output.make && output.model) {
return "desc:" + output.make + " " + output.model return "desc:" + output.make + " " + output.model;
} }
return outputName return outputName;
} }
function generateOutputsConfig(outputsData) { function generateOutputsConfig(outputsData) {
if (!outputsData || Object.keys(outputsData).length === 0) if (!outputsData || Object.keys(outputsData).length === 0)
return return;
let lines = ["# Auto-generated by DMS - do not edit manually", ""];
let lines = ["# Auto-generated by DMS - do not edit manually", ""]
for (const outputName in outputsData) { for (const outputName in outputsData) {
const output = outputsData[outputName] const output = outputsData[outputName];
if (!output) if (!output)
continue continue;
let resolution = "preferred";
let resolution = "preferred"
if (output.modes && output.current_mode !== undefined) { if (output.modes && output.current_mode !== undefined) {
const mode = output.modes[output.current_mode] const mode = output.modes[output.current_mode];
if (mode) if (mode)
resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3) resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3);
} }
const x = output.logical?.x ?? 0 const x = output.logical?.x ?? 0;
const y = output.logical?.y ?? 0 const y = output.logical?.y ?? 0;
const position = x + "x" + y const position = x + "x" + y;
const scale = output.logical?.scale ?? 1.0 const scale = output.logical?.scale ?? 1.0;
const identifier = getOutputIdentifier(output, outputName) const identifier = getOutputIdentifier(output, outputName);
let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale;
const transform = transformToHyprland(output.logical?.transform ?? "Normal") const transform = transformToHyprland(output.logical?.transform ?? "Normal");
if (transform !== 0) if (transform !== 0)
monitorLine += ", transform, " + transform monitorLine += ", transform, " + transform;
if (output.vrr_supported && output.vrr_enabled) if (output.vrr_supported && output.vrr_enabled)
monitorLine += ", vrr, 1" monitorLine += ", vrr, 1";
lines.push(monitorLine) lines.push(monitorLine);
} }
lines.push("") lines.push("");
const content = lines.join("\n") const content = lines.join("\n");
Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("HyprlandService: Failed to write outputs config:", output) console.warn("HyprlandService: Failed to write outputs config:", output);
return return;
} }
console.info("HyprlandService: Generated outputs config at", outputsPath) console.info("HyprlandService: Generated outputs config at", outputsPath);
if (CompositorService.isHyprland) if (CompositorService.isHyprland)
reloadConfig() reloadConfig();
}) });
} }
function reloadConfig() { function reloadConfig() {
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => { Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: hyprctl reload failed:", output) console.warn("HyprlandService: hyprctl reload failed:", output);
}) });
} }
function transformToHyprland(transform) { function transformToHyprland(transform) {
switch (transform) { switch (transform) {
case "Normal": return 0 case "Normal":
case "90": return 1 return 0;
case "180": return 2 case "90":
case "270": return 3 return 1;
case "Flipped": return 4 case "180":
case "Flipped90": return 5 return 2;
case "Flipped180": return 6 case "270":
case "Flipped270": return 7 return 3;
default: return 0 case "Flipped":
return 4;
case "Flipped90":
return 5;
case "Flipped180":
return 6;
case "Flipped270":
return 7;
default:
return 0;
} }
} }
function hyprlandToTransform(value) { function hyprlandToTransform(value) {
switch (value) { switch (value) {
case 0: return "Normal" case 0:
case 1: return "90" return "Normal";
case 2: return "180" case 1:
case 3: return "270" return "90";
case 4: return "Flipped" case 2:
case 5: return "Flipped90" return "180";
case 6: return "Flipped180" case 3:
case 7: return "Flipped270" return "270";
default: return "Normal" case 4:
return "Flipped";
case 5:
return "Flipped90";
case 6:
return "Flipped180";
case 7:
return "Flipped270";
default:
return "Normal";
} }
} }
} }
+1 -1
View File
@@ -1,3 +1,3 @@
[templates.dmsghostty] [templates.dmsghostty]
input_path = 'SHELL_DIR/matugen/templates/ghostty.conf' input_path = 'SHELL_DIR/matugen/templates/ghostty.conf'
output_path = '~/.config/ghostty/config-dankcolors' output_path = '~/.config/ghostty/themes/dankcolors'