mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 03:28:28 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e791337ae9 | |||
| a8c15fcde9 | |||
| 601d4104a3 | |||
| 7979fb2b0e | |||
| 06fa21118e |
@@ -24,7 +24,6 @@ jobs:
|
||||
check-updates:
|
||||
name: Check for updates
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'AvengeMedia/DankMaterialShell'
|
||||
|
||||
outputs:
|
||||
has_updates: ${{ steps.check.outputs.has_updates }}
|
||||
|
||||
@@ -24,7 +24,6 @@ jobs:
|
||||
check-updates:
|
||||
name: Check package/series updates
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'AvengeMedia/DankMaterialShell'
|
||||
|
||||
outputs:
|
||||
has_updates: ${{ steps.check.outputs.has_updates }}
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
name: Void Linux XBPS Repository
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 2,5,14,17,20,23 * * *" # 9am, 12pm, 3pm, 6pm, 9pm, 12am EST (UTC times shown)
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force_rebuild:
|
||||
description: 'Force rebuilding packages even if they already exist in the repository'
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
build_git:
|
||||
description: 'Build dms-git package'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_dms:
|
||||
description: 'Build stable dms package'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_greeter:
|
||||
description: 'Build stable dms-greeter package'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Build & Deploy XBPS packages
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'AvengeMedia/DankMaterialShell'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout gh-pages branch
|
||||
run: |
|
||||
git clone --branch gh-pages https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git gh-pages-repo || {
|
||||
echo "⚠️ gh-pages branch not found or empty, initializing a new one..."
|
||||
mkdir gh-pages-repo
|
||||
cd gh-pages-repo
|
||||
git init
|
||||
git checkout -b gh-pages
|
||||
git remote add origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
||||
cd ..
|
||||
}
|
||||
|
||||
- name: Install XBPS Static Utilities
|
||||
run: |
|
||||
mkdir -p ${{ github.workspace }}/xbps
|
||||
curl -s -L https://repo-default.voidlinux.org/static/xbps-static-latest.x86_64-musl.tar.xz | tar -xJ -C ${{ github.workspace }}/xbps
|
||||
echo "${{ github.workspace }}/xbps/usr/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Clone void-packages
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/void-linux/void-packages.git
|
||||
|
||||
- name: Inject templates
|
||||
run: |
|
||||
cp -R distro/void/srcpkgs/dms void-packages/srcpkgs/
|
||||
cp -R distro/void/srcpkgs/dms-greeter void-packages/srcpkgs/
|
||||
cp -R distro/void/srcpkgs/dms-git void-packages/srcpkgs/
|
||||
|
||||
- name: Enable unprivileged user namespaces (Ubuntu 24.04)
|
||||
run: |
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true
|
||||
|
||||
- name: Bootstrap xbps-src
|
||||
run: |
|
||||
cd void-packages
|
||||
./xbps-src binary-bootstrap
|
||||
|
||||
- name: Configure signing keys and trust
|
||||
run: |
|
||||
# Write private key; extract and register the public key
|
||||
echo "${{ secrets.XBPS_PRIVATE_KEY }}" > /tmp/xbps_privkey.pem
|
||||
chmod 600 /tmp/xbps_privkey.pem
|
||||
|
||||
# Extract public key in PEM format
|
||||
openssl rsa -in /tmp/xbps_privkey.pem -pubout -out /tmp/dms-key.pub
|
||||
rm -f /tmp/xbps_privkey.pem
|
||||
|
||||
# Compute MD5 fingerprint in colon-separated hex format
|
||||
FINGERPRINT=$(openssl rsa -pubin -in /tmp/dms-key.pub -outform DER 2>/dev/null | openssl dgst -md5 -c | tr '[:upper:]' '[:lower:]' | awk '{print $NF}')
|
||||
|
||||
# Format key in XML property list (plist) format as expected by xbps
|
||||
mkdir -p /tmp/keys
|
||||
cat <<EOF > "/tmp/keys/${FINGERPRINT}.plist"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>public-key</key>
|
||||
<data>$(base64 -w0 /tmp/dms-key.pub)</data>
|
||||
<key>public-key-size</key>
|
||||
<integer>4096</integer>
|
||||
<key>signature-by</key>
|
||||
<string>AvengeMedia</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
# Copy keys to all host and chroot trust stores
|
||||
sudo mkdir -p /var/db/xbps/keys
|
||||
sudo cp "/tmp/keys/${FINGERPRINT}.plist" "/var/db/xbps/keys/${FINGERPRINT}.plist"
|
||||
|
||||
mkdir -p void-packages/masterdir/var/db/xbps/keys
|
||||
cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/masterdir/var/db/xbps/keys/${FINGERPRINT}.plist"
|
||||
|
||||
mkdir -p void-packages/etc/xbps.d/keys
|
||||
cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/etc/xbps.d/keys/${FINGERPRINT}.plist"
|
||||
|
||||
mkdir -p void-packages/common/repo-keys
|
||||
cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/common/repo-keys/${FINGERPRINT}.plist"
|
||||
|
||||
rm -rf /tmp/keys /tmp/dms-key.pub
|
||||
|
||||
- name: Configure repositories
|
||||
run: |
|
||||
# Append the repository to repos-remote templates so xbps-src translates it automatically
|
||||
echo "repository=https://avengemedia.github.io/DankLinux/current" >> void-packages/etc/xbps.d/repos-remote.conf
|
||||
echo "repository=https://avengemedia.github.io/DankLinux/current" >> void-packages/etc/xbps.d/repos-remote-x86_64-multilib.conf
|
||||
|
||||
# Add any existing compiled packages to the build cache directory to avoid rebuilds
|
||||
if [ -d "gh-pages-repo/current" ]; then
|
||||
mkdir -p void-packages/hostdir/binpkgs
|
||||
cp -L gh-pages-repo/current/*.xbps void-packages/hostdir/binpkgs/ 2>/dev/null || true
|
||||
xbps-rindex -a void-packages/hostdir/binpkgs/*.xbps 2>/dev/null || true
|
||||
fi
|
||||
|
||||
- name: Build packages
|
||||
run: |
|
||||
mkdir -p gh-pages-repo/current
|
||||
|
||||
BUILD_DMS="${{ github.event.inputs.build_dms || 'true' }}"
|
||||
BUILD_GREETER="${{ github.event.inputs.build_greeter || 'true' }}"
|
||||
BUILD_GIT="${{ github.event.inputs.build_git || 'true' }}"
|
||||
FORCE_REBUILD="${{ github.event.inputs.force_rebuild || 'false' }}"
|
||||
|
||||
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
BUILD_DMS="false"
|
||||
BUILD_GREETER="false"
|
||||
BUILD_GIT="true"
|
||||
fi
|
||||
|
||||
if [ "${{ github.event_name }}" = "release" ]; then
|
||||
BUILD_DMS="true"
|
||||
BUILD_GREETER="true"
|
||||
BUILD_GIT="false"
|
||||
fi
|
||||
|
||||
echo "=== Starting Builds ==="
|
||||
echo "DMS stable build enabled: $BUILD_DMS"
|
||||
echo "Greeter stable build enabled: $BUILD_GREETER"
|
||||
echo "Git build enabled: $BUILD_GIT"
|
||||
echo "Force rebuild: $FORCE_REBUILD"
|
||||
|
||||
cd void-packages
|
||||
|
||||
# 1. Build dms-git (development package)
|
||||
if [ "$BUILD_GIT" = "true" ]; then
|
||||
# Calculate dynamic git version (tag.commits.hash)
|
||||
GIT_VER=$(git -C .. describe --tags --always | sed 's/^v//; s/-/./g')
|
||||
echo "🔨 Preparing dms-git version $GIT_VER"
|
||||
|
||||
# Stage source tarball in the xbps-src source cache.
|
||||
# --transform adds a top-level directory so xbps-src can extract
|
||||
# into $wrksrc (create_wrksrc=yes handles the rest).
|
||||
SRC_CACHE="hostdir/sources/dms-git-${GIT_VER}"
|
||||
mkdir -p "$SRC_CACHE"
|
||||
tar -czf "${SRC_CACHE}/dms-git-${GIT_VER}.tar.gz" \
|
||||
--exclude=void-packages \
|
||||
--exclude=gh-pages-repo \
|
||||
--exclude=.git \
|
||||
--exclude=danklinux \
|
||||
-C .. .
|
||||
|
||||
CHECKSUM=$(sha256sum "${SRC_CACHE}/dms-git-${GIT_VER}.tar.gz" | cut -d' ' -f1)
|
||||
|
||||
# Dynamically patch template version, checksum, and distfiles
|
||||
sed -i "s/^version=.*/version=${GIT_VER}/" srcpkgs/dms-git/template
|
||||
sed -i "s/^checksum=.*/checksum=${CHECKSUM}/" srcpkgs/dms-git/template
|
||||
sed -i "s|^distfiles=.*|distfiles=\"dms-git-${GIT_VER}.tar.gz\"|" srcpkgs/dms-git/template
|
||||
|
||||
EXPECTED_GIT_FILE="dms-git-${GIT_VER}_1.x86_64.xbps"
|
||||
|
||||
if [ -f "../gh-pages-repo/current/$EXPECTED_GIT_FILE" ] && [ "$FORCE_REBUILD" != "true" ]; then
|
||||
echo "✅ $EXPECTED_GIT_FILE already exists, skipping build."
|
||||
else
|
||||
echo "🔨 Compiling dms-git..."
|
||||
./xbps-src pkg dms-git
|
||||
rm -f "../gh-pages-repo/current/${EXPECTED_GIT_FILE}"
|
||||
cp -L hostdir/binpkgs/dms-git-*.xbps ../gh-pages-repo/current/
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. Build stable dms package
|
||||
if [ "$BUILD_DMS" = "true" ]; then
|
||||
STABLE_VER=$(grep -E '^version=' srcpkgs/dms/template | cut -d= -f2 | tr -d '"')
|
||||
STABLE_REV=$(grep -E '^revision=' srcpkgs/dms/template | cut -d= -f2 | tr -d '"')
|
||||
|
||||
EXPECTED_DMS_FILE="dms-${STABLE_VER}_${STABLE_REV}.x86_64.xbps"
|
||||
if [ -f "../gh-pages-repo/current/$EXPECTED_DMS_FILE" ] && [ "$FORCE_REBUILD" != "true" ]; then
|
||||
echo "✅ $EXPECTED_DMS_FILE already exists, skipping build."
|
||||
else
|
||||
echo "🔨 Compiling dms ($STABLE_VER)..."
|
||||
./xbps-src pkg dms
|
||||
rm -f "../gh-pages-repo/current/${EXPECTED_DMS_FILE}"
|
||||
cp -L hostdir/binpkgs/dms-${STABLE_VER}_${STABLE_REV}.x86_64.xbps ../gh-pages-repo/current/
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Build stable dms-greeter package
|
||||
if [ "$BUILD_GREETER" = "true" ]; then
|
||||
GREETER_VER=$(grep -E '^version=' srcpkgs/dms-greeter/template | cut -d= -f2 | tr -d '"')
|
||||
GREETER_REV=$(grep -E '^revision=' srcpkgs/dms-greeter/template | cut -d= -f2 | tr -d '"')
|
||||
|
||||
EXPECTED_GREETER_FILE="dms-greeter-${GREETER_VER}_${GREETER_REV}.x86_64.xbps"
|
||||
if [ -f "../gh-pages-repo/current/$EXPECTED_GREETER_FILE" ] && [ "$FORCE_REBUILD" != "true" ]; then
|
||||
echo "✅ $EXPECTED_GREETER_FILE already exists, skipping build."
|
||||
else
|
||||
echo "🔨 Compiling dms-greeter ($GREETER_VER)..."
|
||||
./xbps-src pkg dms-greeter
|
||||
rm -f "../gh-pages-repo/current/${EXPECTED_GREETER_FILE}"
|
||||
cp -L hostdir/binpkgs/dms-greeter-${GREETER_VER}_${GREETER_REV}.x86_64.xbps ../gh-pages-repo/current/
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Index and sign repository
|
||||
run: |
|
||||
cd gh-pages-repo/current
|
||||
|
||||
# Clean up any stale or dangling signature files to prevent O_CREAT ENOENT errors
|
||||
rm -f *.sig2 *.sig
|
||||
|
||||
# Guard: nothing to index if no .xbps files exist
|
||||
if ! ls *.xbps 1>/dev/null 2>&1; then
|
||||
echo "⚠️ No .xbps files found to index, skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Regenerate repo index
|
||||
xbps-rindex -a $(pwd)/*.xbps
|
||||
|
||||
# Sign repository
|
||||
echo "${{ secrets.XBPS_PRIVATE_KEY }}" > /tmp/xbps_privkey.pem
|
||||
chmod 600 /tmp/xbps_privkey.pem
|
||||
|
||||
xbps-rindex --sign --signedby "AvengeMedia <AvengeMedia.US@gmail.com>" --privkey /tmp/xbps_privkey.pem $(pwd)
|
||||
xbps-rindex --sign-pkg --privkey /tmp/xbps_privkey.pem $(pwd)/*.xbps
|
||||
|
||||
rm -f /tmp/xbps_privkey.pem
|
||||
|
||||
- name: Deploy to gh-pages branch
|
||||
run: |
|
||||
cd gh-pages-repo
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add current/
|
||||
git diff --quiet && git diff --staged --quiet || (git commit -m "Update XBPS packages [skip ci]" && git push origin gh-pages)
|
||||
@@ -110,9 +110,6 @@ bin/
|
||||
# Core dumps
|
||||
core.*
|
||||
|
||||
# prek-installed local git hooks (generated from .pre-commit-config.yaml)
|
||||
.githooks/
|
||||
|
||||
# direnv
|
||||
.envrc
|
||||
.direnv/
|
||||
|
||||
@@ -37,11 +37,9 @@ var resolveIncludeCmd = &cobra.Command{
|
||||
"cursor.lua",
|
||||
"windowrules.lua",
|
||||
"cursor.kdl",
|
||||
"layout.kdl",
|
||||
"outputs.kdl",
|
||||
"binds.kdl",
|
||||
"cursor.conf",
|
||||
"layout.conf",
|
||||
"outputs.conf",
|
||||
"binds.conf",
|
||||
}, cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
@@ -32,14 +32,13 @@ var greeterCmd = &cobra.Command{
|
||||
var (
|
||||
greeterConfigSyncFn = greeter.SyncDMSConfigs
|
||||
sharedAuthSyncFn = sharedpam.SyncAuthConfig
|
||||
greeterIsNixOSFn = greeter.IsNixOS
|
||||
)
|
||||
|
||||
var greeterInstallCmd = &cobra.Command{
|
||||
Use: "install",
|
||||
Short: "Install and configure DMS greeter",
|
||||
Long: "Install greetd and configure it to use DMS as the greeter interface",
|
||||
PreRunE: preRunGreeterMutation,
|
||||
PreRunE: preRunPrivileged,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
yes, _ := cmd.Flags().GetBool("yes")
|
||||
term, _ := cmd.Flags().GetBool("terminal")
|
||||
@@ -65,9 +64,6 @@ var greeterSyncCmd = &cobra.Command{
|
||||
Short: "Sync DMS theme and settings with greeter",
|
||||
Long: "Synchronize your current user's DMS theme, settings, and wallpaper configuration with the login greeter screen. Also updates a per-user cache slot at users/<username>/ for multi-account greeter theme preview.\n\nUse --profile on secondary accounts to sync only your own users/<username>/ slot without sudo or greetd changes.",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := rejectNixOSGreeterMutation(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
profile, _ := cmd.Flags().GetBool("profile")
|
||||
if profile {
|
||||
return nil
|
||||
@@ -144,7 +140,7 @@ var greeterEnableCmd = &cobra.Command{
|
||||
Use: "enable",
|
||||
Short: "Enable DMS greeter in greetd config",
|
||||
Long: "Configure greetd to use DMS as the greeter",
|
||||
PreRunE: preRunGreeterMutation,
|
||||
PreRunE: preRunPrivileged,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
yes, _ := cmd.Flags().GetBool("yes")
|
||||
term, _ := cmd.Flags().GetBool("terminal")
|
||||
@@ -180,7 +176,7 @@ var greeterUninstallCmd = &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Short: "Remove DMS greeter configuration and restore previous display manager",
|
||||
Long: "Disable greetd, remove DMS managed configs, and restore the system to its pre-DMS-greeter state",
|
||||
PreRunE: preRunGreeterMutation,
|
||||
PreRunE: preRunPrivileged,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
yes, _ := cmd.Flags().GetBool("yes")
|
||||
term, _ := cmd.Flags().GetBool("terminal")
|
||||
@@ -210,21 +206,6 @@ func init() {
|
||||
greeterUninstallCmd.Flags().BoolP("terminal", "t", false, "Run in a new terminal (for entering sudo password)")
|
||||
}
|
||||
|
||||
func rejectNixOSGreeterMutation(cmd *cobra.Command) error {
|
||||
if !greeterIsNixOSFn() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("dms %s is disabled on NixOS because the greeter is managed declaratively\nConfigure the DMS greeter in your NixOS module, then apply the change with your normal nixos-rebuild workflow", normalizeCommandSpec(cmd.CommandPath()))
|
||||
}
|
||||
|
||||
func preRunGreeterMutation(cmd *cobra.Command, args []string) error {
|
||||
if err := rejectNixOSGreeterMutation(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
return preRunPrivileged(cmd, args)
|
||||
}
|
||||
|
||||
func syncGreeterConfigsAndAuth(dmsPath, compositor string, logFunc func(string), options sharedpam.SyncAuthOptions, beforeAuth func()) error {
|
||||
if err := greeterConfigSyncFn(dmsPath, compositor, logFunc, ""); err != nil {
|
||||
return err
|
||||
@@ -1434,36 +1415,24 @@ func readDefaultSessionCommand(configPath string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func explicitGreeterCacheDirFromCommand(command string) (string, bool) {
|
||||
func extractGreeterCacheDirFromCommand(command string) string {
|
||||
if command == "" {
|
||||
return greeter.GreeterCacheDir
|
||||
}
|
||||
tokens := strings.Fields(command)
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
token := strings.Trim(tokens[i], "\"")
|
||||
if token == "--cache-dir" && i+1 < len(tokens) {
|
||||
value := strings.Trim(tokens[i+1], "\"")
|
||||
if value != "" {
|
||||
return value, true
|
||||
}
|
||||
return strings.Trim(tokens[i+1], "\"")
|
||||
}
|
||||
if strings.HasPrefix(token, "--cache-dir=") {
|
||||
value := strings.TrimPrefix(token, "--cache-dir=")
|
||||
value = strings.Trim(value, "\"")
|
||||
if value != "" {
|
||||
return value, true
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
const nixOSGreeterStateDir = "/var/lib/dms-greeter"
|
||||
|
||||
func greeterStatusStateDir(command string, isNixOS bool) string {
|
||||
if cacheDir, ok := explicitGreeterCacheDirFromCommand(command); ok {
|
||||
return cacheDir
|
||||
}
|
||||
if isNixOS {
|
||||
return nixOSGreeterStateDir
|
||||
}
|
||||
return greeter.GreeterCacheDir
|
||||
}
|
||||
|
||||
@@ -1600,10 +1569,6 @@ func checkGreeterStatus() error {
|
||||
fmt.Println("=== DMS Greeter Status ===")
|
||||
fmt.Println()
|
||||
|
||||
if greeterIsNixOSFn() {
|
||||
return checkNixOSGreeterStatus()
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get user home directory: %w", err)
|
||||
@@ -1667,7 +1632,7 @@ func checkGreeterStatus() error {
|
||||
fmt.Println(" Run 'dms greeter sync' to set up group membership and permissions")
|
||||
}
|
||||
|
||||
cacheDir := greeterStatusStateDir(configuredCommand, false)
|
||||
cacheDir := extractGreeterCacheDirFromCommand(configuredCommand)
|
||||
fmt.Println("\nGreeter Cache Directory:")
|
||||
fmt.Printf(" Effective cache dir: %s\n", cacheDir)
|
||||
if cacheDir != greeter.GreeterCacheDir {
|
||||
@@ -1930,85 +1895,6 @@ func checkGreeterStatus() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkNixOSGreeterStatus() error {
|
||||
const configPath = "/etc/greetd/config.toml"
|
||||
|
||||
configuredCommand := readDefaultSessionCommand(configPath)
|
||||
allGood := true
|
||||
|
||||
fmt.Println("Greeter Configuration:")
|
||||
switch {
|
||||
case strings.Contains(configuredCommand, "dms-greeter"):
|
||||
fmt.Println(" ✓ DMS greeter command found")
|
||||
if wrapper := extractGreeterWrapperFromCommand(configuredCommand); wrapper != "" {
|
||||
fmt.Printf(" Wrapper: %s\n", wrapper)
|
||||
}
|
||||
case configuredCommand != "":
|
||||
fmt.Println(" ⚠ greetd default session does not reference dms-greeter")
|
||||
allGood = false
|
||||
default:
|
||||
fmt.Printf(" ℹ No readable DMS command found in %s\n", configPath)
|
||||
}
|
||||
fmt.Println(" ℹ NixOS manages greeter configuration declaratively; apply changes through your NixOS module.")
|
||||
|
||||
stateDir := greeterStatusStateDir(configuredCommand, true)
|
||||
fmt.Println("\nGreeter State Directory:")
|
||||
fmt.Printf(" Effective state dir: %s\n", stateDir)
|
||||
if stateDir == nixOSGreeterStateDir {
|
||||
fmt.Println(" ✓ Using the NixOS module state path")
|
||||
}
|
||||
if stat, err := os.Stat(stateDir); err == nil && stat.IsDir() {
|
||||
fmt.Printf(" ✓ %s exists\n", stateDir)
|
||||
} else if os.IsNotExist(err) {
|
||||
fmt.Printf(" ✗ %s not found\n", stateDir)
|
||||
fmt.Println(" Rebuild your NixOS configuration after enabling the DMS greeter module.")
|
||||
allGood = false
|
||||
} else if err != nil {
|
||||
fmt.Printf(" ✗ Could not inspect %s: %v\n", stateDir, err)
|
||||
allGood = false
|
||||
} else {
|
||||
fmt.Printf(" ✗ %s is not a directory\n", stateDir)
|
||||
allGood = false
|
||||
}
|
||||
|
||||
fmt.Println("\nDeclarative Configuration Files:")
|
||||
configFiles := []struct {
|
||||
name string
|
||||
path string
|
||||
}{
|
||||
{name: "Settings", path: filepath.Join(stateDir, "settings.json")},
|
||||
{name: "Session state", path: filepath.Join(stateDir, "session.json")},
|
||||
{name: "Color theme", path: filepath.Join(stateDir, "colors.json")},
|
||||
}
|
||||
for _, configFile := range configFiles {
|
||||
if stat, err := os.Stat(configFile.path); err == nil && !stat.IsDir() {
|
||||
fmt.Printf(" ✓ %s: %s\n", configFile.name, configFile.path)
|
||||
} else if os.IsNotExist(err) {
|
||||
fmt.Printf(" ℹ %s not present (optional; configure configHome/configFiles in the NixOS module)\n", configFile.name)
|
||||
} else if err != nil {
|
||||
fmt.Printf(" ⚠ %s could not be inspected: %v\n", configFile.name, err)
|
||||
} else {
|
||||
fmt.Printf(" ⚠ %s path is not a regular file: %s\n", configFile.name, configFile.path)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("\nGroup Membership:")
|
||||
fmt.Println(" ℹ User group membership is managed by NixOS and is not required for declarative theme copies.")
|
||||
|
||||
fmt.Println("\nGreeter PAM Authentication:")
|
||||
fmt.Println(" ℹ PAM is managed by NixOS modules.")
|
||||
fmt.Println(" Configure fingerprint/U2F through security.pam.services.greetd.")
|
||||
|
||||
fmt.Println()
|
||||
if allGood {
|
||||
fmt.Println("✓ NixOS greeter state looks healthy and is managed declaratively.")
|
||||
} else {
|
||||
fmt.Println("⚠ Some issues detected. Update the DMS greeter module and rebuild NixOS; do not run 'dms greeter sync'.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func recentAppArmorGreeterDenials(sampleLimit int) (int, []string, error) {
|
||||
if sampleLimit <= 0 {
|
||||
sampleLimit = 3
|
||||
|
||||
@@ -3,11 +3,9 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
sharedpam "github.com/AvengeMedia/DankMaterialShell/core/internal/pam"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func TestSyncGreeterConfigsAndAuthDelegatesSharedAuth(t *testing.T) {
|
||||
@@ -87,57 +85,3 @@ func TestSyncGreeterConfigsAndAuthStopsOnConfigError(t *testing.T) {
|
||||
t.Fatal("expected auth sync not to run after config sync failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreeterStatusStateDirUsesNixOSDefault(t *testing.T) {
|
||||
if got := greeterStatusStateDir("", true); got != nixOSGreeterStateDir {
|
||||
t.Fatalf("greeterStatusStateDir() = %q, want %q", got, nixOSGreeterStateDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreeterStatusStateDirHonorsExplicitOverrideOnNixOS(t *testing.T) {
|
||||
command := "dms-greeter --cache-dir /srv/dms-greeter --command niri"
|
||||
if got := greeterStatusStateDir(command, true); got != "/srv/dms-greeter" {
|
||||
t.Fatalf("greeterStatusStateDir() = %q, want %q", got, "/srv/dms-greeter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectNixOSGreeterMutationBlocksImperativeCommands(t *testing.T) {
|
||||
origGreeterIsNixOSFn := greeterIsNixOSFn
|
||||
greeterIsNixOSFn = func() bool { return true }
|
||||
t.Cleanup(func() {
|
||||
greeterIsNixOSFn = origGreeterIsNixOSFn
|
||||
})
|
||||
|
||||
for _, commandName := range []string{"install", "enable", "sync", "uninstall"} {
|
||||
t.Run(commandName, func(t *testing.T) {
|
||||
root := &cobra.Command{Use: "dms"}
|
||||
greeterCommand := &cobra.Command{Use: "greeter"}
|
||||
mutationCommand := &cobra.Command{Use: commandName}
|
||||
root.AddCommand(greeterCommand)
|
||||
greeterCommand.AddCommand(mutationCommand)
|
||||
|
||||
err := rejectNixOSGreeterMutation(mutationCommand)
|
||||
if err == nil {
|
||||
t.Fatalf("expected NixOS greeter %s to be rejected", commandName)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "dms greeter "+commandName+" is disabled on NixOS") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if strings.Contains(err.Error(), "/var/cache/dms-greeter") {
|
||||
t.Fatalf("NixOS remediation should not recommend the non-NixOS cache path: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectNixOSGreeterMutationAllowsOtherDistros(t *testing.T) {
|
||||
origGreeterIsNixOSFn := greeterIsNixOSFn
|
||||
greeterIsNixOSFn = func() bool { return false }
|
||||
t.Cleanup(func() {
|
||||
greeterIsNixOSFn = origGreeterIsNixOSFn
|
||||
})
|
||||
|
||||
if err := rejectNixOSGreeterMutation(&cobra.Command{Use: "sync"}); err != nil {
|
||||
t.Fatalf("expected non-NixOS greeter command to be allowed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultImmutablePolicyAllowsSyncButBlocksEnable(t *testing.T) {
|
||||
var policyFile cliPolicyFile
|
||||
if err := json.Unmarshal(defaultCLIPolicyJSON, &policyFile); err != nil {
|
||||
t.Fatalf("failed to parse embedded CLI policy: %v", err)
|
||||
}
|
||||
if policyFile.BlockedCommands == nil {
|
||||
t.Fatal("embedded CLI policy has no blocked_commands")
|
||||
}
|
||||
|
||||
blocked := normalizeBlockedCommands(*policyFile.BlockedCommands)
|
||||
if !commandBlockedByPolicy("greeter enable", blocked) {
|
||||
t.Fatal("expected greeter enable to remain blocked on immutable/image-based systems")
|
||||
}
|
||||
if commandBlockedByPolicy("greeter sync", blocked) {
|
||||
t.Fatal("expected greeter sync to remain available on immutable/image-based systems")
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ hl.config({
|
||||
input = {
|
||||
kb_layout = "us",
|
||||
numlock_by_default = true,
|
||||
follow_mouse = 0,
|
||||
touchpad = {
|
||||
tap_to_click = true,
|
||||
natural_scroll = true,
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/tailscale"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/thememode"
|
||||
serverThemes "github.com/AvengeMedia/DankMaterialShell/core/internal/server/themes"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wallpaper"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlroutput"
|
||||
)
|
||||
@@ -57,15 +56,6 @@ func RouteRequest(conn net.Conn, req models.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(req.Method, "wallpaper.") {
|
||||
if wallpaperManager == nil {
|
||||
models.RespondError(conn, req.ID, "wallpaper manager not initialized")
|
||||
return
|
||||
}
|
||||
wallpaper.HandleRequest(conn, req, wallpaperManager)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(req.Method, "loginctl.") {
|
||||
if loginctlManager == nil {
|
||||
models.RespondError(conn, req.ID, "loginctl manager not initialized")
|
||||
|
||||
@@ -33,14 +33,13 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/tailscale"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/thememode"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/trayrecovery"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wallpaper"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlroutput"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
|
||||
)
|
||||
|
||||
const APIVersion = 27
|
||||
const APIVersion = 26
|
||||
|
||||
var CLIVersion = "dev"
|
||||
|
||||
@@ -74,7 +73,6 @@ var clipboardManager *clipboard.Manager
|
||||
var dbusManager *serverDbus.Manager
|
||||
var wlContext *wlcontext.SharedContext
|
||||
var themeModeManager *thememode.Manager
|
||||
var wallpaperManager *wallpaper.Manager
|
||||
var trayRecoveryManager *trayrecovery.Manager
|
||||
var locationManager *location.Manager
|
||||
var sysUpdateManager *sysupdate.Manager
|
||||
@@ -349,13 +347,6 @@ func InitializeThemeModeManager() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitializeWallpaperManager() error {
|
||||
wallpaperManager = wallpaper.NewManager()
|
||||
|
||||
log.Info("Wallpaper rotation scheduler initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitializeTrayRecoveryManager() error {
|
||||
manager, err := trayrecovery.NewManager()
|
||||
if err != nil {
|
||||
@@ -472,10 +463,6 @@ func getCapabilities() Capabilities {
|
||||
caps = append(caps, "theme.auto")
|
||||
}
|
||||
|
||||
if wallpaperManager != nil {
|
||||
caps = append(caps, "wallpaper")
|
||||
}
|
||||
|
||||
if dbusManager != nil {
|
||||
caps = append(caps, "dbus")
|
||||
}
|
||||
@@ -542,10 +529,6 @@ func getServerInfo() ServerInfo {
|
||||
caps = append(caps, "theme.auto")
|
||||
}
|
||||
|
||||
if wallpaperManager != nil {
|
||||
caps = append(caps, "wallpaper")
|
||||
}
|
||||
|
||||
if locationManager != nil {
|
||||
caps = append(caps, "location")
|
||||
}
|
||||
@@ -858,38 +841,6 @@ func handleSubscribe(conn net.Conn, req models.Request) {
|
||||
}()
|
||||
}
|
||||
|
||||
if shouldSubscribe("wallpaper") && wallpaperManager != nil {
|
||||
wg.Add(1)
|
||||
wallpaperChan := wallpaperManager.Subscribe(clientID + "-wallpaper")
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer wallpaperManager.Unsubscribe(clientID + "-wallpaper")
|
||||
|
||||
initialState := wallpaperManager.GetState()
|
||||
select {
|
||||
case eventChan <- ServiceEvent{Service: "wallpaper", Data: initialState}:
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case state, ok := <-wallpaperChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case eventChan <- ServiceEvent{Service: "wallpaper", Data: state}:
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if shouldSubscribe("bluetooth") && bluezManager != nil {
|
||||
wg.Add(1)
|
||||
bluezChan := bluezManager.Subscribe(clientID + "-bluetooth")
|
||||
@@ -1335,9 +1286,6 @@ func cleanupManagers() {
|
||||
if themeModeManager != nil {
|
||||
themeModeManager.Close()
|
||||
}
|
||||
if wallpaperManager != nil {
|
||||
wallpaperManager.Close()
|
||||
}
|
||||
if trayRecoveryManager != nil {
|
||||
trayRecoveryManager.Close()
|
||||
}
|
||||
@@ -1630,19 +1578,6 @@ func Start(printDocs bool) error {
|
||||
}()
|
||||
}
|
||||
|
||||
if err := InitializeWallpaperManager(); err != nil {
|
||||
log.Warnf("Wallpaper scheduler unavailable: %v", err)
|
||||
} else {
|
||||
notifyCapabilityChange()
|
||||
go func() {
|
||||
<-loginctlReady
|
||||
if loginctlManager == nil {
|
||||
return
|
||||
}
|
||||
wallpaperManager.WatchLoginctl(loginctlManager)
|
||||
}()
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-loginctlReady
|
||||
if loginctlManager == nil {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package wallpaper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/params"
|
||||
)
|
||||
|
||||
func HandleRequest(conn net.Conn, req models.Request, manager *Manager) {
|
||||
if manager == nil {
|
||||
models.RespondError(conn, req.ID, "wallpaper manager not initialized")
|
||||
return
|
||||
}
|
||||
|
||||
switch req.Method {
|
||||
case "wallpaper.getState":
|
||||
handleGetState(conn, req, manager)
|
||||
case "wallpaper.setConfig":
|
||||
handleSetConfig(conn, req, manager)
|
||||
case "wallpaper.trigger":
|
||||
handleTrigger(conn, req, manager)
|
||||
case "wallpaper.subscribe":
|
||||
handleSubscribe(conn, req, manager)
|
||||
default:
|
||||
models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
|
||||
}
|
||||
}
|
||||
|
||||
func handleGetState(conn net.Conn, req models.Request, manager *Manager) {
|
||||
models.Respond(conn, req.ID, manager.GetState())
|
||||
}
|
||||
|
||||
func handleSetConfig(conn net.Conn, req models.Request, manager *Manager) {
|
||||
raw, ok := params.Any(req.Params, "config")
|
||||
if !ok {
|
||||
models.RespondError(conn, req.ID, "missing or invalid 'config' parameter")
|
||||
return
|
||||
}
|
||||
|
||||
data, err := json.Marshal(raw)
|
||||
if err != nil {
|
||||
models.RespondError(conn, req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
models.RespondError(conn, req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
manager.SetConfig(config)
|
||||
models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "wallpaper schedule set"})
|
||||
}
|
||||
|
||||
func handleTrigger(conn net.Conn, req models.Request, manager *Manager) {
|
||||
manager.ResetSchedule(params.StringOpt(req.Params, "target", ""))
|
||||
models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "wallpaper schedule reset"})
|
||||
}
|
||||
|
||||
func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) {
|
||||
clientID := fmt.Sprintf("client-%p", conn)
|
||||
stateChan := manager.Subscribe(clientID)
|
||||
defer manager.Unsubscribe(clientID)
|
||||
|
||||
initialState := manager.GetState()
|
||||
if err := json.NewEncoder(conn).Encode(models.Response[State]{
|
||||
ID: req.ID,
|
||||
Result: &initialState,
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for state := range stateChan {
|
||||
if err := json.NewEncoder(conn).Encode(models.Response[State]{
|
||||
Result: &state,
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,325 +0,0 @@
|
||||
package wallpaper
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
|
||||
)
|
||||
|
||||
type activeSchedule struct {
|
||||
cfg ScheduleConfig
|
||||
nextFire time.Time
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
config Config
|
||||
configMutex sync.RWMutex
|
||||
|
||||
state *State
|
||||
stateMutex sync.RWMutex
|
||||
|
||||
subscribers syncmap.Map[string, chan State]
|
||||
|
||||
stopChan chan struct{}
|
||||
updateTrigger chan struct{}
|
||||
resetReq chan string
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
m := &Manager{
|
||||
config: Config{
|
||||
Global: ScheduleConfig{Mode: "interval", IntervalSec: 300, Time: "06:00"},
|
||||
Monitors: map[string]ScheduleConfig{},
|
||||
},
|
||||
stopChan: make(chan struct{}),
|
||||
updateTrigger: make(chan struct{}, 1),
|
||||
resetReq: make(chan string, 8),
|
||||
}
|
||||
m.state = &State{Config: m.getConfig()}
|
||||
|
||||
m.wg.Add(1)
|
||||
go m.schedulerLoop()
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Manager) GetState() State {
|
||||
m.stateMutex.RLock()
|
||||
defer m.stateMutex.RUnlock()
|
||||
if m.state == nil {
|
||||
return State{Config: m.getConfig()}
|
||||
}
|
||||
return *m.state
|
||||
}
|
||||
|
||||
func (m *Manager) Subscribe(id string) chan State {
|
||||
ch := make(chan State, 64)
|
||||
m.subscribers.Store(id, ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func (m *Manager) Unsubscribe(id string) {
|
||||
if val, ok := m.subscribers.LoadAndDelete(id); ok {
|
||||
close(val)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) SetConfig(config Config) {
|
||||
if config.Monitors == nil {
|
||||
config.Monitors = map[string]ScheduleConfig{}
|
||||
}
|
||||
m.configMutex.Lock()
|
||||
if reflect.DeepEqual(m.config, config) {
|
||||
m.configMutex.Unlock()
|
||||
return
|
||||
}
|
||||
m.config = config
|
||||
m.configMutex.Unlock()
|
||||
m.TriggerUpdate()
|
||||
}
|
||||
|
||||
func (m *Manager) ResetSchedule(target string) {
|
||||
select {
|
||||
case m.resetReq <- target:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) TriggerUpdate() {
|
||||
select {
|
||||
case m.updateTrigger <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Close() {
|
||||
select {
|
||||
case <-m.stopChan:
|
||||
return
|
||||
default:
|
||||
close(m.stopChan)
|
||||
}
|
||||
m.wg.Wait()
|
||||
m.subscribers.Range(func(key string, ch chan State) bool {
|
||||
close(ch)
|
||||
m.subscribers.Delete(key)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Manager) WatchLoginctl(lm *loginctl.Manager) {
|
||||
ch := lm.Subscribe("wallpaper")
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
defer lm.Unsubscribe("wallpaper")
|
||||
for {
|
||||
select {
|
||||
case <-m.stopChan:
|
||||
return
|
||||
case state, ok := <-ch:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if state.PreparingForSleep {
|
||||
continue
|
||||
}
|
||||
m.TriggerUpdate()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *Manager) schedulerLoop() {
|
||||
defer m.wg.Done()
|
||||
|
||||
schedules := map[string]*activeSchedule{}
|
||||
resets := map[string]bool{}
|
||||
var seq uint64
|
||||
var timer *time.Timer
|
||||
|
||||
for {
|
||||
now := time.Now()
|
||||
config := m.getConfig()
|
||||
active := activeSchedules(config)
|
||||
|
||||
for key := range schedules {
|
||||
if _, ok := active[key]; !ok {
|
||||
delete(schedules, key)
|
||||
}
|
||||
}
|
||||
for key, cfg := range active {
|
||||
s, ok := schedules[key]
|
||||
switch {
|
||||
case !ok:
|
||||
schedules[key] = &activeSchedule{cfg: cfg, nextFire: computeNext(now, cfg)}
|
||||
case s.cfg != cfg || resets[key]:
|
||||
s.cfg = cfg
|
||||
s.nextFire = computeNext(now, cfg)
|
||||
}
|
||||
delete(resets, key)
|
||||
}
|
||||
|
||||
var dueKeys []string
|
||||
for key, s := range schedules {
|
||||
if !s.nextFire.After(now) {
|
||||
dueKeys = append(dueKeys, key)
|
||||
s.nextFire = computeNext(now, s.cfg)
|
||||
}
|
||||
}
|
||||
|
||||
next, hasNext := soonest(schedules)
|
||||
if len(dueKeys) == 0 {
|
||||
m.setState(config, next, seq, "")
|
||||
}
|
||||
for _, key := range dueKeys {
|
||||
seq++
|
||||
m.setState(config, next, seq, key)
|
||||
}
|
||||
|
||||
waitDur := 24 * time.Hour
|
||||
if hasNext {
|
||||
waitDur = time.Until(next)
|
||||
if waitDur < time.Second {
|
||||
waitDur = time.Second
|
||||
}
|
||||
}
|
||||
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
timer = time.NewTimer(waitDur)
|
||||
|
||||
select {
|
||||
case <-m.stopChan:
|
||||
timer.Stop()
|
||||
return
|
||||
case <-m.updateTrigger:
|
||||
timer.Stop()
|
||||
case key := <-m.resetReq:
|
||||
timer.Stop()
|
||||
resets[key] = true
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) setState(config Config, next time.Time, seq uint64, target string) {
|
||||
newState := State{Config: config, NextRotation: next, CycleSeq: seq, Target: target}
|
||||
|
||||
m.stateMutex.Lock()
|
||||
if m.state != nil && statesEqual(m.state, &newState) {
|
||||
m.stateMutex.Unlock()
|
||||
return
|
||||
}
|
||||
m.state = &newState
|
||||
m.stateMutex.Unlock()
|
||||
|
||||
m.notifySubscribers()
|
||||
}
|
||||
|
||||
func (m *Manager) notifySubscribers() {
|
||||
state := m.GetState()
|
||||
m.subscribers.Range(func(key string, ch chan State) bool {
|
||||
select {
|
||||
case ch <- state:
|
||||
default:
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Manager) getConfig() Config {
|
||||
m.configMutex.RLock()
|
||||
defer m.configMutex.RUnlock()
|
||||
return m.config
|
||||
}
|
||||
|
||||
func activeSchedules(config Config) map[string]ScheduleConfig {
|
||||
out := map[string]ScheduleConfig{}
|
||||
if config.PerMonitor {
|
||||
for name, cfg := range config.Monitors {
|
||||
if cfg.Enabled {
|
||||
out[name] = cfg
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
if config.Global.Enabled {
|
||||
out[""] = config.Global
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func computeNext(now time.Time, cfg ScheduleConfig) time.Time {
|
||||
switch cfg.Mode {
|
||||
case "time":
|
||||
return nextDailyTime(now, cfg.Time)
|
||||
default:
|
||||
sec := cfg.IntervalSec
|
||||
if sec < 1 {
|
||||
sec = 1
|
||||
}
|
||||
return now.Add(time.Duration(sec) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func nextDailyTime(now time.Time, hhmm string) time.Time {
|
||||
hour, minute, ok := parseHHMM(hhmm)
|
||||
if !ok {
|
||||
return now.Add(24 * time.Hour)
|
||||
}
|
||||
next := time.Date(now.Year(), now.Month(), now.Day(), hour, minute, 0, 0, now.Location())
|
||||
if !next.After(now) {
|
||||
next = next.Add(24 * time.Hour)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
func parseHHMM(hhmm string) (int, int, bool) {
|
||||
parts := strings.Split(hhmm, ":")
|
||||
if len(parts) != 2 {
|
||||
return 0, 0, false
|
||||
}
|
||||
hour, err := strconv.Atoi(parts[0])
|
||||
if err != nil || hour < 0 || hour > 23 {
|
||||
return 0, 0, false
|
||||
}
|
||||
minute, err := strconv.Atoi(parts[1])
|
||||
if err != nil || minute < 0 || minute > 59 {
|
||||
return 0, 0, false
|
||||
}
|
||||
return hour, minute, true
|
||||
}
|
||||
|
||||
func soonest(schedules map[string]*activeSchedule) (time.Time, bool) {
|
||||
var best time.Time
|
||||
found := false
|
||||
for _, s := range schedules {
|
||||
if !found || s.nextFire.Before(best) {
|
||||
best = s.nextFire
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return best, found
|
||||
}
|
||||
|
||||
func statesEqual(a, b *State) bool {
|
||||
switch {
|
||||
case a == nil || b == nil:
|
||||
return a == b
|
||||
case a.CycleSeq != b.CycleSeq:
|
||||
return false
|
||||
case a.Target != b.Target:
|
||||
return false
|
||||
case !a.NextRotation.Equal(b.NextRotation):
|
||||
return false
|
||||
}
|
||||
return reflect.DeepEqual(a.Config, b.Config)
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package wallpaper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseHHMM(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
hour int
|
||||
minute int
|
||||
ok bool
|
||||
}{
|
||||
{"06:00", 6, 0, true},
|
||||
{"23:59", 23, 59, true},
|
||||
{"00:00", 0, 0, true},
|
||||
{"24:00", 0, 0, false},
|
||||
{"6:5", 6, 5, true},
|
||||
{"bad", 0, 0, false},
|
||||
{"12", 0, 0, false},
|
||||
{"12:60", 0, 0, false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
hour, minute, ok := parseHHMM(c.in)
|
||||
if ok != c.ok || (ok && (hour != c.hour || minute != c.minute)) {
|
||||
t.Errorf("parseHHMM(%q) = (%d, %d, %v), want (%d, %d, %v)", c.in, hour, minute, ok, c.hour, c.minute, c.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeNextInterval(t *testing.T) {
|
||||
now := time.Date(2026, 6, 30, 12, 0, 0, 0, time.UTC)
|
||||
got := computeNext(now, ScheduleConfig{Mode: "interval", IntervalSec: 300})
|
||||
if want := now.Add(300 * time.Second); !got.Equal(want) {
|
||||
t.Errorf("interval next = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
clamped := computeNext(now, ScheduleConfig{Mode: "interval", IntervalSec: 0})
|
||||
if want := now.Add(time.Second); !clamped.Equal(want) {
|
||||
t.Errorf("interval clamp = %v, want %v", clamped, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeNextTime(t *testing.T) {
|
||||
now := time.Date(2026, 6, 30, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
later := computeNext(now, ScheduleConfig{Mode: "time", Time: "18:00"})
|
||||
if want := time.Date(2026, 6, 30, 18, 0, 0, 0, time.UTC); !later.Equal(want) {
|
||||
t.Errorf("time next (today) = %v, want %v", later, want)
|
||||
}
|
||||
|
||||
tomorrow := computeNext(now, ScheduleConfig{Mode: "time", Time: "06:00"})
|
||||
if want := time.Date(2026, 7, 1, 6, 0, 0, 0, time.UTC); !tomorrow.Equal(want) {
|
||||
t.Errorf("time next (tomorrow) = %v, want %v", tomorrow, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveSchedules(t *testing.T) {
|
||||
global := activeSchedules(Config{
|
||||
Global: ScheduleConfig{Enabled: true, Mode: "interval", IntervalSec: 60},
|
||||
})
|
||||
if len(global) != 1 {
|
||||
t.Fatalf("global active = %d, want 1", len(global))
|
||||
}
|
||||
if _, ok := global[""]; !ok {
|
||||
t.Errorf("global active missing global key")
|
||||
}
|
||||
|
||||
perMonitor := activeSchedules(Config{
|
||||
PerMonitor: true,
|
||||
Global: ScheduleConfig{Enabled: true},
|
||||
Monitors: map[string]ScheduleConfig{
|
||||
"DP-1": {Enabled: true, Mode: "interval", IntervalSec: 60},
|
||||
"DP-2": {Enabled: false},
|
||||
},
|
||||
})
|
||||
if len(perMonitor) != 1 {
|
||||
t.Fatalf("per-monitor active = %d, want 1", len(perMonitor))
|
||||
}
|
||||
if _, ok := perMonitor["DP-1"]; !ok {
|
||||
t.Errorf("per-monitor active missing DP-1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchedulerEmitsCycle(t *testing.T) {
|
||||
m := NewManager()
|
||||
defer m.Close()
|
||||
|
||||
sub := m.Subscribe("test")
|
||||
defer m.Unsubscribe("test")
|
||||
|
||||
m.SetConfig(Config{Global: ScheduleConfig{Enabled: true, Mode: "interval", IntervalSec: 1}})
|
||||
|
||||
deadline := time.After(3 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case state := <-sub:
|
||||
if state.CycleSeq > 0 && state.Target == "" {
|
||||
return
|
||||
}
|
||||
case <-deadline:
|
||||
t.Fatal("scheduler did not emit a cycle event within 3s")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package wallpaper
|
||||
|
||||
import "time"
|
||||
|
||||
type ScheduleConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Mode string `json:"mode"`
|
||||
IntervalSec int `json:"intervalSec"`
|
||||
Time string `json:"time"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PerMonitor bool `json:"perMonitor"`
|
||||
Global ScheduleConfig `json:"global"`
|
||||
Monitors map[string]ScheduleConfig `json:"monitors"`
|
||||
}
|
||||
|
||||
type State struct {
|
||||
Config Config `json:"config"`
|
||||
NextRotation time.Time `json:"nextRotation"`
|
||||
CycleSeq uint64 `json:"cycleSeq"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
@@ -74,9 +74,6 @@ func NewManager(display wlclient.WaylandDisplay, config Config) (*Manager, error
|
||||
|
||||
if config.Enabled {
|
||||
m.post(func() {
|
||||
if m.controlsInitialized {
|
||||
return
|
||||
}
|
||||
log.Info("Gamma control enabled at startup")
|
||||
gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1)
|
||||
m.availOutputsMu.RLock()
|
||||
@@ -187,26 +184,13 @@ func (m *Manager) setupRegistry() error {
|
||||
enabled := m.config.Enabled
|
||||
m.configMutex.RUnlock()
|
||||
|
||||
if !enabled {
|
||||
return
|
||||
if enabled && m.controlsInitialized {
|
||||
m.post(func() {
|
||||
if err := m.addOutputControl(output); err != nil {
|
||||
log.Warnf("Failed to add output control: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
m.post(func() {
|
||||
if err := m.addOutputControl(output); err != nil {
|
||||
log.Warnf("gamma: failed to add output control: %v", err)
|
||||
return
|
||||
}
|
||||
if m.controlsInitialized {
|
||||
return
|
||||
}
|
||||
// All outputs had been torn down (monitor sleep/disconnect),
|
||||
// clearing controlsInitialized. Mark it ready again so the
|
||||
// gamma_size event that follows control creation drives the
|
||||
// reapply, instead of waiting for a manual toggle. No explicit
|
||||
// apply here: applyGamma's dedup would suppress a no-change
|
||||
// write anyway, and the new control isn't ready until gamma_size.
|
||||
log.Info("gamma: output returned, re-establishing controls")
|
||||
m.controlsInitialized = true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
+1
-48
@@ -10,8 +10,6 @@ let
|
||||
inherit (lib) types;
|
||||
cfg = config.programs.dank-material-shell.greeter;
|
||||
cfgDms = config.programs.dank-material-shell;
|
||||
cfgAutoLogin = config.services.displayManager.autoLogin;
|
||||
sessionData = config.services.displayManager.sessionData;
|
||||
|
||||
inherit (config.services.greetd.settings.default_session) user;
|
||||
|
||||
@@ -50,38 +48,6 @@ let
|
||||
} ${lib.optionalString cfg.logs.save "> ${cfg.logs.path} 2>&1"}
|
||||
'';
|
||||
|
||||
autoLoginCommand =
|
||||
pkgs.runCommand "dms-greeter-autologin-command"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
pkgs.gnugrep
|
||||
pkgs.coreutils
|
||||
];
|
||||
}
|
||||
''
|
||||
set -euo pipefail
|
||||
|
||||
session="${sessionData.autologinSession}"
|
||||
desktops="${sessionData.desktops}"
|
||||
|
||||
for sessionFile in \
|
||||
"$desktops/share/wayland-sessions/$session.desktop" \
|
||||
"$desktops/share/xsessions/$session.desktop"
|
||||
do
|
||||
if [ -f "$sessionFile" ]; then
|
||||
command="$(grep -m1 '^Exec=' "$sessionFile" | cut -d= -f2- || true)"
|
||||
|
||||
if [ -n "$command" ]; then
|
||||
printf '%s\n' "$command" > "$out"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "dms-greeter autologin: could not resolve Exec for session '$session'" >&2
|
||||
exit 1
|
||||
'';
|
||||
|
||||
jq = lib.getExe pkgs.jq;
|
||||
in
|
||||
{
|
||||
@@ -189,13 +155,6 @@ in
|
||||
dmsgreeter: user set for greetd default_session ${user} does not exist. Please create it before referencing it.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfgAutoLogin.enable -> sessionData.autologinSession != null;
|
||||
message = ''
|
||||
dms-greeter auto-login requires services.displayManager.defaultSession to be set,
|
||||
or at least one session in services.displayManager.sessionPackages.
|
||||
'';
|
||||
}
|
||||
];
|
||||
# DMS currently relies on /etc/pam.d/login for lock screen password auth on NixOS.
|
||||
# Declare security.pam.services.dankshell only if you want to override that runtime fallback.
|
||||
@@ -206,13 +165,7 @@ in
|
||||
# };
|
||||
services.greetd = {
|
||||
enable = lib.mkDefault true;
|
||||
settings = {
|
||||
default_session.command = lib.mkDefault (lib.getExe greeterScript);
|
||||
initial_session = lib.mkIf (cfgAutoLogin.enable && (cfgAutoLogin.user != null)) {
|
||||
inherit (cfgAutoLogin) user;
|
||||
command = ''${lib.getExe pkgs.bash} -lc "${pkgs.systemd}/bin/systemd-cat $(<${autoLoginCommand})"'';
|
||||
};
|
||||
};
|
||||
settings.default_session.command = lib.mkDefault (lib.getExe greeterScript);
|
||||
};
|
||||
fonts.packages = with pkgs; [
|
||||
fira-code
|
||||
|
||||
@@ -16,14 +16,8 @@ pkgs.testers.runNixOSTest {
|
||||
isSystemUser = true;
|
||||
group = "greeter";
|
||||
};
|
||||
users.users.alice.isNormalUser = true;
|
||||
|
||||
services.greetd.settings.default_session.user = "greeter";
|
||||
services.displayManager.autoLogin = {
|
||||
enable = true;
|
||||
user = "alice";
|
||||
};
|
||||
services.displayManager.defaultSession = "niri";
|
||||
|
||||
programs.niri.enable = true;
|
||||
|
||||
@@ -52,11 +46,6 @@ pkgs.testers.runNixOSTest {
|
||||
greetd_config_path = config_match.group(1)
|
||||
greetd_config = machine.succeed(f"cat {greetd_config_path}")
|
||||
t.assertIn("dms-greeter", greetd_config)
|
||||
t.assertIn("[initial_session]", greetd_config)
|
||||
|
||||
initial_session = greetd_config.split("[initial_session]", 1)[1]
|
||||
t.assertIn('user = "alice"', initial_session)
|
||||
t.assertIn("systemd-cat", initial_session)
|
||||
|
||||
script_match = re.search(r'command\s*=\s*"([^"]+/bin/dms-greeter)"', greetd_config)
|
||||
if script_match is None:
|
||||
|
||||
+8
-33
@@ -13,41 +13,16 @@ All build from source.
|
||||
|
||||
## Distribution
|
||||
|
||||
This is a DMS maintained repo for VoidLinux until these packages are officially merged upstream in the Void Linux repositories, you can install them from our self-hosted custom XBPS repositories served via GitHub Pages.
|
||||
|
||||
### Using the Self-Hosted Repositories
|
||||
|
||||
We serve both stable release and development packages directly from our repository branches.
|
||||
|
||||
#### 1. Add Repository Configurations
|
||||
|
||||
Create configuration files in `/etc/xbps.d/` pointing to our repositories (needed for both stable and git/nightly variants):
|
||||
|
||||
```sh
|
||||
echo "repository=https://avengemedia.github.io/DankMaterialShell/current" | sudo tee /etc/xbps.d/dms.conf
|
||||
echo "repository=https://avengemedia.github.io/DankLinux/current" | sudo tee /etc/xbps.d/danklinux.conf
|
||||
```
|
||||
|
||||
#### 2. Install DMS
|
||||
|
||||
Synchronize repositories and install the package:
|
||||
|
||||
* For the **stable** variant:
|
||||
|
||||
```sh
|
||||
sudo xbps-install -S dms
|
||||
```
|
||||
|
||||
* For the **git/nightly** variant (this will conflict with and replace the stable package):
|
||||
|
||||
```sh
|
||||
sudo xbps-install -S dms-git
|
||||
```
|
||||
|
||||
*Note: On the first sync, `xbps-install` will output our signing key fingerprint and ask you to type `y` to trust and import it. Verify that the key matches our official signing fingerprint.*
|
||||
These packages target the official
|
||||
[`void-linux/void-packages`](https://github.com/void-linux/void-packages)
|
||||
repository, so they install with a plain `xbps-install dms` and no extra setup.
|
||||
Most dependencies (`quickshell`, `matugen`, `cava`, `niri`, `greetd`, …) are
|
||||
already in Void; `dgop` and `danksearch` are packaged alongside in the
|
||||
[danklinux repo](https://github.com/AvengeMedia/danklinux/tree/master/distro/void).
|
||||
|
||||
The templates here are the source of truth: copy each into a void-packages
|
||||
checkout at `srcpkgs/<pkg>/template` to build or submit it.
|
||||
checkout at `srcpkgs/<pkg>/template` to build or submit it. Only tagged releases
|
||||
are packaged (no `-git`/nightly variant).
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# Template file for 'dms-git'
|
||||
#
|
||||
# DankMaterialShell git development release
|
||||
#
|
||||
# NOTE: This template is built exclusively by CI. The workflow stages a local
|
||||
# source tarball and dynamically patches version, checksum, and distfiles
|
||||
# before calling xbps-src. Do not attempt to build this template manually
|
||||
# without first providing the source archive.
|
||||
#
|
||||
# The binary is built with the `distro_binary` build tag (drops the in-app
|
||||
# self-update command).
|
||||
pkgname=dms-git
|
||||
version=1.4.6.git
|
||||
revision=1
|
||||
create_wrksrc=yes
|
||||
build_style=go
|
||||
build_wrksrc="core"
|
||||
go_import_path="github.com/AvengeMedia/DankMaterialShell/core"
|
||||
go_package="${go_import_path}/cmd/dms"
|
||||
go_build_tags="distro_binary"
|
||||
go_ldflags="-X main.Version=${version}"
|
||||
short_desc="DankMaterialShell — Material 3 desktop shell for Wayland (git variant)"
|
||||
maintainer="AvengeMedia <AvengeMedia.US@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://danklinux.com"
|
||||
# CI populates distfiles/checksum dynamically; these are placeholders.
|
||||
distfiles="https://github.com/AvengeMedia/DankMaterialShell/archive/refs/tags/v${version}.tar.gz"
|
||||
checksum=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb
|
||||
|
||||
# Conflicts and provides
|
||||
conflicts="dms"
|
||||
provides="dms-${version}_${revision}"
|
||||
|
||||
# Optional feature deps are listed in distro/void/README.md.
|
||||
depends="quickshell accountsservice dgop matugen dbus"
|
||||
|
||||
post_install() {
|
||||
# QML shell tree (build_style=go already installed the dms binary)
|
||||
vmkdir usr/share/quickshell/dms
|
||||
vcopy "${wrksrc}/quickshell/*" usr/share/quickshell/dms
|
||||
echo "${version}" > "${DESTDIR}/usr/share/quickshell/dms/VERSION"
|
||||
|
||||
# Desktop entry + icon
|
||||
vinstall "${wrksrc}/assets/dms-open.desktop" 644 usr/share/applications
|
||||
vinstall "${wrksrc}/assets/com.danklinux.dms.desktop" 644 usr/share/applications
|
||||
vinstall "${wrksrc}/assets/danklogo.svg" 644 usr/share/icons/hicolor/scalable/apps
|
||||
|
||||
# Shell completions (generated by the built binary; skip when cross-building)
|
||||
vmkdir usr/share/bash-completion/completions
|
||||
vmkdir usr/share/zsh/site-functions
|
||||
vmkdir usr/share/fish/vendor_completions.d
|
||||
if [ -z "$CROSS_BUILD" ]; then
|
||||
"${DESTDIR}/usr/bin/dms" completion bash > "${DESTDIR}/usr/share/bash-completion/completions/dms"
|
||||
"${DESTDIR}/usr/bin/dms" completion zsh > "${DESTDIR}/usr/share/zsh/site-functions/_dms"
|
||||
"${DESTDIR}/usr/bin/dms" completion fish > "${DESTDIR}/usr/share/fish/vendor_completions.d/dms.fish"
|
||||
fi
|
||||
|
||||
vlicense "${wrksrc}/LICENSE"
|
||||
}
|
||||
@@ -21,8 +21,8 @@ changelog="https://github.com/AvengeMedia/DankMaterialShell/releases"
|
||||
distfiles="https://github.com/AvengeMedia/DankMaterialShell/archive/refs/tags/v${version}.tar.gz"
|
||||
checksum=f54601e522c883fa9cce02bec070e4321e47389a1cf453e7ad0bb7379ad91b61
|
||||
|
||||
# Optional feature deps are listed in distro/void/README.md.
|
||||
depends="quickshell accountsservice dgop matugen dbus"
|
||||
# Optional feature deps (XBPS has no "recommends") are listed in distro/void/README.md.
|
||||
depends="quickshell accountsservice dgop matugen"
|
||||
|
||||
post_install() {
|
||||
# QML shell tree (build_style=go already installed the dms binary)
|
||||
|
||||
@@ -55,7 +55,7 @@ Singleton {
|
||||
|
||||
readonly property bool isDirectionalEffect: isConnectedEffect || _effect === 1
|
||||
readonly property bool isDepthEffect: _effect === 2
|
||||
readonly property bool isConnectedEffect: (typeof FrameTransitionState !== "undefined") && FrameTransitionState.effectiveConnectedFrameModeActive
|
||||
readonly property bool isConnectedEffect: (typeof SettingsData !== "undefined") && SettingsData.connectedFrameModeActive
|
||||
|
||||
readonly property real effectScaleCollapsed: _effectScaleCollapsed[_effect] !== undefined ? _effectScaleCollapsed[_effect] : 0.96
|
||||
readonly property real effectAnimOffset: _effectAnimOffsets[_effect] !== undefined ? _effectAnimOffsets[_effect] : 16
|
||||
|
||||
@@ -7,24 +7,6 @@ function dirname(path) {
|
||||
return idx > 0 ? path.substring(0, idx) : ".";
|
||||
}
|
||||
|
||||
function sectionHeaderFor(includeLine) {
|
||||
const line = String(includeLine ?? "").trim();
|
||||
if (line.startsWith("require"))
|
||||
return "-- DMS Include Configs";
|
||||
if (line.startsWith("source"))
|
||||
return "# DMS Include Configs";
|
||||
return "// DMS Include Configs";
|
||||
}
|
||||
|
||||
function managedIncludePatternFor(includeLine) {
|
||||
const line = String(includeLine ?? "").trim();
|
||||
if (line.startsWith("require"))
|
||||
return "require.*dms[.]";
|
||||
if (line.startsWith("source"))
|
||||
return "source.*dms/";
|
||||
return "include.*dms/";
|
||||
}
|
||||
|
||||
function buildRepairScript(options) {
|
||||
const configFile = options.configFile;
|
||||
const backupFile = options.backupFile;
|
||||
@@ -49,9 +31,7 @@ function buildRepairScript(options) {
|
||||
for (const include of includes) {
|
||||
if (!include.grepPattern || !include.includeLine)
|
||||
continue;
|
||||
const sectionHeader = options.sectionHeader || sectionHeaderFor(include.includeLine);
|
||||
const managedIncludePattern = managedIncludePatternFor(include.includeLine);
|
||||
commands.push(`if ! grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(include.grepPattern)}; then if grep -Fqx ${shQuote(sectionHeader)} ${shQuote(configFile)} 2>/dev/null || grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(managedIncludePattern)}; then printf '%s\\n' ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; elif [ -s ${shQuote(configFile)} ]; then printf '\\n%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; else printf '%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; fi; fi`);
|
||||
commands.push(`if ! grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(include.grepPattern)}; then echo '' >> ${shQuote(configFile)} && printf '%s\\n' ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; fi`);
|
||||
}
|
||||
|
||||
return commands.join("; ");
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property int revision: 0
|
||||
property int appliedRevision: 0
|
||||
readonly property bool ready: appliedRevision >= revision
|
||||
|
||||
// Latched: surfaces render the last compositor-acknowledged state until the atomic flip on ack
|
||||
property bool effectiveFrameEnabled: false
|
||||
property string effectiveFrameMode: "connected"
|
||||
readonly property bool effectiveConnectedFrameModeActive: effectiveFrameEnabled && effectiveFrameMode === "connected"
|
||||
|
||||
signal transitionRequested(int revision)
|
||||
|
||||
function begin() {
|
||||
revision++;
|
||||
transitionRequested(revision);
|
||||
return revision;
|
||||
}
|
||||
|
||||
function acknowledge(requestRevision) {
|
||||
if (requestRevision > appliedRevision)
|
||||
appliedRevision = requestRevision;
|
||||
}
|
||||
|
||||
function syncEffective() {
|
||||
effectiveFrameEnabled = SettingsData.frameEnabled;
|
||||
effectiveFrameMode = SettingsData.frameMode;
|
||||
}
|
||||
|
||||
onReadyChanged: {
|
||||
if (ready)
|
||||
syncEffective();
|
||||
}
|
||||
|
||||
// Tracks settings-load changes; live toggles begin() first (ready false) so the latch holds
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onFrameEnabledChanged() {
|
||||
if (root.ready)
|
||||
root.syncEffective();
|
||||
}
|
||||
function onFrameModeChanged() {
|
||||
if (root.ready)
|
||||
root.syncEffective();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: syncEffective()
|
||||
}
|
||||
@@ -25,16 +25,6 @@ Singleton {
|
||||
return CompositorService.useHyprlandFocusGrab && keyboardFocus(active, customFocus) === WlrKeyboardFocus.OnDemand;
|
||||
}
|
||||
|
||||
function captureActiveToplevel() {
|
||||
return ToplevelManager.activeToplevel;
|
||||
}
|
||||
|
||||
function restoreToplevel(toplevel) {
|
||||
if (toplevel)
|
||||
Qt.callLater(() => toplevel.activate());
|
||||
return null;
|
||||
}
|
||||
|
||||
property list<var> barWindows: []
|
||||
|
||||
function registerBarWindow(window) {
|
||||
|
||||
@@ -262,11 +262,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property bool frameEnabled: false
|
||||
onFrameEnabledChanged: {
|
||||
saveSettings();
|
||||
if (!_loading)
|
||||
updateFrameCompositorLayout();
|
||||
}
|
||||
onFrameEnabledChanged: saveSettings()
|
||||
property real frameThickness: 16
|
||||
onFrameThicknessChanged: saveSettings()
|
||||
property int barInsetPaddingShared: -1
|
||||
@@ -299,11 +295,7 @@ Singleton {
|
||||
onFrameLauncherEdgeHoverChanged: saveSettings()
|
||||
readonly property string frameModalEmergeSide: frameLauncherEmergeSide === "top" ? "bottom" : "top"
|
||||
property string frameMode: "connected"
|
||||
onFrameModeChanged: {
|
||||
saveSettings();
|
||||
if (!_loading && frameEnabled)
|
||||
updateFrameCompositorLayout();
|
||||
}
|
||||
onFrameModeChanged: saveSettings()
|
||||
property var connectedFrameBarStyleBackups: ({})
|
||||
onConnectedFrameBarStyleBackupsChanged: saveSettings()
|
||||
readonly property bool connectedFrameModeActive: frameEnabled && frameMode === "connected"
|
||||
@@ -456,7 +448,6 @@ Singleton {
|
||||
property string audioScrollMode: "volume"
|
||||
property int audioWheelScrollAmount: 5
|
||||
property bool audioDeviceScrollVolumeEnabled: false
|
||||
property var mediaExcludePlayers: []
|
||||
property bool clockCompactMode: false
|
||||
property int focusedWindowSize: 1
|
||||
property bool focusedWindowCompactMode: false
|
||||
@@ -1016,17 +1007,6 @@ Singleton {
|
||||
}
|
||||
]
|
||||
|
||||
// Standalone bar xray is unsafe when windows can render beneath its surface
|
||||
function _standaloneBarXrayAvailable(configs) {
|
||||
const list = configs || [];
|
||||
const activeBars = list.filter(c => c && c.enabled && (c.visible ?? true));
|
||||
const gapsOverride = (typeof CompositorService !== "undefined" && CompositorService.isHyprland) ? hyprlandLayoutGapsOverride : niriLayoutGapsOverride;
|
||||
const layoutGaps = gapsOverride >= 0 ? gapsOverride : Math.max(4, (list[0]?.spacing ?? 4));
|
||||
return activeBars.every(c => !c.autoHide && !(c.useOverlayLayer ?? false) && (c.spacing ?? 4) + (c.bottomGap ?? 0) + layoutGaps >= 0);
|
||||
}
|
||||
|
||||
readonly property bool standaloneBarXrayAvailable: _standaloneBarXrayAvailable(barConfigs)
|
||||
|
||||
property bool desktopClockEnabled: false
|
||||
property string desktopClockStyle: "analog"
|
||||
property real desktopClockTransparency: 0.8
|
||||
@@ -1342,35 +1322,6 @@ Singleton {
|
||||
return true;
|
||||
}
|
||||
|
||||
function moveDesktopWidgetInstanceToGroup(instanceId, groupId, newIndexInGroup) {
|
||||
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||
const groups = desktopWidgetGroups || [];
|
||||
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||
if (idx === -1)
|
||||
return false;
|
||||
const [item] = instances.splice(idx, 1);
|
||||
item.group = groupId || null;
|
||||
const groupMatches = inst => {
|
||||
if (!groupId)
|
||||
return !inst.group || !groups.some(g => g.id === inst.group);
|
||||
return inst.group === groupId;
|
||||
};
|
||||
const groupInstances = instances.filter(groupMatches);
|
||||
const clamped = Math.max(0, Math.min(newIndexInGroup, groupInstances.length));
|
||||
let targetGlobalIdx;
|
||||
if (clamped >= groupInstances.length) {
|
||||
const last = groupInstances[groupInstances.length - 1];
|
||||
targetGlobalIdx = last ? instances.findIndex(inst => inst.id === last.id) + 1 : instances.length;
|
||||
} else {
|
||||
const targetInstance = groupInstances[clamped];
|
||||
targetGlobalIdx = instances.findIndex(inst => inst.id === targetInstance.id);
|
||||
}
|
||||
instances.splice(targetGlobalIdx, 0, item);
|
||||
desktopWidgetInstances = instances;
|
||||
saveSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
function createDesktopWidgetGroup(name) {
|
||||
const id = "dwg_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
|
||||
const group = {
|
||||
@@ -1471,17 +1422,6 @@ Singleton {
|
||||
MangoService.generateLayoutConfig();
|
||||
}
|
||||
|
||||
function updateFrameCompositorLayout() {
|
||||
// Generate before begin() so compositor readiness is already pending at transitionRequested
|
||||
if (typeof CompositorService !== "undefined") {
|
||||
if (CompositorService.isNiri && typeof NiriService !== "undefined")
|
||||
NiriService.generateNiriLayoutConfig(true);
|
||||
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined")
|
||||
HyprlandService.generateLayoutConfig(true);
|
||||
}
|
||||
FrameTransitionState.begin();
|
||||
}
|
||||
|
||||
function resolveIconTheme() {
|
||||
if (iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||
return iconThemeLight;
|
||||
@@ -2429,17 +2369,13 @@ Singleton {
|
||||
if (index === -1)
|
||||
return;
|
||||
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position;
|
||||
const barXrayTargetWasAvailable = _standaloneBarXrayAvailable(configs);
|
||||
if (updates.autoHide === false || updates.visible === false)
|
||||
setBarIpcReveal(barId, false);
|
||||
|
||||
Object.assign(configs[index], updates);
|
||||
const sanitizedConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
||||
barConfigs = sanitizedConfigs;
|
||||
barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
||||
updateBarConfigs();
|
||||
|
||||
if (!frameEnabled && _standaloneBarXrayAvailable(sanitizedConfigs) !== barXrayTargetWasAvailable)
|
||||
updateCompositorLayout();
|
||||
if (positionChanged) {
|
||||
NotificationService.dismissAllPopups();
|
||||
}
|
||||
@@ -3126,32 +3062,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function addMediaExcludePlayer(identity) {
|
||||
if (identity === undefined || identity === null)
|
||||
return;
|
||||
var normalizedIdentity = identity.toString().trim().toLowerCase();
|
||||
if (!normalizedIdentity)
|
||||
return;
|
||||
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
|
||||
var normalizedList = list.map(function (id) {
|
||||
return id ? id.toString().trim().toLowerCase() : "";
|
||||
});
|
||||
if (normalizedList.indexOf(normalizedIdentity) >= 0)
|
||||
return;
|
||||
list.push(normalizedIdentity);
|
||||
mediaExcludePlayers = list;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function removeMediaExcludePlayer(index) {
|
||||
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
|
||||
if (index < 0 || index >= list.length)
|
||||
return;
|
||||
list.splice(index, 1);
|
||||
mediaExcludePlayers = list;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
property bool _pendingExpandNotificationRules: false
|
||||
property int _pendingNotificationRuleIndex: -1
|
||||
|
||||
@@ -3572,9 +3482,6 @@ Singleton {
|
||||
onLoaded: {
|
||||
if (isGreeterMode)
|
||||
return;
|
||||
const wasLoaded = _hasLoaded;
|
||||
const prevFrameEnabled = frameEnabled;
|
||||
const prevFrameMode = frameMode;
|
||||
_loading = true;
|
||||
_hasUnsavedChanges = false;
|
||||
try {
|
||||
@@ -3609,9 +3516,6 @@ Singleton {
|
||||
} finally {
|
||||
_loading = false;
|
||||
}
|
||||
// External edits reload under _loading, which skips the per-property transition triggers
|
||||
if (wasLoaded && !_parseError && (frameEnabled !== prevFrameEnabled || (frameEnabled && frameMode !== prevFrameMode)))
|
||||
updateFrameCompositorLayout();
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode) {
|
||||
|
||||
@@ -17,8 +17,6 @@ const StockThemes = {
|
||||
background: "#101418",
|
||||
backgroundText: "#e0e2e8",
|
||||
outline: "#8c9199",
|
||||
surfaceContainerLowest: "#0c1014",
|
||||
surfaceContainerLow: "#191c20",
|
||||
surfaceContainer: "#1d2024",
|
||||
surfaceContainerHigh: "#272a2f",
|
||||
surfaceContainerHighest: "#32353a",
|
||||
@@ -37,8 +35,6 @@ const StockThemes = {
|
||||
background: "#141218",
|
||||
backgroundText: "#e6e0e9",
|
||||
outline: "#948f99",
|
||||
surfaceContainerLowest: "#100e14",
|
||||
surfaceContainerLow: "#1d1b20",
|
||||
surfaceContainer: "#211f24",
|
||||
surfaceContainerHigh: "#2b292f",
|
||||
surfaceContainerHighest: "#36343a",
|
||||
@@ -57,8 +53,6 @@ const StockThemes = {
|
||||
background: "#10140f",
|
||||
backgroundText: "#e0e4db",
|
||||
outline: "#8c9388",
|
||||
surfaceContainerLowest: "#0c100b",
|
||||
surfaceContainerLow: "#191d17",
|
||||
surfaceContainer: "#1d211b",
|
||||
surfaceContainerHigh: "#272b25",
|
||||
surfaceContainerHighest: "#323630",
|
||||
@@ -77,8 +71,6 @@ const StockThemes = {
|
||||
background: "#1a120e",
|
||||
backgroundText: "#f0dfd8",
|
||||
outline: "#a08d85",
|
||||
surfaceContainerLowest: "#160e0a",
|
||||
surfaceContainerLow: "#231a16",
|
||||
surfaceContainer: "#271e1a",
|
||||
surfaceContainerHigh: "#322824",
|
||||
surfaceContainerHighest: "#3d332e",
|
||||
@@ -97,8 +89,6 @@ const StockThemes = {
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c89",
|
||||
surfaceContainerLowest: "#160d0c",
|
||||
surfaceContainerLow: "#231918",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231",
|
||||
@@ -117,8 +107,6 @@ const StockThemes = {
|
||||
background: "#0e1416",
|
||||
backgroundText: "#dee3e5",
|
||||
outline: "#899295",
|
||||
surfaceContainerLowest: "#0a1012",
|
||||
surfaceContainerLow: "#171d1e",
|
||||
surfaceContainer: "#1b2122",
|
||||
surfaceContainerHigh: "#252b2c",
|
||||
surfaceContainerHighest: "#303637",
|
||||
@@ -137,8 +125,6 @@ const StockThemes = {
|
||||
background: "#191112",
|
||||
backgroundText: "#f0dee0",
|
||||
outline: "#9f8c8e",
|
||||
surfaceContainerLowest: "#150d0e",
|
||||
surfaceContainerLow: "#22191a",
|
||||
surfaceContainer: "#261d1e",
|
||||
surfaceContainerHigh: "#312829",
|
||||
surfaceContainerHighest: "#3c3233",
|
||||
@@ -157,8 +143,6 @@ const StockThemes = {
|
||||
background: "#17130b",
|
||||
backgroundText: "#ebe1d4",
|
||||
outline: "#998f80",
|
||||
surfaceContainerLowest: "#130f07",
|
||||
surfaceContainerLow: "#1f1b13",
|
||||
surfaceContainer: "#231f17",
|
||||
surfaceContainerHigh: "#2e2921",
|
||||
surfaceContainerHighest: "#39342b",
|
||||
@@ -177,8 +161,6 @@ const StockThemes = {
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c8a",
|
||||
surfaceContainerLowest: "#160d0c",
|
||||
surfaceContainerLow: "#231918",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231",
|
||||
@@ -197,8 +179,6 @@ const StockThemes = {
|
||||
background: "#131315",
|
||||
backgroundText: "#e4e2e3",
|
||||
outline: "#929092",
|
||||
surfaceContainerLowest: "#252525",
|
||||
surfaceContainerLow: "#303030",
|
||||
surfaceContainer: "#353535",
|
||||
surfaceContainerHigh: "#424242",
|
||||
surfaceContainerHighest: "#505050",
|
||||
@@ -223,8 +203,6 @@ const StockThemes = {
|
||||
background: "#f7f9ff",
|
||||
backgroundText: "#181c20",
|
||||
outline: "#72777f",
|
||||
surfaceContainerLowest: "#f9fbff",
|
||||
surfaceContainerLow: "#eef0f6",
|
||||
surfaceContainer: "#eceef4",
|
||||
surfaceContainerHigh: "#e6e8ee",
|
||||
surfaceContainerHighest: "#e0e2e8",
|
||||
@@ -243,8 +221,6 @@ const StockThemes = {
|
||||
background: "#fef7ff",
|
||||
backgroundText: "#1d1b20",
|
||||
outline: "#7a757f",
|
||||
surfaceContainerLowest: "#fff9ff",
|
||||
surfaceContainerLow: "#f4eef6",
|
||||
surfaceContainer: "#f2ecf4",
|
||||
surfaceContainerHigh: "#ece6ee",
|
||||
surfaceContainerHighest: "#e6e0e9",
|
||||
@@ -263,8 +239,6 @@ const StockThemes = {
|
||||
background: "#f7fbf1",
|
||||
backgroundText: "#191d17",
|
||||
outline: "#72796f",
|
||||
surfaceContainerLowest: "#f9fdf3",
|
||||
surfaceContainerLow: "#eef1e8",
|
||||
surfaceContainer: "#ecefe6",
|
||||
surfaceContainerHigh: "#e6e9e0",
|
||||
surfaceContainerHighest: "#e0e4db",
|
||||
@@ -283,8 +257,6 @@ const StockThemes = {
|
||||
background: "#fff8f6",
|
||||
backgroundText: "#221a16",
|
||||
outline: "#85736c",
|
||||
surfaceContainerLowest: "#fffaf8",
|
||||
surfaceContainerLow: "#feece5",
|
||||
surfaceContainer: "#fceae3",
|
||||
surfaceContainerHigh: "#f6e5de",
|
||||
surfaceContainerHighest: "#f0dfd8",
|
||||
@@ -303,8 +275,6 @@ const StockThemes = {
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857370",
|
||||
surfaceContainerLowest: "#fffaf9",
|
||||
surfaceContainerLow: "#feece9",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f7e4e1",
|
||||
surfaceContainerHighest: "#f1dedc",
|
||||
@@ -323,8 +293,6 @@ const StockThemes = {
|
||||
background: "#f5fafc",
|
||||
backgroundText: "#171d1e",
|
||||
outline: "#6f797b",
|
||||
surfaceContainerLowest: "#f7fcfe",
|
||||
surfaceContainerLow: "#ebf1f2",
|
||||
surfaceContainer: "#e9eff0",
|
||||
surfaceContainerHigh: "#e3e9eb",
|
||||
surfaceContainerHighest: "#dee3e5",
|
||||
@@ -343,8 +311,6 @@ const StockThemes = {
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#22191a",
|
||||
outline: "#847375",
|
||||
surfaceContainerLowest: "#fffaf9",
|
||||
surfaceContainerLow: "#fdeced",
|
||||
surfaceContainer: "#fbeaeb",
|
||||
surfaceContainerHigh: "#f5e4e5",
|
||||
surfaceContainerHighest: "#f0dee0",
|
||||
@@ -363,8 +329,6 @@ const StockThemes = {
|
||||
background: "#fff8f2",
|
||||
backgroundText: "#1f1b13",
|
||||
outline: "#7f7667",
|
||||
surfaceContainerLowest: "#fffaf4",
|
||||
surfaceContainerLow: "#f8eee1",
|
||||
surfaceContainer: "#f6ecdf",
|
||||
surfaceContainerHigh: "#f1e7d9",
|
||||
surfaceContainerHighest: "#ebe1d4",
|
||||
@@ -383,8 +347,6 @@ const StockThemes = {
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857371",
|
||||
surfaceContainerLowest: "#fffaf9",
|
||||
surfaceContainerLow: "#feece9",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f6e4e2",
|
||||
surfaceContainerHighest: "#f1dedc",
|
||||
@@ -403,8 +365,6 @@ const StockThemes = {
|
||||
background: "#ffffff",
|
||||
backgroundText: "#1a1a1a",
|
||||
outline: "#757577",
|
||||
surfaceContainerLowest: "#fafafb",
|
||||
surfaceContainerLow: "#ededef",
|
||||
surfaceContainer: "#e8e8ea",
|
||||
surfaceContainerHigh: "#dcdcde",
|
||||
surfaceContainerHighest: "#d0d0d2",
|
||||
|
||||
+46
-64
@@ -463,8 +463,6 @@ Singleton {
|
||||
"background": getMatugenColor("background", "#1a1c1e"),
|
||||
"backgroundText": getMatugenColor("on_background", "#e3e8ef"),
|
||||
"outline": getMatugenColor("outline", "#8e918f"),
|
||||
"surfaceContainerLowest": getMatugenColor("surface_container_lowest", "#0e1013"),
|
||||
"surfaceContainerLow": getMatugenColor("surface_container_low", "#181a1d"),
|
||||
"surfaceContainer": getMatugenColor("surface_container", "#1e2023"),
|
||||
"surfaceContainerHigh": getMatugenColor("surface_container_high", "#292b2f"),
|
||||
"surfaceContainerHighest": getMatugenColor("surface_container_highest", "#343740"),
|
||||
@@ -537,9 +535,7 @@ Singleton {
|
||||
property color background: currentThemeData.background
|
||||
property color backgroundText: currentThemeData.backgroundText
|
||||
property color outline: currentThemeData.outline
|
||||
property color outlineVariant: currentThemeData.outlineVariant || withAlpha(outline, 0.6)
|
||||
property color surfaceContainerLowest: currentThemeData.surfaceContainerLowest || blend(surfaceContainer, surface, 1.2)
|
||||
property color surfaceContainerLow: currentThemeData.surfaceContainerLow || blend(surface, surfaceContainer, 0.667)
|
||||
property color outlineVariant: currentThemeData.outlineVariant || Qt.rgba(outline.r, outline.g, outline.b, 0.6)
|
||||
property color surfaceContainer: currentThemeData.surfaceContainer
|
||||
property color surfaceContainerHigh: currentThemeData.surfaceContainerHigh
|
||||
property color surfaceContainerHighest: currentThemeData.surfaceContainerHighest || surfaceContainerHigh
|
||||
@@ -550,9 +546,9 @@ Singleton {
|
||||
property color onSurface: surfaceText
|
||||
property color onSurfaceVariant: surfaceVariantText
|
||||
property color onPrimary: primaryText
|
||||
property color onSurface_12: withAlpha(onSurface, 0.12)
|
||||
property color onSurface_38: withAlpha(onSurface, 0.38)
|
||||
property color onSurfaceVariant_30: withAlpha(onSurfaceVariant, 0.30)
|
||||
property color onSurface_12: Qt.rgba(onSurface.r, onSurface.g, onSurface.b, 0.12)
|
||||
property color onSurface_38: Qt.rgba(onSurface.r, onSurface.g, onSurface.b, 0.38)
|
||||
property color onSurfaceVariant_30: Qt.rgba(onSurfaceVariant.r, onSurfaceVariant.g, onSurfaceVariant.b, 0.30)
|
||||
|
||||
property color error: currentThemeData.error || "#F2B8B5"
|
||||
property color warning: currentThemeData.warning || "#FF9800"
|
||||
@@ -561,33 +557,32 @@ Singleton {
|
||||
property color tempDanger: "#ff5555"
|
||||
property color success: currentThemeData.success || "#4CAF50"
|
||||
|
||||
property color primaryHover: withAlpha(primary, 0.12)
|
||||
property color primaryHoverLight: withAlpha(primary, transparentBlurLayers ? 0.12 : 0.08)
|
||||
property color primaryPressed: withAlpha(primary, transparentBlurLayers ? 0.24 : 0.16)
|
||||
property color primarySelected: withAlpha(primary, 0.3)
|
||||
property color primaryBackground: withAlpha(primary, 0.04)
|
||||
property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12)
|
||||
property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, transparentBlurLayers ? 0.12 : 0.08)
|
||||
property color primaryPressed: Qt.rgba(primary.r, primary.g, primary.b, transparentBlurLayers ? 0.24 : 0.16)
|
||||
property color primarySelected: Qt.rgba(primary.r, primary.g, primary.b, 0.3)
|
||||
property color primaryBackground: Qt.rgba(primary.r, primary.g, primary.b, 0.04)
|
||||
|
||||
property color secondaryHover: withAlpha(secondary, 0.08)
|
||||
property color secondaryHover: Qt.rgba(secondary.r, secondary.g, secondary.b, 0.08)
|
||||
|
||||
property color surfaceHover: withAlpha(surfaceVariant, 0.08)
|
||||
property color surfacePressed: withAlpha(surfaceVariant, 0.12)
|
||||
property color surfaceSelected: withAlpha(surfaceVariant, 0.15)
|
||||
property color surfaceLight: withAlpha(surfaceVariant, transparentBlurLayers ? 0.3 : 0.1)
|
||||
property color surfaceVariantAlpha: withAlpha(surfaceVariant, 0.2)
|
||||
property color surfaceHover: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.08)
|
||||
property color surfacePressed: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.12)
|
||||
property color surfaceSelected: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.15)
|
||||
property color surfaceLight: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, transparentBlurLayers ? 0.3 : 0.1)
|
||||
property color surfaceVariantAlpha: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.2)
|
||||
|
||||
readonly property bool foregroundLayers: typeof SettingsData === "undefined" || (SettingsData.blurForegroundLayers ?? true)
|
||||
readonly property bool blurForegroundLayers: BlurService.enabled && foregroundLayers
|
||||
readonly property bool transparentBlurLayers: BlurService.enabled && !foregroundLayers
|
||||
readonly property bool blurForegroundLayers: BlurService.enabled && (typeof SettingsData === "undefined" || (SettingsData.blurForegroundLayers ?? true))
|
||||
readonly property bool transparentBlurLayers: BlurService.enabled && !blurForegroundLayers
|
||||
readonly property color readableSurface: withAlpha(surfaceContainer, popupTransparency)
|
||||
readonly property color readableSurfaceHigh: withAlpha(surfaceContainerHigh, popupTransparency)
|
||||
readonly property color floatingSurface: foregroundLayers ? readableSurface : withAlpha(readableSurface, 0)
|
||||
readonly property color floatingSurfaceHigh: foregroundLayers ? readableSurfaceHigh : withAlpha(readableSurfaceHigh, 0)
|
||||
readonly property color floatingSurface: transparentBlurLayers ? "transparent" : readableSurface
|
||||
readonly property color floatingSurfaceHigh: transparentBlurLayers ? "transparent" : readableSurfaceHigh
|
||||
readonly property color nestedSurface: floatingSurfaceHigh
|
||||
readonly property real blurLayerOutlineOpacity: Math.max(0, Math.min(1, typeof SettingsData === "undefined" ? 0.12 : (SettingsData.blurLayerOutlineOpacity ?? 0.12)))
|
||||
readonly property real layerOutlineOpacity: blurLayerOutlineOpacity
|
||||
readonly property int layerOutlineWidth: layerOutlineOpacity > 0 ? 1 : 0
|
||||
property color surfaceTextHover: withAlpha(surfaceText, 0.08)
|
||||
property color surfaceTextAlpha: withAlpha(surfaceText, 0.3)
|
||||
readonly property real layerOutlineOpacity: BlurService.enabled ? blurLayerOutlineOpacity : 0.08
|
||||
readonly property int layerOutlineWidth: BlurService.enabled && layerOutlineOpacity > 0 ? 1 : 0
|
||||
property color surfaceTextHover: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.08)
|
||||
property color surfaceTextAlpha: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.3)
|
||||
|
||||
function roleColor(mode) {
|
||||
switch (mode) {
|
||||
@@ -612,10 +607,6 @@ Singleton {
|
||||
return surfaceVariant;
|
||||
case "s":
|
||||
return surface;
|
||||
case "scll":
|
||||
return surfaceContainerLowest;
|
||||
case "scl":
|
||||
return surfaceContainerLow;
|
||||
case "sc":
|
||||
return surfaceContainer;
|
||||
case "sch":
|
||||
@@ -628,23 +619,19 @@ Singleton {
|
||||
case "err":
|
||||
return error;
|
||||
default:
|
||||
return withAlpha(surface, 0);
|
||||
return "transparent";
|
||||
}
|
||||
}
|
||||
property color surfaceTextLight: withAlpha(surfaceText, 0.06)
|
||||
property color surfaceTextSecondary: withAlpha(surfaceText, 0.6)
|
||||
property color surfaceTextMedium: withAlpha(surfaceText, 0.7)
|
||||
property color surfaceTextLight: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.06)
|
||||
property color surfaceTextMedium: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.7)
|
||||
|
||||
property color outlineButton: withAlpha(outline, 0.5)
|
||||
property color outlineLight: withAlpha(outline, Math.min(1, layerOutlineOpacity * 0.625))
|
||||
property color outlineMedium: withAlpha(outline, layerOutlineOpacity)
|
||||
property color outlineStrong: withAlpha(outline, Math.min(1, layerOutlineOpacity * 1.5))
|
||||
property color outlineHeavy: withAlpha(outline, 0.2)
|
||||
property color outlineButton: Qt.rgba(outline.r, outline.g, outline.b, 0.5)
|
||||
property color outlineLight: Qt.rgba(outline.r, outline.g, outline.b, BlurService.enabled ? Math.min(1, layerOutlineOpacity * 0.625) : 0.05)
|
||||
property color outlineMedium: Qt.rgba(outline.r, outline.g, outline.b, layerOutlineOpacity)
|
||||
property color outlineStrong: Qt.rgba(outline.r, outline.g, outline.b, BlurService.enabled ? Math.min(1, layerOutlineOpacity * 1.5) : 0.12)
|
||||
|
||||
property color errorHover: withAlpha(error, 0.12)
|
||||
property color errorPressed: withAlpha(error, 0.16)
|
||||
property color errorSelected: withAlpha(error, 0.3)
|
||||
property color warningHover: withAlpha(warning, 0.12)
|
||||
property color errorHover: Qt.rgba(error.r, error.g, error.b, 0.12)
|
||||
property color errorPressed: Qt.rgba(error.r, error.g, error.b, 0.16)
|
||||
|
||||
readonly property color ccTileActiveBg: {
|
||||
switch (SettingsData.controlCenterTileColorMode) {
|
||||
@@ -659,7 +646,7 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
readonly property color ccTileInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.16) : (foregroundLayers ? withAlpha(surfaceContainerHigh, BlurService.enabled ? Math.min(popupTransparency, 0.24) : popupTransparency) : withAlpha(surfaceContainer, 0))
|
||||
readonly property color ccTileInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.16) : (blurForegroundLayers ? withAlpha(surfaceContainerHigh, Math.min(popupTransparency, 0.24)) : withAlpha(surfaceContainer, popupTransparency))
|
||||
readonly property color ccPillInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.08) : nestedSurface
|
||||
readonly property color ccPillInactiveHoverBg: transparentBlurLayers ? withAlpha(primary, 0.10) : primaryPressed
|
||||
readonly property color ccSliderTrackColor: transparentBlurLayers ? surfaceText : surfaceContainerHigh
|
||||
@@ -694,13 +681,13 @@ Singleton {
|
||||
readonly property color ccTileRing: {
|
||||
switch (SettingsData.controlCenterTileColorMode) {
|
||||
case "primaryContainer":
|
||||
return withAlpha(primary, 0.22);
|
||||
return Qt.rgba(primary.r, primary.g, primary.b, 0.22);
|
||||
case "secondary":
|
||||
return withAlpha(surfaceText, 0.22);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.22);
|
||||
case "surfaceVariant":
|
||||
return withAlpha(surfaceText, 0.22);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.22);
|
||||
default:
|
||||
return withAlpha(primaryText, 0.22);
|
||||
return Qt.rgba(primaryText.r, primaryText.g, primaryText.b, 0.22);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,11 +720,11 @@ Singleton {
|
||||
readonly property color buttonHover: {
|
||||
switch (SettingsData.buttonColorMode) {
|
||||
case "primaryContainer":
|
||||
return withAlpha(primary, 0.12);
|
||||
return Qt.rgba(primary.r, primary.g, primary.b, 0.12);
|
||||
case "secondary":
|
||||
return withAlpha(surfaceText, 0.12);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.12);
|
||||
case "surfaceVariant":
|
||||
return withAlpha(surfaceText, 0.12);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.12);
|
||||
default:
|
||||
return primaryHover;
|
||||
}
|
||||
@@ -746,11 +733,11 @@ Singleton {
|
||||
readonly property color buttonPressed: {
|
||||
switch (SettingsData.buttonColorMode) {
|
||||
case "primaryContainer":
|
||||
return withAlpha(primary, 0.16);
|
||||
return Qt.rgba(primary.r, primary.g, primary.b, 0.16);
|
||||
case "secondary":
|
||||
return withAlpha(surfaceText, 0.16);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.16);
|
||||
case "surfaceVariant":
|
||||
return withAlpha(surfaceText, 0.16);
|
||||
return Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.16);
|
||||
default:
|
||||
return primaryPressed;
|
||||
}
|
||||
@@ -1076,12 +1063,12 @@ Singleton {
|
||||
readonly property real connectedCornerRadius: {
|
||||
if (typeof SettingsData === "undefined")
|
||||
return 12;
|
||||
return FrameTransitionState.effectiveConnectedFrameModeActive ? SettingsData.frameRounding : cornerRadius;
|
||||
return SettingsData.connectedFrameModeActive ? SettingsData.frameRounding : cornerRadius;
|
||||
}
|
||||
readonly property color connectedSurfaceColor: {
|
||||
if (typeof SettingsData === "undefined")
|
||||
return withAlpha(surfaceContainer, popupTransparency);
|
||||
return isConnectedEffect ? withAlpha(SettingsData.effectiveFrameColor, SettingsData.frameOpacity) : withAlpha(surfaceContainer, popupTransparency);
|
||||
return isConnectedEffect ? Qt.rgba(SettingsData.effectiveFrameColor.r, SettingsData.effectiveFrameColor.g, SettingsData.effectiveFrameColor.b, SettingsData.frameOpacity) : withAlpha(surfaceContainer, popupTransparency);
|
||||
}
|
||||
readonly property real connectedSurfaceRadius: isConnectedEffect ? connectedCornerRadius : cornerRadius
|
||||
readonly property bool connectedSurfaceBlurEnabled: (typeof SettingsData === "undefined") ? true : (!isConnectedEffect || SettingsData.frameBlurEnabled)
|
||||
@@ -1250,7 +1237,6 @@ Singleton {
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0;
|
||||
}
|
||||
|
||||
property real spacingXXS: 2
|
||||
property real spacingXS: 4
|
||||
property real spacingS: 8
|
||||
property real spacingM: 12
|
||||
@@ -1482,7 +1468,7 @@ Singleton {
|
||||
property string currentThemeName: currentTheme
|
||||
|
||||
function panelBackground() {
|
||||
return withAlpha(surfaceContainer, panelTransparency);
|
||||
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, panelTransparency);
|
||||
}
|
||||
|
||||
property real notepadTransparency: SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : popupTransparency
|
||||
@@ -1992,8 +1978,6 @@ Singleton {
|
||||
}
|
||||
|
||||
function withAlpha(c, a) {
|
||||
if (!c || c.r === undefined)
|
||||
return Qt.rgba(0, 0, 0, 0);
|
||||
return Qt.rgba(c.r, c.g, c.b, a);
|
||||
}
|
||||
|
||||
@@ -2004,8 +1988,6 @@ Singleton {
|
||||
}
|
||||
|
||||
function blendAlpha(c, a) {
|
||||
if (!c || c.r === undefined)
|
||||
return Qt.rgba(0, 0, 0, 0);
|
||||
return Qt.rgba(c.r, c.g, c.b, c.a * a);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,6 @@ var SPEC = {
|
||||
audioScrollMode: { def: "volume" },
|
||||
audioWheelScrollAmount: { def: 5 },
|
||||
audioDeviceScrollVolumeEnabled: { def: false },
|
||||
mediaExcludePlayers: { def: [] },
|
||||
clockCompactMode: { def: false },
|
||||
focusedWindowCompactMode: { def: false },
|
||||
focusedWindowSize: { def: 1 },
|
||||
|
||||
+8
-34
@@ -173,7 +173,6 @@ Item {
|
||||
}
|
||||
|
||||
property bool barSurfacesLoaded: true
|
||||
property int pendingFrameTransitionRevision: 0
|
||||
|
||||
function recreateBarSurfaces() {
|
||||
log.info("Recreating bar surfaces, screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
||||
@@ -182,23 +181,9 @@ Item {
|
||||
barSurfaceReloadAction.schedule();
|
||||
}
|
||||
|
||||
// Holds the bar rebuild until the compositor applies the layout, so the swap lands in one pass
|
||||
function runPendingFrameTransition() {
|
||||
if (pendingFrameTransitionRevision <= 0 || !CompositorService.frameCompositorLayoutReady)
|
||||
return;
|
||||
recreateBarSurfaces();
|
||||
}
|
||||
|
||||
DeferredAction {
|
||||
id: barSurfaceReloadAction
|
||||
onTriggered: {
|
||||
// Ack first so the latch flips and new bars build directly in the post-transition state
|
||||
if (root.pendingFrameTransitionRevision > 0 && CompositorService.frameCompositorLayoutReady) {
|
||||
FrameTransitionState.acknowledge(root.pendingFrameTransitionRevision);
|
||||
root.pendingFrameTransitionRevision = 0;
|
||||
}
|
||||
root.barSurfacesLoaded = true;
|
||||
}
|
||||
onTriggered: root.barSurfacesLoaded = true
|
||||
}
|
||||
|
||||
property string _barLayoutStateJson: {
|
||||
@@ -227,23 +212,14 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: FrameTransitionState
|
||||
function onTransitionRequested(revision) {
|
||||
root.pendingFrameTransitionRevision = Math.max(root.pendingFrameTransitionRevision, revision);
|
||||
root.runPendingFrameTransition();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onFrameCompositorLayoutReadyChanged() {
|
||||
root.runPendingFrameTransition();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onFrameEnabledChanged() {
|
||||
root.recreateBarSurfaces();
|
||||
}
|
||||
function onConnectedFrameModeActiveChanged() {
|
||||
root.recreateBarSurfaces();
|
||||
}
|
||||
function onForceDankBarLayoutRefresh() {
|
||||
root.recreateBarSurfaces();
|
||||
}
|
||||
@@ -258,7 +234,7 @@ Item {
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: FrameTransitionState.effectiveFrameEnabled && SettingsData.frameLauncherEdgeHover
|
||||
active: SettingsData.frameEnabled && SettingsData.frameLauncherEdgeHover
|
||||
asynchronous: false
|
||||
sourceComponent: FrameLauncherHoverZone {}
|
||||
}
|
||||
@@ -275,8 +251,6 @@ Item {
|
||||
values: JSON.parse(root._barLayoutStateJson)
|
||||
}
|
||||
|
||||
Component.onCompleted: BarWidgetService.dankBarRepeater = dankBarRepeater
|
||||
|
||||
property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader
|
||||
|
||||
delegate: Loader {
|
||||
|
||||
@@ -253,7 +253,7 @@ DankModal {
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -264,7 +264,7 @@ DankModal {
|
||||
iconName: "view_list"
|
||||
iconSize: 20
|
||||
iconColor: root.viewMode === "list" ? Theme.primary : Theme.surfaceText
|
||||
backgroundColor: root.viewMode === "list" ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0)
|
||||
backgroundColor: root.viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
onClicked: {
|
||||
root.viewMode = "list";
|
||||
}
|
||||
@@ -276,7 +276,7 @@ DankModal {
|
||||
iconName: "grid_view"
|
||||
iconSize: 20
|
||||
iconColor: root.viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
||||
backgroundColor: root.viewMode === "grid" ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0)
|
||||
backgroundColor: root.viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
onClicked: {
|
||||
root.viewMode = "grid";
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ DankModal {
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Passkey:")
|
||||
@@ -256,7 +256,7 @@ DankModal {
|
||||
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ Rectangle {
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
width: parent.width - root.iconContainerSize - Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -24,8 +24,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: visible = false
|
||||
|
||||
FocusScope {
|
||||
id: contentFocusScope
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -147,7 +147,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: "filter_list"
|
||||
iconColor: modal.activeFilter !== "all" ? Theme.primary : Theme.surfaceText
|
||||
backgroundColor: modal.activeFilter !== "all" ? Theme.primarySelected : Theme.withAlpha(Theme.primarySelected, 0)
|
||||
backgroundColor: modal.activeFilter !== "all" ? Theme.primarySelected : "transparent"
|
||||
tooltipText: I18n.tr("Filter by type", "Clipboard history type filter button tooltip")
|
||||
onClicked: filterMenuLoader.item?.openDropdownMenu()
|
||||
}
|
||||
|
||||
@@ -121,12 +121,12 @@ Item {
|
||||
const hostX = host?.alignedX;
|
||||
const hostY = host?.renderedAlignedY ?? host?.alignedY;
|
||||
const globalPos = (!isNaN(hostX) && !isNaN(hostY)) ? ({
|
||||
x: screenX + hostX + x,
|
||||
y: screenY + hostY + y
|
||||
}) : (parentHandler ? parentHandler.mapToGlobal(x, y) : ({
|
||||
x: screenX + x,
|
||||
y: screenY + y
|
||||
}));
|
||||
x: screenX + hostX + x,
|
||||
y: screenY + hostY + y
|
||||
}) : (parentHandler ? parentHandler.mapToGlobal(x, y) : ({
|
||||
x: screenX + x,
|
||||
y: screenY + y
|
||||
}));
|
||||
|
||||
targetScreen = screenRef;
|
||||
anchorX = globalPos.x - screenX + 4;
|
||||
@@ -258,7 +258,7 @@ Item {
|
||||
height: root.effectiveMenuHeight
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: BlurService.enabled ? BlurService.borderWidth : 1
|
||||
opacity: root.openState ? 1 : 0
|
||||
|
||||
@@ -321,7 +321,7 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineHeavy
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ Item {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
radius: Theme.cornerRadius
|
||||
color: itemMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(BlurService.hoverColor(Theme.widgetBaseHoverColor), 0)
|
||||
color: itemMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -419,7 +419,7 @@ Item {
|
||||
implicitWidth: saveMenuRow.implicitWidth + Theme.spacingS * 2
|
||||
implicitHeight: saveMenuRow.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: saveMenuSaveArea.containsMouse ? Theme.surfaceVariant : Theme.withAlpha(Theme.surfaceVariant, 0)
|
||||
color: saveMenuSaveArea.containsMouse ? Theme.surfaceVariant : "transparent"
|
||||
|
||||
Row {
|
||||
id: saveMenuRow
|
||||
@@ -457,7 +457,7 @@ Item {
|
||||
implicitWidth: saveMenuCloseRow.implicitWidth + Theme.spacingS * 2
|
||||
implicitHeight: saveMenuCloseRow.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: saveMenuCloseArea.containsMouse ? Theme.surfaceVariant : Theme.withAlpha(Theme.surfaceVariant, 0)
|
||||
color: saveMenuCloseArea.containsMouse ? Theme.surfaceVariant : "transparent"
|
||||
|
||||
Row {
|
||||
id: saveMenuCloseRow
|
||||
@@ -495,7 +495,7 @@ Item {
|
||||
implicitWidth: saveMenuPasteRow.implicitWidth + Theme.spacingS * 2
|
||||
implicitHeight: saveMenuPasteRow.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: saveMenuPasteArea.containsMouse ? Theme.surfaceVariant : Theme.withAlpha(Theme.surfaceVariant, 0)
|
||||
color: saveMenuPasteArea.containsMouse ? Theme.surfaceVariant : "transparent"
|
||||
opacity: modal.wtypeAvailable ? 1 : 0.5
|
||||
|
||||
Row {
|
||||
|
||||
@@ -110,7 +110,7 @@ Rectangle {
|
||||
iconName: "push_pin"
|
||||
iconSize: Theme.iconSize - 6
|
||||
iconColor: (entry.pinned || hasPinnedDuplicate) ? Theme.primary : Theme.surfaceText
|
||||
backgroundColor: (entry.pinned || hasPinnedDuplicate) ? Theme.primarySelected : Theme.withAlpha(Theme.primarySelected, 0)
|
||||
backgroundColor: (entry.pinned || hasPinnedDuplicate) ? Theme.primarySelected : "transparent"
|
||||
visible: root.showPinAction
|
||||
onClicked: {
|
||||
if (entry.pinned) {
|
||||
@@ -228,9 +228,9 @@ Rectangle {
|
||||
}
|
||||
onClicked: {
|
||||
if (SettingsData.clipboardClickToPaste) {
|
||||
pasteRequested();
|
||||
pasteRequested()
|
||||
} else {
|
||||
copyRequested();
|
||||
copyRequested()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ Item {
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -49,7 +50,7 @@ Item {
|
||||
iconName: "push_pin"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: header.activeTab === "saved" ? Theme.primary : Theme.surfaceText
|
||||
backgroundColor: header.activeTab === "saved" ? Theme.primarySelected : Theme.withAlpha(Theme.primarySelected, 0)
|
||||
backgroundColor: header.activeTab === "saved" ? Theme.primarySelected : "transparent"
|
||||
visible: header.pinnedCount > 0 || header.activeTab === "saved"
|
||||
tooltipText: header.activeTab === "saved" ? I18n.tr("Recent") : I18n.tr("Saved")
|
||||
onClicked: tabChanged(header.activeTab === "saved" ? "recents" : "saved")
|
||||
|
||||
@@ -15,7 +15,7 @@ Rectangle {
|
||||
|
||||
height: ClipboardConstants.keyboardHintsHeight
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, 0.95)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
opacity: visible ? 1 : 0
|
||||
@@ -24,7 +24,7 @@ Rectangle {
|
||||
Column {
|
||||
width: parent.width - Theme.spacingL * 2
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: keyboardHints.enterToPaste ? I18n.tr("↑/↓: Navigate • Enter: Paste • Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help")
|
||||
|
||||
@@ -211,14 +211,14 @@ DankModal {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (keyboardNavigation && selectedButton === 0) {
|
||||
return Theme.primaryHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
} else if (cancelButton.containsMouse) {
|
||||
return Theme.surfacePressed;
|
||||
} else {
|
||||
return Theme.surfaceVariantAlpha;
|
||||
}
|
||||
}
|
||||
border.color: (keyboardNavigation && selectedButton === 0) ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: (keyboardNavigation && selectedButton === 0) ? Theme.primary : "transparent"
|
||||
border.width: (keyboardNavigation && selectedButton === 0) ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
@@ -249,14 +249,14 @@ DankModal {
|
||||
color: {
|
||||
const baseColor = confirmButtonColor;
|
||||
if (keyboardNavigation && selectedButton === 1) {
|
||||
return Theme.withAlpha(baseColor, 1);
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 1);
|
||||
} else if (confirmButton.containsMouse) {
|
||||
return Theme.withAlpha(baseColor, 0.9);
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 0.9);
|
||||
} else {
|
||||
return baseColor;
|
||||
}
|
||||
}
|
||||
border.color: (keyboardNavigation && selectedButton === 1) ? "white" : Qt.rgba(1, 1, 1, 0)
|
||||
border.color: (keyboardNavigation && selectedButton === 1) ? "white" : "transparent"
|
||||
border.width: (keyboardNavigation && selectedButton === 1) ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -58,9 +58,6 @@ Item {
|
||||
HyprlandFocusGrab {
|
||||
windows: root.contentWindow ? [root.contentWindow] : []
|
||||
active: KeyboardFocus.wantsGrab(root.shouldHaveFocus, root.customKeyboardFocus)
|
||||
|
||||
property var restoreToplevel: null
|
||||
onActiveChanged: restoreToplevel = active ? KeyboardFocus.captureActiveToplevel() : KeyboardFocus.restoreToplevel(restoreToplevel)
|
||||
}
|
||||
readonly property var contentWindow: impl.item ? impl.item.contentWindow : null
|
||||
readonly property var effectiveScreen: impl.item ? impl.item.effectiveScreen : null
|
||||
@@ -93,7 +90,7 @@ Item {
|
||||
impl.item.toggle();
|
||||
}
|
||||
|
||||
readonly property var _desiredBackend: FrameTransitionState.effectiveConnectedFrameModeActive ? connectedComp : standaloneComp
|
||||
readonly property var _desiredBackend: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
|
||||
property var _resolvedBackend: null
|
||||
|
||||
Component.onCompleted: _resolvedBackend = _desiredBackend
|
||||
|
||||
@@ -33,7 +33,7 @@ Item {
|
||||
|
||||
property string preferredConnectedBarSide: SettingsData.frameModalEmergeSide
|
||||
|
||||
readonly property bool frameConnectedMode: FrameTransitionState.effectiveFrameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||
readonly property bool frameConnectedMode: SettingsData.frameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||
|
||||
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
||||
|
||||
@@ -69,7 +69,7 @@ Item {
|
||||
property real cornerRadius: Theme.cornerRadius
|
||||
readonly property bool connectedSurfaceOverride: frameOwnsConnectedChrome
|
||||
readonly property color effectiveBackgroundColor: connectedSurfaceOverride ? Theme.connectedSurfaceColor : backgroundColor
|
||||
readonly property color effectiveBorderColor: connectedSurfaceOverride ? Theme.withAlpha(borderColor, 0) : borderColor
|
||||
readonly property color effectiveBorderColor: connectedSurfaceOverride ? "transparent" : borderColor
|
||||
readonly property real effectiveBorderWidth: connectedSurfaceOverride ? 0 : borderWidth
|
||||
readonly property real effectiveCornerRadius: connectedSurfaceOverride ? Theme.connectedSurfaceRadius : cornerRadius
|
||||
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||
@@ -659,8 +659,8 @@ Item {
|
||||
level: root.shadowLevel
|
||||
fallbackOffset: root.shadowFallbackOffset
|
||||
targetRadius: root.effectiveCornerRadius
|
||||
targetColor: root.frameOwnsConnectedChrome ? Theme.withAlpha(root.effectiveBackgroundColor, 0) : root.effectiveBackgroundColor
|
||||
borderColor: root.frameOwnsConnectedChrome ? Theme.withAlpha(root.effectiveBorderColor, 0) : root.effectiveBorderColor
|
||||
targetColor: root.frameOwnsConnectedChrome ? "transparent" : root.effectiveBackgroundColor
|
||||
borderColor: root.frameOwnsConnectedChrome ? "transparent" : root.effectiveBorderColor
|
||||
borderWidth: root.frameOwnsConnectedChrome ? 0 : root.effectiveBorderWidth
|
||||
shadowEnabled: !root.frameOwnsConnectedChrome && root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
||||
}
|
||||
@@ -669,7 +669,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
radius: root.effectiveCornerRadius
|
||||
color: "transparent"
|
||||
border.color: (root.connectedSurfaceOverride || root.frameOwnsConnectedChrome) ? Theme.withAlpha(BlurService.borderColor, 0) : BlurService.borderColor
|
||||
border.color: (root.connectedSurfaceOverride || root.frameOwnsConnectedChrome) ? "transparent" : BlurService.borderColor
|
||||
border.width: (root.connectedSurfaceOverride || root.frameOwnsConnectedChrome) ? 0 : BlurService.borderWidth
|
||||
z: 100
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ Item {
|
||||
readonly property alias contentWindow: contentWindow
|
||||
readonly property alias clickCatcher: clickCatcher
|
||||
readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab
|
||||
readonly property bool useBackground: showBackground && !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool useBackground: showBackground && !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackground
|
||||
|
||||
signal opened
|
||||
|
||||
@@ -194,7 +194,7 @@ DankModal {
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariantAlpha
|
||||
border.color: textInput.activeFocus ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: textInput.activeFocus ? Theme.primary : "transparent"
|
||||
border.width: textInput.activeFocus ? 1 : 0
|
||||
|
||||
TextInput {
|
||||
@@ -216,7 +216,7 @@ DankModal {
|
||||
anchors.fill: parent
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.onSurface_38
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
|
||||
text: root.inputPlaceholder
|
||||
visible: textInput.text === "" && !textInput.activeFocus
|
||||
}
|
||||
@@ -238,14 +238,14 @@ DankModal {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (root.keyboardNavigation && root.selectedButton === 0) {
|
||||
return Theme.primaryHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
} else if (cancelButton.containsMouse) {
|
||||
return Theme.surfacePressed;
|
||||
} else {
|
||||
return Theme.surfaceVariantAlpha;
|
||||
}
|
||||
}
|
||||
border.color: (root.keyboardNavigation && root.selectedButton === 0) ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: (root.keyboardNavigation && root.selectedButton === 0) ? Theme.primary : "transparent"
|
||||
border.width: (root.keyboardNavigation && root.selectedButton === 0) ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
@@ -273,14 +273,14 @@ DankModal {
|
||||
color: {
|
||||
const baseColor = root.confirmButtonColor;
|
||||
if (root.keyboardNavigation && root.selectedButton === 1) {
|
||||
return Theme.withAlpha(baseColor, 1);
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 1);
|
||||
} else if (confirmButton.containsMouse) {
|
||||
return Theme.withAlpha(baseColor, 0.9);
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 0.9);
|
||||
} else {
|
||||
return baseColor;
|
||||
}
|
||||
}
|
||||
border.color: (root.keyboardNavigation && root.selectedButton === 1) ? "white" : Qt.rgba(1, 1, 1, 0)
|
||||
border.color: (root.keyboardNavigation && root.selectedButton === 1) ? "white" : "transparent"
|
||||
border.width: (root.keyboardNavigation && root.selectedButton === 1) ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -157,7 +157,7 @@ Rectangle {
|
||||
width: actionContent.implicitWidth + Theme.spacingM * 2
|
||||
height: actionsRow.height
|
||||
radius: Theme.cornerRadius
|
||||
color: index === root.selectedActionIndex ? Theme.primaryHover : actionArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
|
||||
color: index === root.selectedActionIndex ? Theme.primaryHover : actionArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
Row {
|
||||
id: actionContent
|
||||
|
||||
@@ -43,7 +43,6 @@ Item {
|
||||
signal queryChanged(string query)
|
||||
signal viewModeChanged(string sectionId, string mode)
|
||||
signal searchQueryRequested(string query)
|
||||
signal sectionExpanded(string sectionId)
|
||||
|
||||
Ref {
|
||||
service: AppSearchService
|
||||
@@ -1875,9 +1874,6 @@ Item {
|
||||
selectedFlatIndex = getFirstItemIndex();
|
||||
}
|
||||
updateSelectedItem();
|
||||
|
||||
if (!newCollapsed[sectionId])
|
||||
sectionExpanded(sectionId);
|
||||
}
|
||||
|
||||
function executeSelected() {
|
||||
|
||||
@@ -63,8 +63,8 @@ Item {
|
||||
impl.item.toggleWithMode(mode);
|
||||
}
|
||||
|
||||
readonly property bool useSpotlightBackend: !FrameTransitionState.effectiveConnectedFrameModeActive && SettingsData.launcherStyle === "spotlight"
|
||||
readonly property var _desiredBackend: useSpotlightBackend ? spotlightComp : (FrameTransitionState.effectiveConnectedFrameModeActive ? connectedComp : standaloneComp)
|
||||
readonly property bool useSpotlightBackend: !SettingsData.connectedFrameModeActive && SettingsData.launcherStyle === "spotlight"
|
||||
readonly property var _desiredBackend: useSpotlightBackend ? spotlightComp : (SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp)
|
||||
property var _resolvedBackend: null
|
||||
|
||||
Component.onCompleted: _resolvedBackend = _desiredBackend
|
||||
|
||||
@@ -77,7 +77,7 @@ Item {
|
||||
|
||||
readonly property string preferredConnectedBarSide: SettingsData.frameLauncherEmergeSide
|
||||
|
||||
readonly property bool frameConnectedMode: FrameTransitionState.effectiveFrameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||
readonly property bool frameConnectedMode: SettingsData.frameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||
|
||||
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
||||
|
||||
@@ -168,7 +168,7 @@ Item {
|
||||
}
|
||||
}
|
||||
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0
|
||||
readonly property color effectiveBorderColor: connectedSurfaceOverride ? Theme.withAlpha(borderColor, 0) : borderColor
|
||||
readonly property color effectiveBorderColor: connectedSurfaceOverride ? "transparent" : borderColor
|
||||
readonly property int effectiveBorderWidth: connectedSurfaceOverride ? 0 : borderWidth
|
||||
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||
|
||||
@@ -359,10 +359,8 @@ Item {
|
||||
contentVisible = true;
|
||||
spotlightContent.closeTransientUi?.();
|
||||
|
||||
const targetQuery = query || (SettingsData.rememberLastQuery ? (SessionData.launcherLastQuery || "") : "");
|
||||
|
||||
if (spotlightContent.searchField) {
|
||||
spotlightContent.searchField.text = targetQuery;
|
||||
spotlightContent.searchField.text = query;
|
||||
}
|
||||
if (spotlightContent.controller) {
|
||||
var targetMode = mode || SessionData.getLauncherRestoreMode();
|
||||
@@ -377,8 +375,8 @@ Item {
|
||||
spotlightContent.controller.collapsedSections = {};
|
||||
spotlightContent.controller.selectedFlatIndex = 0;
|
||||
spotlightContent.controller.selectedItem = null;
|
||||
if (targetQuery) {
|
||||
spotlightContent.controller.setSearchQuery(targetQuery);
|
||||
if (query) {
|
||||
spotlightContent.controller.setSearchQuery(query);
|
||||
} else {
|
||||
spotlightContent.controller.searchQuery = "";
|
||||
spotlightContent.controller.performSearch();
|
||||
@@ -424,10 +422,8 @@ Item {
|
||||
|
||||
Qt.callLater(() => {
|
||||
root.keyboardActive = true;
|
||||
if (root.spotlightContent && root.spotlightContent.searchField) {
|
||||
if (root.spotlightContent && root.spotlightContent.searchField)
|
||||
root.spotlightContent.searchField.forceActiveFocus();
|
||||
root.spotlightContent.searchField.selectAll();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -534,9 +530,7 @@ Item {
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: focusGrab
|
||||
readonly property var contextMenuWindow: root.spotlightContent?.activeContextMenu?.contextWindow ?? null
|
||||
readonly property bool contextMenuActive: root.spotlightContent?.activeContextMenu?.renderActive ?? false
|
||||
windows: contextMenuActive && contextMenuWindow ? [contentWindow, contextMenuWindow] : [contentWindow]
|
||||
windows: [contentWindow]
|
||||
active: root.useHyprlandFocusGrab && root.spotlightOpen
|
||||
|
||||
onCleared: {
|
||||
@@ -803,8 +797,8 @@ Item {
|
||||
y: contentWrapper.y
|
||||
level: root.shadowLevel
|
||||
fallbackOffset: root.shadowFallbackOffset
|
||||
targetColor: root.frameOwnsConnectedChrome ? Theme.withAlpha(root.backgroundColor, 0) : root.backgroundColor
|
||||
borderColor: root.frameOwnsConnectedChrome ? Theme.withAlpha(root.effectiveBorderColor, 0) : root.effectiveBorderColor
|
||||
targetColor: root.frameOwnsConnectedChrome ? "transparent" : root.backgroundColor
|
||||
borderColor: root.frameOwnsConnectedChrome ? "transparent" : root.effectiveBorderColor
|
||||
borderWidth: root.frameOwnsConnectedChrome ? 0 : root.effectiveBorderWidth
|
||||
targetRadius: root.cornerRadius
|
||||
shadowEnabled: !root.frameOwnsConnectedChrome && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
||||
|
||||
@@ -30,7 +30,7 @@ Item {
|
||||
readonly property real screenWidth: effectiveScreen?.width ?? 1920
|
||||
readonly property real screenHeight: effectiveScreen?.height ?? 1080
|
||||
readonly property real dpr: effectiveScreen ? CompositorService.getScreenScale(effectiveScreen) : 1
|
||||
readonly property bool useBackgroundDarken: !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool useBackgroundDarken: !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
||||
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
||||
"allow": ["top", "overlay"],
|
||||
@@ -155,7 +155,7 @@ Item {
|
||||
}
|
||||
if (spotlightContent.searchField) {
|
||||
spotlightContent.searchField.forceActiveFocus();
|
||||
spotlightContent.searchField.selectAll();
|
||||
spotlightContent.searchField.cursorPosition = spotlightContent.searchField.text.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,9 +228,7 @@ Item {
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: focusGrab
|
||||
readonly property var contextMenuWindow: root.spotlightContent?.activeContextMenu?.contextWindow ?? null
|
||||
readonly property bool contextMenuActive: root.spotlightContent?.activeContextMenu?.renderActive ?? false
|
||||
windows: contextMenuActive && contextMenuWindow ? [launcherWindow, contextMenuWindow] : [launcherWindow]
|
||||
windows: [launcherWindow]
|
||||
active: root.useHyprlandFocusGrab && root.keyboardActive
|
||||
onCleared: {
|
||||
if (spotlightOpen)
|
||||
|
||||
@@ -79,7 +79,7 @@ Item {
|
||||
readonly property real windowHeight: alignedHeight + contentY + shadowPad
|
||||
|
||||
readonly property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
readonly property bool useBackgroundDarken: !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool useBackgroundDarken: !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
||||
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackgroundDarken
|
||||
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
||||
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
||||
@@ -139,7 +139,6 @@ Item {
|
||||
|
||||
if (spotlightContent.searchField) {
|
||||
spotlightContent.searchField.text = targetQuery;
|
||||
spotlightContent.searchField.selectAll();
|
||||
}
|
||||
if (spotlightContent.controller) {
|
||||
var targetMode = mode || SessionData.getLauncherRestoreMode();
|
||||
@@ -260,9 +259,7 @@ Item {
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: focusGrab
|
||||
readonly property var contextMenuWindow: root.spotlightContent?.activeContextMenu?.contextWindow ?? null
|
||||
readonly property bool contextMenuActive: root.spotlightContent?.activeContextMenu?.renderActive ?? false
|
||||
windows: contextMenuActive && contextMenuWindow ? [launcherWindow, contextMenuWindow] : [launcherWindow]
|
||||
windows: [launcherWindow]
|
||||
active: root.useHyprlandFocusGrab && root.keyboardActive
|
||||
|
||||
onCleared: {
|
||||
|
||||
@@ -36,7 +36,7 @@ Rectangle {
|
||||
readonly property int computedIconSize: Math.min(48, Math.max(32, width * 0.45))
|
||||
|
||||
radius: Theme.cornerRadius
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0)
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
|
||||
@@ -314,13 +314,9 @@ FocusScope {
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentHolder
|
||||
anchors.fill: parent
|
||||
visible: !editMode
|
||||
|
||||
readonly property bool inverted: (root.parentModal?.frameOwnsConnectedChrome ?? false) && (root.parentModal?.resolvedConnectedBarSide === "top")
|
||||
readonly property bool _connectedArcAtHeader: inverted && !(root.parentModal?.launcherArcExtenderActive ?? false)
|
||||
|
||||
Item {
|
||||
id: footerBar
|
||||
readonly property bool _connectedBottomEmerge: (root.parentModal?.frameOwnsConnectedChrome ?? false) && (root.parentModal?.resolvedConnectedBarSide === "bottom")
|
||||
@@ -329,10 +325,11 @@ FocusScope {
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.leftMargin: root.parentModal?.borderWidth ?? 1
|
||||
anchors.rightMargin: root.parentModal?.borderWidth ?? 1
|
||||
y: contentHolder.inverted ? 0 : (parent.height - height - (_connectedBottomEmerge ? 0 : (root.parentModal?.borderWidth ?? 1)))
|
||||
height: showFooter ? ((_connectedArcAtFooter || contentHolder._connectedArcAtHeader) ? 76 : 36) : 0
|
||||
anchors.bottomMargin: _connectedBottomEmerge ? 0 : (root.parentModal?.borderWidth ?? 1)
|
||||
height: showFooter ? (_connectedArcAtFooter ? 76 : 36) : 0
|
||||
visible: showFooter
|
||||
clip: true
|
||||
|
||||
@@ -351,7 +348,7 @@ FocusScope {
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
@@ -384,7 +381,7 @@ FocusScope {
|
||||
width: buttonContent.width + Theme.spacingM * 2
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
color: controller.searchMode === modelData.id ? Theme.buttonBg : modeArea.containsMouse ? Theme.surfaceContainerHighest : Theme.withAlpha(Theme.surfaceContainerHighest, 0)
|
||||
color: controller.searchMode === modelData.id ? Theme.buttonBg : modeArea.containsMouse ? Theme.surfaceContainerHighest : "transparent"
|
||||
|
||||
Row {
|
||||
id: buttonContent
|
||||
@@ -449,112 +446,105 @@ FocusScope {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: searchRow
|
||||
spacing: Theme.spacingS
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: footerBar.top
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
y: contentHolder.inverted ? (parent.height - height - Theme.spacingM) : Theme.spacingM
|
||||
|
||||
Rectangle {
|
||||
id: pluginBadge
|
||||
visible: controller.activePluginName.length > 0
|
||||
width: visible ? pluginBadgeContent.implicitWidth + Theme.spacingM : 0
|
||||
height: searchField.height
|
||||
radius: 16
|
||||
color: Theme.primary
|
||||
|
||||
Row {
|
||||
id: pluginBadgeContent
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: "extension"
|
||||
size: 14
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: controller.activePluginName
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primaryText
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
width: parent.width - (pluginBadge.visible ? pluginBadge.width + Theme.spacingS : 0)
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: root._launcherSearchFieldColor
|
||||
normalBorderColor: root._launcherSearchBorderColor
|
||||
focusedBorderColor: root._launcherSearchFocusedBorderColor
|
||||
borderWidth: 1
|
||||
focusedBorderWidth: 2
|
||||
leftIconName: controller.activePluginId ? "extension" : controller.searchQuery.startsWith("/") ? "folder" : "search"
|
||||
leftIconSize: Theme.iconSize
|
||||
leftIconColor: Theme.surfaceVariantText
|
||||
leftIconFocusedColor: Theme.primary
|
||||
showClearButton: true
|
||||
textColor: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: root.parentModal ? (root.parentModal.spotlightOpen || root.parentModal.isClosing) : true
|
||||
placeholderText: ""
|
||||
ignoreUpDownKeys: true
|
||||
ignoreTabKeys: true
|
||||
keyForwardTargets: [root]
|
||||
|
||||
onTextChanged: {
|
||||
controller.setSearchQuery(text);
|
||||
if (actionPanel.expanded) {
|
||||
actionPanel.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
if (root.parentModal) {
|
||||
root.parentModal.hide();
|
||||
}
|
||||
event.accepted = true;
|
||||
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter)) {
|
||||
if (actionPanel.expanded && actionPanel.selectedActionIndex > 0) {
|
||||
actionPanel.executeSelectedAction();
|
||||
} else {
|
||||
controller.executeSelected();
|
||||
}
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentStack
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: contentHolder.inverted ? footerBar.bottom : searchRow.bottom
|
||||
anchors.bottom: contentHolder.inverted ? searchRow.top : footerBar.top
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.topMargin: contentHolder.inverted && !footerBar.showFooter ? Theme.spacingM : contentStack.gap
|
||||
anchors.bottomMargin: contentHolder.inverted ? contentStack.gap : 0
|
||||
readonly property real gap: Theme.spacingXS
|
||||
anchors.topMargin: Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
clip: false
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
id: pluginBadge
|
||||
visible: controller.activePluginName.length > 0
|
||||
width: visible ? pluginBadgeContent.implicitWidth + Theme.spacingM : 0
|
||||
height: searchField.height
|
||||
radius: 16
|
||||
color: Theme.primary
|
||||
|
||||
Row {
|
||||
id: pluginBadgeContent
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: "extension"
|
||||
size: 14
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: controller.activePluginName
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primaryText
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
width: parent.width - (pluginBadge.visible ? pluginBadge.width + Theme.spacingS : 0)
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: root._launcherSearchFieldColor
|
||||
normalBorderColor: root._launcherSearchBorderColor
|
||||
focusedBorderColor: root._launcherSearchFocusedBorderColor
|
||||
borderWidth: 1
|
||||
focusedBorderWidth: 2
|
||||
leftIconName: controller.activePluginId ? "extension" : controller.searchQuery.startsWith("/") ? "folder" : "search"
|
||||
leftIconSize: Theme.iconSize
|
||||
leftIconColor: Theme.surfaceVariantText
|
||||
leftIconFocusedColor: Theme.primary
|
||||
showClearButton: true
|
||||
textColor: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: root.parentModal ? (root.parentModal.spotlightOpen || root.parentModal.isClosing) : true
|
||||
placeholderText: ""
|
||||
ignoreUpDownKeys: true
|
||||
ignoreTabKeys: true
|
||||
keyForwardTargets: [root]
|
||||
|
||||
onTextChanged: {
|
||||
controller.setSearchQuery(text);
|
||||
if (actionPanel.expanded) {
|
||||
actionPanel.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
if (root.parentModal) {
|
||||
root.parentModal.hide();
|
||||
}
|
||||
event.accepted = true;
|
||||
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter)) {
|
||||
if (actionPanel.expanded && actionPanel.selectedActionIndex > 0) {
|
||||
actionPanel.executeSelectedAction();
|
||||
} else {
|
||||
controller.executeSelected();
|
||||
}
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: categoryRow
|
||||
width: parent.width
|
||||
@@ -562,8 +552,6 @@ FocusScope {
|
||||
height: showPluginCategories ? 36 : 0
|
||||
visible: showPluginCategories
|
||||
spacing: Theme.spacingS
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
|
||||
clip: true
|
||||
|
||||
@@ -619,8 +607,6 @@ FocusScope {
|
||||
width: parent.width
|
||||
height: showFileFilters ? fileFilterContent.height : 0
|
||||
visible: showFileFilters
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
|
||||
readonly property bool showFileFilters: controller.searchMode === "files"
|
||||
|
||||
@@ -639,7 +625,7 @@ FocusScope {
|
||||
Row {
|
||||
id: typeChips
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
visible: DSearchService.supportsTypeFilter
|
||||
|
||||
Repeater {
|
||||
@@ -668,7 +654,7 @@ FocusScope {
|
||||
width: chipContent.width + Theme.spacingM * 2
|
||||
height: sortDropdown.height
|
||||
radius: Theme.cornerRadius
|
||||
color: controller.fileSearchType === modelData.id ? Theme.buttonBg : chipArea.containsMouse ? Theme.surfaceContainerHighest : Theme.withAlpha(Theme.surfaceContainerHighest, 0)
|
||||
color: controller.fileSearchType === modelData.id ? Theme.buttonBg : chipArea.containsMouse ? Theme.surfaceContainerHighest : "transparent"
|
||||
|
||||
Row {
|
||||
id: chipContent
|
||||
@@ -760,12 +746,8 @@ FocusScope {
|
||||
}
|
||||
|
||||
Item {
|
||||
id: resultsSlot
|
||||
width: parent.width
|
||||
anchors.top: fileFilterRow.visible ? fileFilterRow.bottom : (categoryRow.visible ? categoryRow.bottom : parent.top)
|
||||
anchors.topMargin: (fileFilterRow.visible || categoryRow.visible) ? contentStack.gap : 0
|
||||
anchors.bottom: actionPanel.top
|
||||
anchors.bottomMargin: actionPanel.height > 0 || !contentHolder.inverted ? contentStack.gap : 0
|
||||
height: parent.height - searchField.height - categoryRow.height - fileFilterRow.height - actionPanel.height - Theme.spacingXS * ((categoryRow.visible ? 1 : 0) + (fileFilterRow.visible ? 1 : 0) + 2)
|
||||
opacity: {
|
||||
if (!root.parentModal)
|
||||
return 1;
|
||||
@@ -778,7 +760,6 @@ FocusScope {
|
||||
id: resultsList
|
||||
anchors.fill: parent
|
||||
controller: root.controller
|
||||
leadingSectionHeaderAtBottom: contentHolder.inverted
|
||||
|
||||
onItemRightClicked: (index, item, sceneX, sceneY) => {
|
||||
if (item && contextMenu.hasContextMenuActions(item)) {
|
||||
@@ -792,7 +773,6 @@ FocusScope {
|
||||
ActionPanel {
|
||||
id: actionPanel
|
||||
width: parent.width
|
||||
anchors.bottom: parent.bottom
|
||||
selectedItem: controller.selectedItem
|
||||
controller: controller
|
||||
}
|
||||
@@ -848,7 +828,7 @@ FocusScope {
|
||||
width: 40
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: backButtonArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
|
||||
color: backButtonArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -878,7 +858,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Edit App")
|
||||
@@ -915,7 +895,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Name")
|
||||
@@ -935,7 +915,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Icon")
|
||||
@@ -955,7 +935,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Description")
|
||||
@@ -975,7 +955,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Environment Variables")
|
||||
@@ -1001,7 +981,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Extra Arguments")
|
||||
@@ -1080,7 +1060,7 @@ FocusScope {
|
||||
width: 90
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: saveButtonArea.containsMouse ? Theme.withAlpha(Theme.primary, 0.9) : Theme.primary
|
||||
color: saveButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.9) : Theme.primary
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Save")
|
||||
|
||||
@@ -25,7 +25,6 @@ Item {
|
||||
property real anchorY: 0
|
||||
property bool openState: false
|
||||
property bool renderActive: false
|
||||
readonly property alias contextWindow: menuWindow
|
||||
readonly property bool blurActive: renderActive && openState && BlurService.enabled && Theme.connectedSurfaceBlurEnabled
|
||||
|
||||
readonly property real minMenuWidth: 180
|
||||
@@ -447,17 +446,7 @@ Item {
|
||||
WlrLayershell.namespace: "dms:launcher-context-menu"
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
// Hyprland steals the launcher's focus grab on exclusive focus; keep keys on the
|
||||
// launcher window, which forwards them to the menu via handleKey().
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (PopoutManager.screenshotActive)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (!root.renderActive)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (CompositorService.useHyprlandFocusGrab)
|
||||
return WlrKeyboardFocus.None;
|
||||
return WlrKeyboardFocus.Exclusive;
|
||||
}
|
||||
WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (root.renderActive ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None)
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
@@ -518,7 +507,7 @@ Item {
|
||||
height: root.effectiveMenuHeight
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: BlurService.enabled ? BlurService.borderWidth : 1
|
||||
opacity: root.openState ? 1 : 0
|
||||
|
||||
@@ -596,7 +585,7 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineHeavy
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,9 +596,9 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (root.keyboardNavigation && root.selectedMenuIndex === menuItemDelegate.itemIndex) {
|
||||
return Theme.primaryPressed;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
|
||||
}
|
||||
return itemMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(BlurService.hoverColor(Theme.widgetBaseHoverColor), 0);
|
||||
return itemMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent";
|
||||
}
|
||||
|
||||
Row {
|
||||
|
||||
@@ -37,7 +37,7 @@ Rectangle {
|
||||
|
||||
width: parent?.width ?? 200
|
||||
height: 52
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0)
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
DankRipple {
|
||||
@@ -170,7 +170,7 @@ Rectangle {
|
||||
height: 28
|
||||
radius: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: allModeToggleArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
|
||||
color: allModeToggleArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
property bool isAllowed: {
|
||||
if (root.item?.type !== "plugin_browse")
|
||||
|
||||
@@ -11,11 +11,9 @@ Item {
|
||||
|
||||
property var controller: null
|
||||
property int gridColumns: controller?.gridColumns ?? 4
|
||||
property bool leadingSectionHeaderAtBottom: false
|
||||
property var _visualRows: []
|
||||
property var _flatIndexToRowMap: ({})
|
||||
property var _cumulativeHeights: []
|
||||
readonly property bool _bottomSectionHeaderActive: leadingSectionHeaderAtBottom && (controller?.sections?.length ?? 0) > 0
|
||||
|
||||
signal itemRightClicked(int index, var item, real mouseX, real mouseY)
|
||||
|
||||
@@ -30,17 +28,15 @@ Item {
|
||||
var section = sections[s];
|
||||
var sectionId = section.id;
|
||||
|
||||
if (!root._bottomSectionHeaderActive || s > 0) {
|
||||
cumHeights.push(cumY);
|
||||
rows.push({
|
||||
_rowId: "h_" + sectionId,
|
||||
type: "header",
|
||||
section: section,
|
||||
sectionId: sectionId,
|
||||
height: 32
|
||||
});
|
||||
cumY += 32;
|
||||
}
|
||||
cumHeights.push(cumY);
|
||||
rows.push({
|
||||
_rowId: "h_" + sectionId,
|
||||
type: "header",
|
||||
section: section,
|
||||
sectionId: sectionId,
|
||||
height: 32
|
||||
});
|
||||
cumY += 32;
|
||||
|
||||
if (section.collapsed)
|
||||
continue;
|
||||
@@ -107,7 +103,6 @@ Item {
|
||||
|
||||
onGridColumnsChanged: Qt.callLater(_rebuildVisualModel)
|
||||
onWidthChanged: Qt.callLater(_rebuildVisualModel)
|
||||
onLeadingSectionHeaderAtBottomChanged: Qt.callLater(_rebuildVisualModel)
|
||||
|
||||
Connections {
|
||||
target: root.controller
|
||||
@@ -122,27 +117,12 @@ Item {
|
||||
root._cumulativeHeights = [];
|
||||
root._flatIndexToRowMap = {};
|
||||
}
|
||||
function onSectionExpanded(sectionId) {
|
||||
Qt.callLater(() => {
|
||||
root._rebuildVisualModel();
|
||||
Qt.callLater(() => root.revealExpandedSection(sectionId));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resetScroll() {
|
||||
mainListView.contentY = mainListView.originY;
|
||||
}
|
||||
|
||||
function revealExpandedSection(sectionId) {
|
||||
for (var i = 0; i < _visualRows.length; i++) {
|
||||
if (_visualRows[i].sectionId === sectionId) {
|
||||
mainListView.positionViewAtIndex(i, ListView.Beginning);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || !controller?.flatModel || index >= controller.flatModel.length)
|
||||
return;
|
||||
@@ -214,7 +194,6 @@ Item {
|
||||
id: listClip
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: BlurService.enabled && stickyHeader.visible ? 32 : 0
|
||||
anchors.bottomMargin: bottomSectionHeader.visible ? bottomSectionHeader.height : 0
|
||||
clip: true
|
||||
|
||||
DankListView {
|
||||
@@ -353,7 +332,6 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: bottomSectionHeader.visible ? bottomSectionHeader.height : 0
|
||||
height: 24
|
||||
z: 100
|
||||
visible: {
|
||||
@@ -399,7 +377,7 @@ Item {
|
||||
height: 32
|
||||
z: 101
|
||||
color: Theme.floatingSurface
|
||||
visible: !root._bottomSectionHeaderActive && stickyHeaderSection !== null
|
||||
visible: stickyHeaderSection !== null
|
||||
|
||||
readonly property int versionTrigger: root.controller?.viewModeVersion ?? 0
|
||||
|
||||
@@ -450,30 +428,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
SectionHeader {
|
||||
id: bottomSectionHeader
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
z: 101
|
||||
visible: root._bottomSectionHeaderActive
|
||||
section: visible ? root.controller.sections[0] : null
|
||||
controller: root.controller
|
||||
viewMode: {
|
||||
var vt = root.controller?.viewModeVersion ?? 0;
|
||||
void (vt);
|
||||
return root.controller?.getSectionViewMode(section?.id ?? "") ?? "list";
|
||||
}
|
||||
canChangeViewMode: {
|
||||
var vt = root.controller?.viewModeVersion ?? 0;
|
||||
void (vt);
|
||||
return root.controller?.canChangeSectionViewMode(section?.id ?? "") ?? false;
|
||||
}
|
||||
canCollapse: root.controller?.canCollapseSection(section?.id ?? "") ?? false
|
||||
isSticky: true
|
||||
popupAbove: true
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.centerIn: parent
|
||||
visible: (!root.controller?.sections || root.controller.sections.length === 0) && !root.controller?.isFileSearching
|
||||
|
||||
@@ -50,7 +50,7 @@ Item {
|
||||
id: listComponent
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
width: contentLoader.width
|
||||
|
||||
Repeater {
|
||||
@@ -83,7 +83,7 @@ Item {
|
||||
|
||||
Flow {
|
||||
width: contentLoader.width
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
|
||||
@@ -15,14 +15,12 @@ Rectangle {
|
||||
property bool canChangeViewMode: true
|
||||
property bool canCollapse: true
|
||||
property bool isSticky: false
|
||||
property bool popupAbove: false
|
||||
property Item popupAboveItem: null
|
||||
|
||||
signal viewModeToggled
|
||||
|
||||
width: parent?.width ?? 200
|
||||
height: 32
|
||||
color: isSticky ? Theme.withAlpha(Theme.surfaceHover, 0) : (hoverArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0))
|
||||
color: isSticky ? "transparent" : (hoverArea.containsMouse ? Theme.surfaceHover : "transparent")
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
MouseArea {
|
||||
@@ -83,7 +81,7 @@ Rectangle {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: chipArea.containsMouse || categoryPopup.visible ? Theme.surfaceContainerHigh : Theme.withAlpha(Theme.surfaceContainerHigh, 0)
|
||||
color: chipArea.containsMouse || categoryPopup.visible ? Theme.surfaceContainerHigh : "transparent"
|
||||
border.color: categoryPopup.visible ? Theme.primary : Theme.outlineMedium
|
||||
border.width: categoryPopup.visible ? 2 : 1
|
||||
}
|
||||
@@ -124,10 +122,9 @@ Rectangle {
|
||||
if (categoryPopup.visible) {
|
||||
categoryPopup.close();
|
||||
} else {
|
||||
const chipPos = categoryChip.mapToItem(Overlay.overlay, 0, 0);
|
||||
const abovePos = (root.popupAboveItem ?? categoryChip).mapToItem(Overlay.overlay, 0, 0);
|
||||
categoryPopup.x = chipPos.x;
|
||||
categoryPopup.y = root.popupAbove ? abovePos.y - categoryPopup.height - 4 : chipPos.y + categoryChip.height + 4;
|
||||
const pos = categoryChip.mapToItem(Overlay.overlay, 0, 0);
|
||||
categoryPopup.x = pos.x;
|
||||
categoryPopup.y = pos.y + categoryChip.height + 4;
|
||||
categoryPopup.open();
|
||||
}
|
||||
}
|
||||
@@ -148,7 +145,7 @@ Rectangle {
|
||||
|
||||
contentItem: Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, 1)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
|
||||
@@ -169,7 +166,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
model: root.controller?.appCategories ?? []
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
clip: true
|
||||
interactive: contentHeight > height
|
||||
implicitHeight: contentHeight
|
||||
@@ -182,7 +179,7 @@ Rectangle {
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
readonly property bool isCurrent: categoryChip.currentCategory === modelData
|
||||
color: isCurrent ? Theme.primaryHover : catArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0)
|
||||
color: isCurrent ? Theme.primaryHover : catArea.containsMouse ? Theme.primaryHoverLight : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -246,7 +243,7 @@ Rectangle {
|
||||
Row {
|
||||
id: viewModeRow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
visible: root.canChangeViewMode && !root.section?.collapsed
|
||||
|
||||
Repeater {
|
||||
@@ -272,7 +269,7 @@ Rectangle {
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 4
|
||||
color: root.viewMode === modelData.mode ? Theme.primaryHover : modeArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
|
||||
color: root.viewMode === modelData.mode ? Theme.primaryHover : modeArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -328,7 +325,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: rightContent.width + Theme.spacingS
|
||||
cursorShape: root.canCollapse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: root.canCollapse && !leftContent.hasAppCategories
|
||||
enabled: root.canCollapse
|
||||
onClicked: {
|
||||
if (root.canCollapse && root.controller && root.section) {
|
||||
root.controller.toggleSection(root.section.id);
|
||||
|
||||
@@ -76,7 +76,7 @@ Rectangle {
|
||||
width: parent?.width ?? 200
|
||||
height: 64
|
||||
radius: Theme.cornerRadius
|
||||
color: root.isSelected ? Theme.primaryPressed : root.isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0)
|
||||
color: root.isSelected ? Theme.primaryPressed : root.isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
@@ -150,7 +150,7 @@ Rectangle {
|
||||
anchors.right: previewFrame.visible ? previewFrame.left : metaRow.left
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
@@ -225,7 +225,7 @@ Rectangle {
|
||||
height: 28
|
||||
radius: height / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: quickToggleArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
|
||||
color: quickToggleArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
readonly property bool isAllowed: {
|
||||
if (root.item?.type !== "plugin_browse")
|
||||
|
||||
@@ -143,7 +143,7 @@ Item {
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Math.min(420, root.width - 88)
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
|
||||
@@ -19,7 +19,7 @@ Rectangle {
|
||||
signal rightClicked(real mouseX, real mouseY)
|
||||
|
||||
radius: Theme.cornerRadius
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryPressed : Theme.withAlpha(Theme.primaryPressed, 0)
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryPressed : "transparent"
|
||||
border.width: isSelected ? 2 : 0
|
||||
border.color: Theme.primary
|
||||
|
||||
@@ -93,7 +93,7 @@ Rectangle {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.isHovered ? Theme.withAlpha(Theme.surfaceVariant, 0.2) : Theme.withAlpha(Theme.surfaceVariant, 0)
|
||||
color: root.isHovered ? Theme.withAlpha(Theme.surfaceVariant, 0.2) : "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ Rectangle {
|
||||
width: root.hasScreencopy ? 28 : 40
|
||||
height: root.hasScreencopy ? 28 : 16
|
||||
radius: root.hasScreencopy ? 14 : 4
|
||||
color: root.hasScreencopy ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, 0)
|
||||
color: root.hasScreencopy ? Theme.surfaceContainer : "transparent"
|
||||
visible: attributionImage.status === Image.Ready
|
||||
opacity: 0.95
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ DankModal {
|
||||
width: Math.max(70, revertText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: revertArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: revertArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
|
||||
|
||||
@@ -804,7 +804,7 @@ FocusScope {
|
||||
anchors.topMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
visible: viewMode === "list"
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
model: folderModel
|
||||
currentIndex: selectedIndex
|
||||
onCurrentIndexChanged: {
|
||||
|
||||
@@ -136,9 +136,9 @@ StyledRect {
|
||||
if (keyboardNavigationActive && delegateRoot.index === selectedIndex)
|
||||
return Theme.surfacePressed;
|
||||
|
||||
return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : Theme.withAlpha(Theme.surfaceContainerHigh, 0);
|
||||
return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent";
|
||||
}
|
||||
border.color: keyboardNavigationActive && delegateRoot.index === selectedIndex ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: keyboardNavigationActive && delegateRoot.index === selectedIndex ? Theme.primary : "transparent"
|
||||
border.width: (keyboardNavigationActive && delegateRoot.index === selectedIndex) ? 2 : 0
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
@@ -89,7 +89,7 @@ Popup {
|
||||
contentItem: Rectangle {
|
||||
color: Theme.floatingSurface
|
||||
radius: Theme.cornerRadius
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium
|
||||
border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: BlurService.enabled ? BlurService.borderWidth : 1
|
||||
|
||||
Column {
|
||||
@@ -110,7 +110,7 @@ Popup {
|
||||
if (!modelData.enabled || !area.containsMouse)
|
||||
return "transparent";
|
||||
if (modelData.dangerous)
|
||||
return Theme.errorHover;
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
|
||||
return BlurService.hoverColor(Theme.widgetBaseHoverColor);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,9 @@ StyledRect {
|
||||
color: {
|
||||
if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)
|
||||
return Theme.surfacePressed;
|
||||
return listMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : Theme.withAlpha(Theme.surfaceContainerHigh, 0);
|
||||
return listMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent";
|
||||
}
|
||||
border.color: keyboardNavigationActive && listDelegateRoot.index === selectedIndex ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: keyboardNavigationActive && listDelegateRoot.index === selectedIndex ? Theme.primary : "transparent"
|
||||
border.width: (keyboardNavigationActive && listDelegateRoot.index === selectedIndex) ? 2 : 0
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
@@ -41,8 +41,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: close()
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
if (parentModal && "shouldHaveFocus" in parentModal) {
|
||||
|
||||
@@ -26,7 +26,7 @@ Row {
|
||||
width: 32
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: (backButtonMouseArea.containsMouse || (backButtonFocused && keyboardNavigationActive)) && currentPath !== homeDir ? Theme.surfaceVariant : Theme.withAlpha(Theme.surfaceVariant, 0)
|
||||
color: (backButtonMouseArea.containsMouse || (backButtonFocused && keyboardNavigationActive)) && currentPath !== homeDir ? Theme.surfaceVariant : "transparent"
|
||||
opacity: currentPath !== homeDir ? 1 : 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -56,8 +56,8 @@ Row {
|
||||
StyledRect {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: pathEditMode ? Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) : Theme.withAlpha(Theme.surfaceContainer, 0)
|
||||
border.color: pathEditMode ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
color: pathEditMode ? Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) : "transparent"
|
||||
border.color: pathEditMode ? Theme.primary : "transparent"
|
||||
border.width: pathEditMode ? 1 : 0
|
||||
visible: !pathEditMode
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ StyledRect {
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Quick Access")
|
||||
@@ -34,7 +34,7 @@ StyledRect {
|
||||
width: parent?.width ?? 0
|
||||
height: 38
|
||||
radius: Theme.cornerRadius
|
||||
color: quickAccessMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : (currentPath === modelData?.path ? Theme.surfacePressed : Theme.withAlpha(Theme.surfacePressed, 0))
|
||||
color: quickAccessMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : (currentPath === modelData?.path ? Theme.surfacePressed : "transparent")
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -60,7 +60,7 @@ StyledRect {
|
||||
width: sortColumn?.width ?? 0
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: sortMouseArea.containsMouse ? Theme.surfaceVariant : (sortBy === modelData?.value ? Theme.surfacePressed : Theme.withAlpha(Theme.surfacePressed, 0))
|
||||
color: sortMouseArea.containsMouse ? Theme.surfaceVariant : (sortBy === modelData?.value ? Theme.surfacePressed : "transparent")
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
@@ -114,7 +114,7 @@ StyledRect {
|
||||
width: sortColumn?.width ?? 0
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: ascMouseArea.containsMouse ? Theme.surfaceVariant : (sortAscending ? Theme.surfacePressed : Theme.withAlpha(Theme.surfacePressed, 0))
|
||||
color: ascMouseArea.containsMouse ? Theme.surfaceVariant : (sortAscending ? Theme.surfacePressed : "transparent")
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
@@ -152,7 +152,7 @@ StyledRect {
|
||||
width: sortColumn?.width ?? 0
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: descMouseArea.containsMouse ? Theme.surfaceVariant : (!sortAscending ? Theme.surfacePressed : Theme.withAlpha(Theme.surfacePressed, 0))
|
||||
color: descMouseArea.containsMouse ? Theme.surfaceVariant : (!sortAscending ? Theme.surfacePressed : "transparent")
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -13,7 +13,7 @@ Rectangle {
|
||||
|
||||
height: 200
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, 0.95)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
border.color: Theme.secondary
|
||||
border.width: 2
|
||||
opacity: showFileInfo ? 1 : 0
|
||||
|
||||
@@ -9,7 +9,7 @@ Rectangle {
|
||||
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, 0.95)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
opacity: showHints ? 1 : 0
|
||||
@@ -20,7 +20,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select")
|
||||
|
||||
@@ -99,7 +99,7 @@ Item {
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("You're All Set!", "greeter completion page title")
|
||||
|
||||
@@ -209,7 +209,7 @@ Item {
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System Check", "greeter doctor page title")
|
||||
|
||||
@@ -45,7 +45,7 @@ Rectangle {
|
||||
|
||||
Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: root.title
|
||||
|
||||
@@ -93,8 +93,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: visible = false
|
||||
|
||||
Process {
|
||||
id: cheatsheetProcess
|
||||
running: false
|
||||
|
||||
@@ -48,7 +48,7 @@ Rectangle {
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
width: parent.width - root.iconContainerSize - Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -18,7 +18,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: bgColor
|
||||
border.width: selected ? 2 : 0
|
||||
border.color: selected ? iconColor : Theme.withAlpha(iconColor, 0)
|
||||
border.color: selected ? iconColor : "transparent"
|
||||
scale: mouseArea.pressed ? 0.97 : 1
|
||||
|
||||
Behavior on scale {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -147,7 +148,8 @@ Item {
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Control Center", "greeter feature card title")
|
||||
description: I18n.tr("Quick system toggles", "greeter feature card description")
|
||||
onClicked: BarWidgetService.getBarWindowOnFocusedScreen()?.triggerControlCenter()
|
||||
// This is doing an IPC since its just easier and lazier to access the bar ref
|
||||
onClicked: Quickshell.execDetached(["dms", "ipc", "call", "control-center", "open"])
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
|
||||
@@ -361,7 +361,7 @@ DankModal {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("New Session")
|
||||
@@ -414,7 +414,7 @@ DankModal {
|
||||
width: parent.width
|
||||
height: 64
|
||||
radius: Theme.cornerRadius
|
||||
color: muxModal.selectedIndex === index ? Theme.primaryContainer : (sessionMouse.containsMouse ? Theme.surfaceContainerHigh : Theme.withAlpha(Theme.surfaceContainerHigh, 0))
|
||||
color: muxModal.selectedIndex === index ? Theme.primaryContainer : (sessionMouse.containsMouse ? Theme.surfaceContainerHigh : "transparent")
|
||||
|
||||
MouseArea {
|
||||
id: sessionMouse
|
||||
@@ -449,7 +449,7 @@ DankModal {
|
||||
// Info
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: modelData.name
|
||||
@@ -478,7 +478,7 @@ DankModal {
|
||||
Layout.preferredHeight: 36
|
||||
radius: 18
|
||||
visible: MuxService.supportsRename
|
||||
color: renameMouse.containsMouse ? Theme.surfaceContainerHighest : Theme.withAlpha(Theme.surfaceContainerHighest, 0)
|
||||
color: renameMouse.containsMouse ? Theme.surfaceContainerHighest : "transparent"
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -501,7 +501,7 @@ DankModal {
|
||||
Layout.preferredWidth: 36
|
||||
Layout.preferredHeight: 36
|
||||
radius: 18
|
||||
color: deleteMouse.containsMouse ? Theme.errorContainer : Theme.withAlpha(Theme.errorContainer, 0)
|
||||
color: deleteMouse.containsMouse ? Theme.errorContainer : "transparent"
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -601,7 +601,7 @@ DankModal {
|
||||
|
||||
delegate: Row {
|
||||
required property var modelData
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
Rectangle {
|
||||
width: keyText.width + Theme.spacingS
|
||||
|
||||
@@ -314,7 +314,7 @@ FocusScope {
|
||||
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
enabled: !root.isLoading
|
||||
|
||||
@@ -32,8 +32,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: hide()
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
Qt.callLater(focusContent);
|
||||
|
||||
@@ -551,12 +551,12 @@ DankModal {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected)
|
||||
return Theme.primaryHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
if (mouseArea.containsMouse)
|
||||
return Theme.primaryHoverLight;
|
||||
return Theme.surfaceHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||
}
|
||||
border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: isSelected ? Theme.primary : "transparent"
|
||||
border.width: isSelected ? 2 : 0
|
||||
|
||||
Rectangle {
|
||||
@@ -585,10 +585,10 @@ DankModal {
|
||||
width: parent.width * root.holdProgress
|
||||
color: {
|
||||
if (gridButtonRect.modelData === "poweroff")
|
||||
return Theme.errorSelected;
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
|
||||
if (gridButtonRect.modelData === "reboot")
|
||||
return Theme.withAlpha(Theme.warning, 0.3);
|
||||
return Theme.primarySelected;
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3);
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -626,13 +626,13 @@ DankModal {
|
||||
width: 20
|
||||
height: 16
|
||||
radius: 4
|
||||
color: Theme.onSurface_12
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: gridButtonRect.actionData.key
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceTextSecondary
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -688,12 +688,12 @@ DankModal {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected)
|
||||
return Theme.primaryHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
if (listMouseArea.containsMouse)
|
||||
return Theme.primaryHoverLight;
|
||||
return Theme.surfaceHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||
}
|
||||
border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
border.color: isSelected ? Theme.primary : "transparent"
|
||||
border.width: isSelected ? 2 : 0
|
||||
|
||||
Rectangle {
|
||||
@@ -722,10 +722,10 @@ DankModal {
|
||||
width: parent.width * root.holdProgress
|
||||
color: {
|
||||
if (listButtonRect.modelData === "poweroff")
|
||||
return Theme.errorSelected;
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
|
||||
if (listButtonRect.modelData === "reboot")
|
||||
return Theme.withAlpha(Theme.warning, 0.3);
|
||||
return Theme.primarySelected;
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3);
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -770,7 +770,7 @@ DankModal {
|
||||
width: 28
|
||||
height: 20
|
||||
radius: 4
|
||||
color: Theme.onSurface_12
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1)
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Theme.spacingM
|
||||
@@ -780,7 +780,7 @@ DankModal {
|
||||
StyledText {
|
||||
text: listButtonRect.actionData.key
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextSecondary
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -820,7 +820,7 @@ DankModal {
|
||||
DankIcon {
|
||||
name: root.showHoldHint ? "warning" : "touch_app"
|
||||
size: Theme.fontSizeSmall
|
||||
color: root.showHoldHint ? Theme.warning : Theme.surfaceTextSecondary
|
||||
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
@@ -840,7 +840,7 @@ DankModal {
|
||||
return I18n.tr("Hold to confirm (%1s)").arg(SettingsData.powerActionHoldDuration);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: root.showHoldHint ? Theme.warning : Theme.surfaceTextSecondary
|
||||
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,15 +174,15 @@ DankModal {
|
||||
|
||||
color: {
|
||||
if (isActive)
|
||||
return Theme.primaryPressed;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16);
|
||||
if (isSelected)
|
||||
return Theme.primaryHoverLight;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||
if (mouseArea.containsMouse)
|
||||
return Theme.surfacePressed;
|
||||
return Theme.surfaceHover;
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12);
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.06);
|
||||
}
|
||||
|
||||
border.color: isActive ? Theme.primary : (isSelected ? Theme.withAlpha(Theme.primary, 0.5) : Theme.withAlpha(Theme.primary, 0))
|
||||
border.color: isActive ? Theme.primary : (isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5) : "transparent")
|
||||
border.width: (isActive || isSelected) ? 2 : 0
|
||||
|
||||
// Shortcut Key Badge on Top-Right Corner
|
||||
@@ -193,8 +193,8 @@ DankModal {
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 4
|
||||
color: isActive ? Theme.primaryPressed : Theme.surfaceTextHover
|
||||
border.color: isActive ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
color: isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||
border.color: isActive ? Theme.primary : "transparent"
|
||||
border.width: isActive ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -48,22 +48,19 @@ FloatingWindow {
|
||||
log.warn("dgop is not available");
|
||||
return;
|
||||
}
|
||||
if (!visible) {
|
||||
show();
|
||||
return;
|
||||
}
|
||||
const modalTitle = I18n.tr("System Monitor", "sysmon window title");
|
||||
for (const toplevel of ToplevelManager.toplevels.values) {
|
||||
if (toplevel.title !== "System Monitor" && toplevel.title !== modalTitle)
|
||||
continue;
|
||||
if (toplevel.activated) {
|
||||
hide();
|
||||
if (visible) {
|
||||
const modalTitle = I18n.tr("System Monitor", "sysmon window title");
|
||||
for (const toplevel of ToplevelManager.toplevels.values) {
|
||||
if (toplevel.title !== "System Monitor" && toplevel.title !== modalTitle)
|
||||
continue;
|
||||
if (toplevel.activated) {
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
toplevel.activate();
|
||||
return;
|
||||
}
|
||||
toplevel.activate();
|
||||
return;
|
||||
}
|
||||
hide();
|
||||
show();
|
||||
}
|
||||
|
||||
@@ -93,8 +90,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: hide()
|
||||
|
||||
onCurrentTabChanged: {
|
||||
if (visible && currentTab === 0 && searchField.visible)
|
||||
searchField.forceActiveFocus();
|
||||
@@ -200,7 +195,7 @@ FloatingWindow {
|
||||
width: 400
|
||||
height: 200
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.errorHover
|
||||
color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1)
|
||||
border.color: Theme.error
|
||||
border.width: 2
|
||||
visible: !DgopService.dgopAvailable
|
||||
@@ -305,7 +300,7 @@ FloatingWindow {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
@@ -331,8 +326,8 @@ FloatingWindow {
|
||||
width: tabRowContent.implicitWidth + Theme.spacingM * 2
|
||||
height: Math.round(Theme.fontSizeMedium * 3.1)
|
||||
radius: Theme.cornerRadius
|
||||
color: currentTab === index ? Theme.primaryPressed : (tabMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0))
|
||||
border.color: currentTab === index ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
color: currentTab === index ? Theme.primaryPressed : (tabMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent")
|
||||
border.color: currentTab === index ? Theme.primary : "transparent"
|
||||
border.width: currentTab === index ? 1 : 0
|
||||
|
||||
Row {
|
||||
|
||||
@@ -52,7 +52,7 @@ Rectangle {
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
|
||||
@@ -434,9 +434,7 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: MediaPlayerTab {
|
||||
parentModal: root.parentModal
|
||||
}
|
||||
sourceComponent: MediaPlayerTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item)
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
FloatingWindow {
|
||||
id: settingsModal
|
||||
|
||||
property bool disablePopupTransparency: true
|
||||
property var profileBrowser: profileBrowserLoader.item
|
||||
property var wallpaperBrowser: wallpaperBrowserLoader.item
|
||||
|
||||
@@ -92,8 +93,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: hide()
|
||||
|
||||
onIsCompactModeChanged: {
|
||||
enableAnimations = false;
|
||||
if (!isCompactMode) {
|
||||
@@ -174,8 +173,6 @@ FloatingWindow {
|
||||
FocusScope {
|
||||
id: contentFocusScope
|
||||
|
||||
property bool disablePopupTransparency: true
|
||||
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
|
||||
@@ -711,7 +711,7 @@ Rectangle {
|
||||
rightPadding: Theme.spacingS
|
||||
bottomPadding: Theme.spacingL
|
||||
topPadding: Theme.spacingM + 2
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
ProfileSection {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
@@ -804,7 +804,7 @@ Rectangle {
|
||||
Column {
|
||||
id: searchResultsColumn
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
visible: root.searchActive
|
||||
|
||||
Item {
|
||||
@@ -859,7 +859,7 @@ Rectangle {
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: resultDelegate.modelData.label
|
||||
@@ -928,7 +928,7 @@ Rectangle {
|
||||
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
visible: !root.searchActive && root.isCategoryVisible(modelData)
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
@@ -1035,7 +1035,7 @@ Rectangle {
|
||||
Column {
|
||||
id: childrenColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
visible: categoryDelegate.modelData.children !== undefined && root.isCategoryExpanded(categoryDelegate.modelData.id)
|
||||
clip: true
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ DankModal {
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - 4 - chevron.width - Theme.spacingM * 2
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
@@ -215,7 +215,7 @@ DankModal {
|
||||
Column {
|
||||
id: bodyCol
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("No other active sessions on this seat")
|
||||
|
||||
@@ -626,7 +626,7 @@ DankModal {
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 4
|
||||
color: checked ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||
color: checked ? Theme.primary : "transparent"
|
||||
border.color: checked ? Theme.primary : Theme.outlineButton
|
||||
border.width: 2
|
||||
|
||||
@@ -667,7 +667,7 @@ DankModal {
|
||||
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: hide()
|
||||
|
||||
function resetForm() {
|
||||
nameInput.text = "";
|
||||
appIdInput.text = "";
|
||||
@@ -506,7 +504,7 @@ FloatingWindow {
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 4
|
||||
color: parent.indeterminate ? Theme.surfaceVariant : (checked ? Theme.primary : Theme.withAlpha(Theme.primary, 0))
|
||||
color: parent.indeterminate ? Theme.surfaceVariant : (checked ? Theme.primary : "transparent")
|
||||
border.color: parent.indeterminate ? Theme.outlineButton : (checked ? Theme.primary : Theme.outlineButton)
|
||||
border.width: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -1843,7 +1841,7 @@ FloatingWindow {
|
||||
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ FloatingWindow {
|
||||
color: Theme.surfaceContainer
|
||||
visible: false
|
||||
|
||||
onClosed: hide()
|
||||
|
||||
function show(name) {
|
||||
nameInput.text = name;
|
||||
visible = true;
|
||||
@@ -153,7 +151,7 @@ FloatingWindow {
|
||||
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
border.color: Theme.surfaceVariantAlpha
|
||||
border.width: 1
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
@@ -93,15 +92,6 @@ Item {
|
||||
precision: root.needsSeconds ? SystemClock.Seconds : SystemClock.Minutes
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
|
||||
function onSessionResumed() {
|
||||
systemClock.enabled = false;
|
||||
systemClock.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
@@ -405,8 +405,8 @@ Item {
|
||||
|
||||
var c = root.accentColor;
|
||||
var grad = ctx.createLinearGradient(0, 0, 0, height);
|
||||
grad.addColorStop(0, Theme.withAlpha(c, 0.3));
|
||||
grad.addColorStop(1, Theme.withAlpha(c, 0.05));
|
||||
grad.addColorStop(0, Qt.rgba(c.r, c.g, c.b, 0.3));
|
||||
grad.addColorStop(1, Qt.rgba(c.r, c.g, c.b, 0.05));
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.beginPath();
|
||||
@@ -420,7 +420,7 @@ Item {
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.strokeStyle = Theme.withAlpha(c, 0.6);
|
||||
ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.6);
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.beginPath();
|
||||
for (var j = 0; j < hist.length; j++) {
|
||||
@@ -431,7 +431,7 @@ Item {
|
||||
ctx.stroke();
|
||||
|
||||
if (hist2 && hist2.length >= 2) {
|
||||
ctx.strokeStyle = Theme.withAlpha(c, 0.3);
|
||||
ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.3);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
for (var m = 0; m < hist2.length; m++) {
|
||||
@@ -447,7 +447,7 @@ Item {
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -206,7 +206,7 @@ PluginComponent {
|
||||
Rectangle {
|
||||
height: 1
|
||||
width: parent.width
|
||||
color: Theme.outlineStrong
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
@@ -274,7 +274,7 @@ PluginComponent {
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ PluginComponent {
|
||||
width: autoLabel.implicitWidth + Theme.spacingL * 2
|
||||
height: 28
|
||||
radius: 14
|
||||
color: root.autoMode ? Theme.primaryPressed : (autoMouseArea.containsMouse ? Theme.surfaceLight : Theme.withAlpha(Theme.surfaceLight, 0))
|
||||
color: root.autoMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : (autoMouseArea.containsMouse ? Theme.surfaceLight : "transparent")
|
||||
border.color: root.autoMode ? Theme.primary : Theme.outlineMedium
|
||||
border.width: root.autoMode ? 1 : Theme.layerOutlineWidth
|
||||
|
||||
@@ -170,7 +170,7 @@ PluginComponent {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isActive)
|
||||
return Theme.primaryHover;
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
if (profileMouseArea.containsMouse)
|
||||
return Theme.surfaceLight;
|
||||
return Theme.floatingSurface;
|
||||
@@ -234,7 +234,7 @@ PluginComponent {
|
||||
|
||||
verticalBarPill: Component {
|
||||
Column {
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
DankIcon {
|
||||
name: "monitor"
|
||||
color: Theme.primary
|
||||
|
||||
@@ -333,7 +333,7 @@ PluginComponent {
|
||||
width: peerListColumn.width
|
||||
height: peerCardColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: modelData.hostname === (TailscaleService.selfNode ? TailscaleService.selfNode.hostname : "") ? Theme.primaryHoverLight : Theme.surfaceContainerHighest
|
||||
color: modelData.hostname === (TailscaleService.selfNode ? TailscaleService.selfNode.hostname : "") ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
|
||||
|
||||
property bool isSelf: modelData.hostname === (TailscaleService.selfNode ? TailscaleService.selfNode.hostname : "")
|
||||
property bool isExpanded: detailRoot.expandedHostname === modelData.hostname
|
||||
@@ -344,7 +344,7 @@ PluginComponent {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
@@ -419,7 +419,7 @@ PluginComponent {
|
||||
Column {
|
||||
visible: isExpanded
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
topPadding: 4
|
||||
|
||||
RowLayout {
|
||||
|
||||
@@ -43,7 +43,7 @@ Rectangle {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: mouseArea.containsMouse ? hoverTint(root.color) : Theme.withAlpha(hoverTint(root.color), 0)
|
||||
color: mouseArea.containsMouse ? hoverTint(root.color) : "transparent"
|
||||
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -74,7 +74,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
Typography {
|
||||
width: parent.width
|
||||
|
||||
@@ -13,7 +13,7 @@ Rectangle {
|
||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outlineStrong
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.16)
|
||||
border.width: 1
|
||||
|
||||
MouseArea {
|
||||
@@ -24,7 +24,7 @@ Rectangle {
|
||||
id: menuColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingXXS
|
||||
spacing: 2
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user