mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-12 23:32:50 -04:00
Compare commits
60 Commits
v1.4.3
...
31aeb8dc4b
| Author | SHA1 | Date | |
|---|---|---|---|
| 31aeb8dc4b | |||
| c4e7f3d62f | |||
| a1d13f276a | |||
| dbf132d633 | |||
| 59451890f1 | |||
| e633c9e039 | |||
| 6c1fff2df1 | |||
| 3891d125d1 | |||
| 997011e008 | |||
| 2504396435 | |||
| d206723b36 | |||
| a0ec3d59b8 | |||
| 17ef08aa58 | |||
| 57279d1c53 | |||
| 8b003ac9cd | |||
| 0ea10b0ad2 | |||
| 2db4c9daa0 | |||
| 363964e90b | |||
| a7b49eba70 | |||
| 4ae334f60f | |||
| 86c0064ff9 | |||
| 5a6b52f07f | |||
| 5aaa56853f | |||
| 35913c22f5 | |||
| d7b560573c | |||
| 02a274ebe2 | |||
| fc7b61c20b | |||
| 5880043f56 | |||
| fee3b7f2a7 | |||
| c0b0339fca | |||
| 26c1e62204 | |||
| 7b2d4dbe30 | |||
| 78c5d46c6b | |||
| 3fb85df504 | |||
| 227dd24726 | |||
| ae6a656899 | |||
| a4055e0f01 | |||
| 6d98c229ef | |||
| 71d93ad85e | |||
| 4ec21fcd3d | |||
| 0a2fe03fee | |||
| 4f4745609b | |||
| a69cd515fb | |||
| 06c4b97a6b | |||
| a6cf71a190 | |||
| 21750156dc | |||
| f9b737f543 | |||
| 246b59f3b9 | |||
| dcda81ea64 | |||
| 9909b665cd | |||
| 4bcd786be3 | |||
| 64c9222000 | |||
| 12acf2dd51 | |||
| fea97b4aad | |||
| c6d398eeac | |||
| 7a74be83d7 | |||
| 67a6427418 | |||
| 18b20d3225 | |||
| 8a76885fb6 | |||
| 69b1e61ab7 |
@@ -40,7 +40,7 @@ jobs:
|
|||||||
echo "Build succeeded, no hash update needed"
|
echo "Build succeeded, no hash update needed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
new_hash=$(echo "$output" | grep -oP "got:\s+\K\S+" | head -n1)
|
new_hash=$(echo "$output" | grep -oP "got:\s+\K\S+" | head -n1 || true)
|
||||||
[ -n "$new_hash" ] || { echo "Could not extract new vendorHash"; echo "$output"; exit 1; }
|
[ -n "$new_hash" ] || { echo "Could not extract new vendorHash"; echo "$output"; exit 1; }
|
||||||
current_hash=$(grep -oP 'vendorHash = "\K[^"]+' flake.nix)
|
current_hash=$(grep -oP 'vendorHash = "\K[^"]+' flake.nix)
|
||||||
[ "$current_hash" = "$new_hash" ] && { echo "vendorHash already up to date"; exit 0; }
|
[ "$current_hash" = "$new_hash" ] && { echo "vendorHash already up to date"; exit 0; }
|
||||||
@@ -59,8 +59,8 @@ jobs:
|
|||||||
git config user.email "dms-ci[bot]@users.noreply.github.com"
|
git config user.email "dms-ci[bot]@users.noreply.github.com"
|
||||||
git add flake.nix
|
git add flake.nix
|
||||||
git commit -m "nix: update vendorHash for go.mod changes" || exit 0
|
git commit -m "nix: update vendorHash for go.mod changes" || exit 0
|
||||||
git pull --rebase origin master
|
git pull --rebase origin ${{ github.ref_name }}
|
||||||
git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git HEAD:master
|
git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git HEAD:${{ github.ref_name }}
|
||||||
else
|
else
|
||||||
echo "No changes to flake.nix"
|
echo "No changes to flake.nix"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -222,16 +222,19 @@ func init() {
|
|||||||
|
|
||||||
func runClipCopy(cmd *cobra.Command, args []string) {
|
func runClipCopy(cmd *cobra.Command, args []string) {
|
||||||
var data []byte
|
var data []byte
|
||||||
|
copyFromStdin := false
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(args) > 0:
|
case len(args) > 0:
|
||||||
data = []byte(args[0])
|
data = []byte(args[0])
|
||||||
default:
|
case clipCopyDownload || clipCopyType == "__multi__":
|
||||||
var err error
|
var err error
|
||||||
data, err = io.ReadAll(os.Stdin)
|
data, err = io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("read stdin: %v", err)
|
log.Fatalf("read stdin: %v", err)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
copyFromStdin = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if clipCopyDownload {
|
if clipCopyDownload {
|
||||||
@@ -257,6 +260,13 @@ func runClipCopy(cmd *cobra.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if copyFromStdin {
|
||||||
|
if err := clipboard.CopyReader(os.Stdin, clipCopyType, clipCopyForeground, clipCopyPasteOnce); err != nil {
|
||||||
|
log.Fatalf("copy: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := clipboard.CopyOpts(data, clipCopyType, clipCopyForeground, clipCopyPasteOnce); err != nil {
|
if err := clipboard.CopyOpts(data, clipCopyType, clipCopyForeground, clipCopyPasteOnce); err != nil {
|
||||||
log.Fatalf("copy: %v", err)
|
log.Fatalf("copy: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package clipboard
|
package clipboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_data_control"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/ext_data_control"
|
||||||
@@ -12,17 +14,37 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Copy(data []byte, mimeType string) error {
|
func Copy(data []byte, mimeType string) error {
|
||||||
return CopyOpts(data, mimeType, false, false)
|
return CopyReader(bytes.NewReader(data), mimeType, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyOpts(data []byte, mimeType string, foreground, pasteOnce bool) error {
|
func CopyOpts(data []byte, mimeType string, foreground, pasteOnce bool) error {
|
||||||
|
if foreground {
|
||||||
|
return copyServeWithWriter(func(writer io.Writer) error {
|
||||||
|
total := 0
|
||||||
|
for total < len(data) {
|
||||||
|
n, err := writer.Write(data[total:])
|
||||||
|
total += n
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if total != len(data) {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, mimeType, pasteOnce)
|
||||||
|
}
|
||||||
|
return CopyReader(bytes.NewReader(data), mimeType, foreground, pasteOnce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyReader(data io.Reader, mimeType string, foreground, pasteOnce bool) error {
|
||||||
if !foreground {
|
if !foreground {
|
||||||
return copyFork(data, mimeType, pasteOnce)
|
return copyFork(data, mimeType, pasteOnce)
|
||||||
}
|
}
|
||||||
return copyServe(data, mimeType, pasteOnce)
|
return copyServeReader(data, mimeType, pasteOnce)
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFork(data []byte, mimeType string, pasteOnce bool) error {
|
func copyFork(data io.Reader, mimeType string, pasteOnce bool) error {
|
||||||
args := []string{os.Args[0], "cl", "copy", "--foreground"}
|
args := []string{os.Args[0], "cl", "copy", "--foreground"}
|
||||||
if pasteOnce {
|
if pasteOnce {
|
||||||
args = append(args, "--paste-once")
|
args = append(args, "--paste-once")
|
||||||
@@ -30,11 +52,15 @@ func copyFork(data []byte, mimeType string, pasteOnce bool) error {
|
|||||||
args = append(args, "--type", mimeType)
|
args = append(args, "--type", mimeType)
|
||||||
|
|
||||||
cmd := exec.Command(args[0], args[1:]...)
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
cmd.Stdin = nil
|
|
||||||
cmd.Stdout = nil
|
cmd.Stdout = nil
|
||||||
cmd.Stderr = nil
|
cmd.Stderr = nil
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||||
|
|
||||||
|
if stdinSource, ok := data.(*os.File); ok {
|
||||||
|
cmd.Stdin = stdinSource
|
||||||
|
return cmd.Start()
|
||||||
|
}
|
||||||
|
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("stdin pipe: %w", err)
|
return fmt.Errorf("stdin pipe: %w", err)
|
||||||
@@ -44,16 +70,66 @@ func copyFork(data []byte, mimeType string, pasteOnce bool) error {
|
|||||||
return fmt.Errorf("start: %w", err)
|
return fmt.Errorf("start: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := stdin.Write(data); err != nil {
|
if _, err := io.Copy(stdin, data); err != nil {
|
||||||
stdin.Close()
|
stdin.Close()
|
||||||
return fmt.Errorf("write stdin: %w", err)
|
return fmt.Errorf("write stdin: %w", err)
|
||||||
}
|
}
|
||||||
stdin.Close()
|
if err := stdin.Close(); err != nil {
|
||||||
|
return fmt.Errorf("close stdin: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyServe(data []byte, mimeType string, pasteOnce bool) error {
|
func copyServeReader(data io.Reader, mimeType string, pasteOnce bool) error {
|
||||||
|
cachedData, err := createClipboardCacheFile()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create clipboard cache file: %w", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(cachedData.Name())
|
||||||
|
|
||||||
|
if _, err := io.Copy(cachedData, data); err != nil {
|
||||||
|
return fmt.Errorf("cache clipboard data: %w", err)
|
||||||
|
}
|
||||||
|
if err := cachedData.Close(); err != nil {
|
||||||
|
return fmt.Errorf("close temp cache file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return copyServeWithWriter(func(writer io.Writer) error {
|
||||||
|
cachedFile, err := os.Open(cachedData.Name())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("open temp cache file: %w", err)
|
||||||
|
}
|
||||||
|
defer cachedFile.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(writer, cachedFile); err != nil {
|
||||||
|
return fmt.Errorf("write clipboard data: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, mimeType, pasteOnce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createClipboardCacheFile() (*os.File, error) {
|
||||||
|
preferredDirs := []string{}
|
||||||
|
|
||||||
|
if cacheDir, err := os.UserCacheDir(); err == nil {
|
||||||
|
preferredDirs = append(preferredDirs, filepath.Join(cacheDir, "dms", "clipboard"))
|
||||||
|
}
|
||||||
|
preferredDirs = append(preferredDirs, "/var/tmp/dms/clipboard")
|
||||||
|
|
||||||
|
for _, dir := range preferredDirs {
|
||||||
|
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cachedData, err := os.CreateTemp(dir, "dms-clipboard-*")
|
||||||
|
if err == nil {
|
||||||
|
return cachedData, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.CreateTemp("", "dms-clipboard-*")
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyServeWithWriter(writeTo func(io.Writer) error, mimeType string, pasteOnce bool) error {
|
||||||
display, err := wlclient.Connect("")
|
display, err := wlclient.Connect("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("wayland connect: %w", err)
|
return fmt.Errorf("wayland connect: %w", err)
|
||||||
@@ -139,12 +215,18 @@ func copyServe(data []byte, mimeType string, pasteOnce bool) error {
|
|||||||
|
|
||||||
cancelled := make(chan struct{})
|
cancelled := make(chan struct{})
|
||||||
pasted := make(chan struct{}, 1)
|
pasted := make(chan struct{}, 1)
|
||||||
|
sendErr := make(chan error, 1)
|
||||||
|
|
||||||
source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) {
|
source.SetSendHandler(func(e ext_data_control.ExtDataControlSourceV1SendEvent) {
|
||||||
defer syscall.Close(e.Fd)
|
defer syscall.Close(e.Fd)
|
||||||
file := os.NewFile(uintptr(e.Fd), "pipe")
|
file := os.NewFile(uintptr(e.Fd), "pipe")
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
file.Write(data)
|
if err := writeTo(file); err != nil {
|
||||||
|
select {
|
||||||
|
case sendErr <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case pasted <- struct{}{}:
|
case pasted <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
@@ -165,6 +247,8 @@ func copyServe(data []byte, mimeType string, pasteOnce bool) error {
|
|||||||
select {
|
select {
|
||||||
case <-cancelled:
|
case <-cancelled:
|
||||||
return nil
|
return nil
|
||||||
|
case err := <-sendErr:
|
||||||
|
return err
|
||||||
case <-pasted:
|
case <-pasted:
|
||||||
if pasteOnce {
|
if pasteOnce {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -440,29 +440,10 @@ func (a *ArchDistribution) installAURPackages(ctx context.Context, packages []st
|
|||||||
a.log(fmt.Sprintf("Installing AUR packages manually: %s", strings.Join(packages, ", ")))
|
a.log(fmt.Sprintf("Installing AUR packages manually: %s", strings.Join(packages, ", ")))
|
||||||
|
|
||||||
hasNiri := false
|
hasNiri := false
|
||||||
hasQuickshell := false
|
|
||||||
for _, pkg := range packages {
|
for _, pkg := range packages {
|
||||||
if pkg == "niri-git" {
|
if pkg == "niri-git" {
|
||||||
hasNiri = true
|
hasNiri = true
|
||||||
}
|
}
|
||||||
if pkg == "quickshell" || pkg == "quickshell-git" {
|
|
||||||
hasQuickshell = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If quickshell is in the list, always reinstall google-breakpad first
|
|
||||||
if hasQuickshell {
|
|
||||||
progressChan <- InstallProgressMsg{
|
|
||||||
Phase: PhaseAURPackages,
|
|
||||||
Progress: 0.63,
|
|
||||||
Step: "Reinstalling google-breakpad for quickshell...",
|
|
||||||
IsComplete: false,
|
|
||||||
CommandInfo: "Reinstalling prerequisite AUR package for quickshell",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := a.installSingleAURPackage(ctx, "google-breakpad", sudoPassword, progressChan, 0.63, 0.65); err != nil {
|
|
||||||
return fmt.Errorf("failed to reinstall google-breakpad prerequisite for quickshell: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If niri is in the list, install makepkg-git-lfs-proto first if not already installed
|
// If niri is in the list, install makepkg-git-lfs-proto first if not already installed
|
||||||
@@ -616,10 +597,16 @@ func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sud
|
|||||||
return fmt.Errorf("failed to remove optdepends from .SRCINFO for %s: %w", pkg, err)
|
return fmt.Errorf("failed to remove optdepends from .SRCINFO for %s: %w", pkg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip dependency installation for dms-shell-git and dms-shell-bin
|
srcinfoPath = filepath.Join(packageDir, ".SRCINFO")
|
||||||
// since we manually manage those dependencies
|
if pkg == "dms-shell-bin" {
|
||||||
if pkg != "dms-shell-git" && pkg != "dms-shell-bin" {
|
progressChan <- InstallProgressMsg{
|
||||||
// Pre-install dependencies from .SRCINFO
|
Phase: PhaseAURPackages,
|
||||||
|
Progress: startProgress + 0.35*(endProgress-startProgress),
|
||||||
|
Step: fmt.Sprintf("Skipping dependency installation for %s (manually managed)...", pkg),
|
||||||
|
IsComplete: false,
|
||||||
|
LogOutput: fmt.Sprintf("Dependencies for %s are installed separately", pkg),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
progressChan <- InstallProgressMsg{
|
progressChan <- InstallProgressMsg{
|
||||||
Phase: PhaseAURPackages,
|
Phase: PhaseAURPackages,
|
||||||
Progress: startProgress + 0.3*(endProgress-startProgress),
|
Progress: startProgress + 0.3*(endProgress-startProgress),
|
||||||
@@ -628,19 +615,19 @@ func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sud
|
|||||||
CommandInfo: "Installing package dependencies and makedepends",
|
CommandInfo: "Installing package dependencies and makedepends",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install dependencies and makedepends explicitly
|
// Install dependencies from .SRCINFO
|
||||||
srcinfoPath = filepath.Join(packageDir, ".SRCINFO")
|
depFilter := ""
|
||||||
|
if pkg == "dms-shell-git" {
|
||||||
|
depFilter = ` | sed -E 's/[[:space:]]*(quickshell|dgop)[[:space:]]*/ /g' | tr -s ' '`
|
||||||
|
}
|
||||||
|
|
||||||
depsCmd := exec.CommandContext(ctx, "bash", "-c",
|
depsCmd := exec.CommandContext(ctx, "bash", "-c",
|
||||||
fmt.Sprintf(`
|
fmt.Sprintf(`
|
||||||
deps=$(grep "depends = " "%s" | grep -v "makedepends" | sed 's/.*depends = //' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
|
deps=$(grep "depends = " "%s" | grep -v "makedepends" | sed 's/.*depends = //' | tr '\n' ' ' %s | sed 's/[[:space:]]*$//')
|
||||||
if [[ "%s" == *"quickshell"* ]]; then
|
|
||||||
deps=$(echo "$deps" | sed 's/google-breakpad//g' | sed 's/ / /g' | sed 's/^ *//g' | sed 's/ *$//g')
|
|
||||||
fi
|
|
||||||
if [ ! -z "$deps" ] && [ "$deps" != " " ]; then
|
if [ ! -z "$deps" ] && [ "$deps" != " " ]; then
|
||||||
echo '%s' | sudo -S pacman -S --needed --noconfirm $deps
|
echo '%s' | sudo -S pacman -S --needed --noconfirm $deps
|
||||||
fi
|
fi
|
||||||
`, srcinfoPath, pkg, sudoPassword))
|
`, srcinfoPath, depFilter, sudoPassword))
|
||||||
|
|
||||||
if err := a.runWithProgress(depsCmd, progressChan, PhaseAURPackages, startProgress+0.3*(endProgress-startProgress), startProgress+0.35*(endProgress-startProgress)); err != nil {
|
if err := a.runWithProgress(depsCmd, progressChan, PhaseAURPackages, startProgress+0.3*(endProgress-startProgress), startProgress+0.35*(endProgress-startProgress)); err != nil {
|
||||||
return fmt.Errorf("FAILED to install runtime dependencies for %s: %w", pkg, err)
|
return fmt.Errorf("FAILED to install runtime dependencies for %s: %w", pkg, err)
|
||||||
@@ -657,14 +644,6 @@ func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sud
|
|||||||
if err := a.runWithProgress(makedepsCmd, progressChan, PhaseAURPackages, startProgress+0.35*(endProgress-startProgress), startProgress+0.4*(endProgress-startProgress)); err != nil {
|
if err := a.runWithProgress(makedepsCmd, progressChan, PhaseAURPackages, startProgress+0.35*(endProgress-startProgress), startProgress+0.4*(endProgress-startProgress)); err != nil {
|
||||||
return fmt.Errorf("FAILED to install make dependencies for %s: %w", pkg, err)
|
return fmt.Errorf("FAILED to install make dependencies for %s: %w", pkg, err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
progressChan <- InstallProgressMsg{
|
|
||||||
Phase: PhaseAURPackages,
|
|
||||||
Progress: startProgress + 0.35*(endProgress-startProgress),
|
|
||||||
Step: fmt.Sprintf("Skipping dependency installation for %s (manually managed)...", pkg),
|
|
||||||
IsComplete: false,
|
|
||||||
LogOutput: fmt.Sprintf("Dependencies for %s are installed separately", pkg),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progressChan <- InstallProgressMsg{
|
progressChan <- InstallProgressMsg{
|
||||||
@@ -677,7 +656,7 @@ func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sud
|
|||||||
|
|
||||||
buildCmd := exec.CommandContext(ctx, "makepkg", "--noconfirm")
|
buildCmd := exec.CommandContext(ctx, "makepkg", "--noconfirm")
|
||||||
buildCmd.Dir = packageDir
|
buildCmd.Dir = packageDir
|
||||||
buildCmd.Env = append(os.Environ(), "PKGEXT=.pkg.tar") // Disable compression for speed
|
buildCmd.Env = append(os.Environ(), "PKGEXT=.pkg.tar")
|
||||||
|
|
||||||
if err := a.runWithProgress(buildCmd, progressChan, PhaseAURPackages, startProgress+0.4*(endProgress-startProgress), startProgress+0.7*(endProgress-startProgress)); err != nil {
|
if err := a.runWithProgress(buildCmd, progressChan, PhaseAURPackages, startProgress+0.4*(endProgress-startProgress), startProgress+0.7*(endProgress-startProgress)); err != nil {
|
||||||
return fmt.Errorf("failed to build %s: %w", pkg, err)
|
return fmt.Errorf("failed to build %s: %w", pkg, err)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
|
||||||
@@ -97,6 +96,17 @@ func (d *DebianDistribution) packageInstalled(pkg string) bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func debianRepoArchitecture(arch string) string {
|
||||||
|
switch arch {
|
||||||
|
case "amd64", "x86_64":
|
||||||
|
return "amd64"
|
||||||
|
case "arm64", "aarch64":
|
||||||
|
return "arm64"
|
||||||
|
default:
|
||||||
|
return arch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DebianDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
|
func (d *DebianDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
|
||||||
return d.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
|
return d.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
|
||||||
}
|
}
|
||||||
@@ -436,7 +446,7 @@ func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Packa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add repository
|
// Add repository
|
||||||
repoLine := fmt.Sprintf("deb [signed-by=%s arch=%s] %s/ /", keyringPath, runtime.GOARCH, baseURL)
|
repoLine := fmt.Sprintf("deb [signed-by=%s arch=%s] %s/ /", keyringPath, debianRepoArchitecture(osInfo.Architecture), baseURL)
|
||||||
|
|
||||||
progressChan <- InstallProgressMsg{
|
progressChan <- InstallProgressMsg{
|
||||||
Phase: PhaseSystemPackages,
|
Phase: PhaseSystemPackages,
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ var templateRegistry = []TemplateDef{
|
|||||||
{ID: "kcolorscheme", ConfigFile: "kcolorscheme.toml", RunUnconditionally: true},
|
{ID: "kcolorscheme", ConfigFile: "kcolorscheme.toml", RunUnconditionally: true},
|
||||||
{ID: "vscode", Kind: TemplateKindVSCode},
|
{ID: "vscode", Kind: TemplateKindVSCode},
|
||||||
{ID: "emacs", Commands: []string{"emacs"}, ConfigFile: "emacs.toml", Kind: TemplateKindEmacs},
|
{ID: "emacs", Commands: []string{"emacs"}, ConfigFile: "emacs.toml", Kind: TemplateKindEmacs},
|
||||||
|
{ID: "zed", Commands: []string{"zed", "zeditor", "zedit"}, ConfigFile: "zed.toml"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ColorMode) GTKTheme() string {
|
func (c *ColorMode) GTKTheme() string {
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ const (
|
|||||||
dbusPath = "/org/freedesktop/login1"
|
dbusPath = "/org/freedesktop/login1"
|
||||||
dbusManagerInterface = "org.freedesktop.login1.Manager"
|
dbusManagerInterface = "org.freedesktop.login1.Manager"
|
||||||
dbusSessionInterface = "org.freedesktop.login1.Session"
|
dbusSessionInterface = "org.freedesktop.login1.Session"
|
||||||
|
dbusUserInterface = "org.freedesktop.login1.User"
|
||||||
dbusPropsInterface = "org.freedesktop.DBus.Properties"
|
dbusPropsInterface = "org.freedesktop.DBus.Properties"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,15 +17,8 @@ func NewManager() (*Manager, error) {
|
|||||||
return nil, fmt.Errorf("failed to connect to system bus: %w", err)
|
return nil, fmt.Errorf("failed to connect to system bus: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionID := os.Getenv("XDG_SESSION_ID")
|
|
||||||
if sessionID == "" {
|
|
||||||
sessionID = "self"
|
|
||||||
}
|
|
||||||
|
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
state: &SessionState{
|
state: &SessionState{},
|
||||||
SessionID: sessionID,
|
|
||||||
},
|
|
||||||
stateMutex: sync.RWMutex{},
|
stateMutex: sync.RWMutex{},
|
||||||
|
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
@@ -60,12 +53,13 @@ func (m *Manager) initialize() error {
|
|||||||
|
|
||||||
m.initializeFallbackDelay()
|
m.initializeFallbackDelay()
|
||||||
|
|
||||||
sessionPath, err := m.getSession(m.state.SessionID)
|
sessionID, sessionPath, err := m.discoverSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get session path: %w", err)
|
return fmt.Errorf("failed to get session path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.stateMutex.Lock()
|
m.stateMutex.Lock()
|
||||||
|
m.state.SessionID = sessionID
|
||||||
m.state.SessionPath = string(sessionPath)
|
m.state.SessionPath = string(sessionPath)
|
||||||
m.sessionPath = sessionPath
|
m.sessionPath = sessionPath
|
||||||
m.stateMutex.Unlock()
|
m.stateMutex.Unlock()
|
||||||
@@ -79,6 +73,41 @@ func (m *Manager) initialize() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) discoverSession() (string, dbus.ObjectPath, error) {
|
||||||
|
// 1. Explicit XDG_SESSION_ID
|
||||||
|
if id := os.Getenv("XDG_SESSION_ID"); id != "" {
|
||||||
|
if path, err := m.getSession(id); err == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "loginctl: using XDG_SESSION_ID=%s\n", id)
|
||||||
|
return id, path, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. PID-based lookup (works when caller is inside a session cgroup)
|
||||||
|
if id, path, err := m.getSessionByPID(uint32(os.Getpid())); err == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "loginctl: found session %s via PID\n", id)
|
||||||
|
return id, path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. User's primary display session (handles UWSM and similar)
|
||||||
|
if id, path, err := m.getUserDisplaySession(); err == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "loginctl: found session %s via User.Display\n", id)
|
||||||
|
return id, path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Score all sessions for current UID
|
||||||
|
if id, path, err := m.findBestSession(); err == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "loginctl: found session %s via ListSessions scoring\n", id)
|
||||||
|
return id, path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Last resort: "self"
|
||||||
|
path, err := m.getSession("self")
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("%w", err)
|
||||||
|
}
|
||||||
|
return "self", path, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) getSession(id string) (dbus.ObjectPath, error) {
|
func (m *Manager) getSession(id string) (dbus.ObjectPath, error) {
|
||||||
var out dbus.ObjectPath
|
var out dbus.ObjectPath
|
||||||
err := m.managerObj.Call(dbusManagerInterface+".GetSession", 0, id).Store(&out)
|
err := m.managerObj.Call(dbusManagerInterface+".GetSession", 0, id).Store(&out)
|
||||||
@@ -88,6 +117,166 @@ func (m *Manager) getSession(id string) (dbus.ObjectPath, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getSessionByPID(pid uint32) (string, dbus.ObjectPath, error) {
|
||||||
|
var path dbus.ObjectPath
|
||||||
|
if err := m.managerObj.Call(dbusManagerInterface+".GetSessionByPID", 0, pid).Store(&path); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionObj := m.conn.Object(dbusDest, path)
|
||||||
|
var id dbus.Variant
|
||||||
|
if err := sessionObj.Call(dbusPropsInterface+".Get", 0, dbusSessionInterface, "Id").Store(&id); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return id.Value().(string), path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getUserDisplaySession() (string, dbus.ObjectPath, error) {
|
||||||
|
uid := uint32(os.Getuid())
|
||||||
|
|
||||||
|
var userPath dbus.ObjectPath
|
||||||
|
if err := m.managerObj.Call(dbusManagerInterface+".GetUser", 0, uid).Store(&userPath); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
userObj := m.conn.Object(dbusDest, userPath)
|
||||||
|
var display dbus.Variant
|
||||||
|
if err := userObj.Call(dbusPropsInterface+".Get", 0, dbusUserInterface, "Display").Store(&display); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pair, ok := display.Value().([]any)
|
||||||
|
if !ok || len(pair) < 2 {
|
||||||
|
return "", "", fmt.Errorf("unexpected Display format")
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionID, _ := pair[0].(string)
|
||||||
|
sessionPath, _ := pair[1].(dbus.ObjectPath)
|
||||||
|
if sessionID == "" || sessionPath == "" {
|
||||||
|
return "", "", fmt.Errorf("empty Display session")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionID, sessionPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type sessionCandidate struct {
|
||||||
|
id string
|
||||||
|
path dbus.ObjectPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) findBestSession() (string, dbus.ObjectPath, error) {
|
||||||
|
// ListSessions returns a(susso): [][]any where each entry is [id, uid, name, seat, path]
|
||||||
|
var raw [][]any
|
||||||
|
if err := m.managerObj.Call(dbusManagerInterface+".ListSessions", 0).Store(&raw); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
uid := uint32(os.Getuid())
|
||||||
|
var candidates []sessionCandidate
|
||||||
|
for _, entry := range raw {
|
||||||
|
if len(entry) < 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entryUID, _ := entry[1].(uint32)
|
||||||
|
if entryUID != uid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id, _ := entry[0].(string)
|
||||||
|
path, _ := entry[4].(dbus.ObjectPath)
|
||||||
|
if id != "" && path != "" {
|
||||||
|
candidates = append(candidates, sessionCandidate{id: id, path: path})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(candidates) == 0 {
|
||||||
|
return "", "", fmt.Errorf("no sessions for uid %d", uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
bestScore := -1
|
||||||
|
var best sessionCandidate
|
||||||
|
for _, c := range candidates {
|
||||||
|
score := m.scoreSession(c.path)
|
||||||
|
if score > bestScore {
|
||||||
|
bestScore = score
|
||||||
|
best = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bestScore < 0 {
|
||||||
|
return "", "", fmt.Errorf("no viable session found")
|
||||||
|
}
|
||||||
|
return best.id, best.path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) scoreSession(path dbus.ObjectPath) int {
|
||||||
|
obj := m.conn.Object(dbusDest, path)
|
||||||
|
var props map[string]dbus.Variant
|
||||||
|
if err := obj.Call(dbusPropsInterface+".GetAll", 0, dbusSessionInterface).Store(&props); err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
getStr := func(key string) string {
|
||||||
|
if v, ok := props[key]; ok {
|
||||||
|
if s, ok := v.Value().(string); ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
getBool := func(key string) bool {
|
||||||
|
if v, ok := props[key]; ok {
|
||||||
|
if b, ok := v.Value().(bool); ok {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
getUint32 := func(key string) uint32 {
|
||||||
|
if v, ok := props[key]; ok {
|
||||||
|
if u, ok := v.Value().(uint32); ok {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class := getStr("Class")
|
||||||
|
if class != "user" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if getBool("Remote") {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
score := 0
|
||||||
|
|
||||||
|
if getBool("Active") {
|
||||||
|
score += 100
|
||||||
|
}
|
||||||
|
|
||||||
|
switch getStr("Type") {
|
||||||
|
case "wayland", "x11":
|
||||||
|
score += 80
|
||||||
|
case "tty":
|
||||||
|
score += 10
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := props["Seat"]; ok {
|
||||||
|
if seatArr, ok := v.Value().([]any); ok && len(seatArr) >= 1 {
|
||||||
|
if seat, ok := seatArr[0].(string); ok && seat != "" {
|
||||||
|
score += 40
|
||||||
|
if seat == "seat0" {
|
||||||
|
score += 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if getUint32("VTNr") > 0 {
|
||||||
|
score += 20
|
||||||
|
}
|
||||||
|
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) refreshSessionBinding() error {
|
func (m *Manager) refreshSessionBinding() error {
|
||||||
if m.managerObj == nil || m.conn == nil {
|
if m.managerObj == nil || m.conn == nil {
|
||||||
return fmt.Errorf("manager not fully initialized")
|
return fmt.Errorf("manager not fully initialized")
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package wlcontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
@@ -123,6 +123,9 @@ func (sc *SharedContext) eventDispatcher() {
|
|||||||
{Fd: int32(sc.wakeR), Events: unix.POLLIN},
|
{Fd: int32(sc.wakeR), Events: unix.POLLIN},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
consecutiveErrors := 0
|
||||||
|
const maxConsecutiveErrors = 20
|
||||||
|
|
||||||
for {
|
for {
|
||||||
sc.drainCmdQueue()
|
sc.drainCmdQueue()
|
||||||
|
|
||||||
@@ -153,9 +156,19 @@ func (sc *SharedContext) eventDispatcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) {
|
if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) {
|
||||||
log.Errorf("Wayland connection error: %v", err)
|
consecutiveErrors++
|
||||||
return
|
log.Warnf("Wayland connection error (%d/%d): %v", consecutiveErrors, maxConsecutiveErrors, err)
|
||||||
|
|
||||||
|
if consecutiveErrors >= maxConsecutiveErrors {
|
||||||
|
log.Errorf("Fatal: Wayland connection unrecoverable after %d attempts. Exiting dispatcher.", maxConsecutiveErrors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond * time.Duration(consecutiveErrors))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
consecutiveErrors = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Vcs-Browser: https://github.com/AvengeMedia/DankMaterialShell
|
|||||||
Vcs-Git: https://github.com/AvengeMedia/DankMaterialShell.git
|
Vcs-Git: https://github.com/AvengeMedia/DankMaterialShell.git
|
||||||
|
|
||||||
Package: dms
|
Package: dms
|
||||||
Architecture: amd64
|
Architecture: amd64 arm64
|
||||||
Depends: ${misc:Depends},
|
Depends: ${misc:Depends},
|
||||||
quickshell | quickshell-git,
|
quickshell | quickshell-git,
|
||||||
accountsservice,
|
accountsservice,
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
dms-distropkg-amd64.gz
|
dms-distropkg-amd64.gz
|
||||||
|
dms-distropkg-arm64.gz
|
||||||
dms-source.tar.gz
|
dms-source.tar.gz
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Include files that are normally excluded by .gitignore
|
# Include files that are normally excluded by .gitignore
|
||||||
# These are needed for the build process on Launchpad
|
# These are needed for the build process on Launchpad
|
||||||
tar-ignore = !dms-distropkg-amd64.gz
|
tar-ignore = !dms-distropkg-amd64.gz
|
||||||
|
tar-ignore = !dms-distropkg-arm64.gz
|
||||||
tar-ignore = !dms-source.tar.gz
|
tar-ignore = !dms-source.tar.gz
|
||||||
|
|||||||
@@ -17,6 +17,25 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
goModVersion =
|
||||||
|
let
|
||||||
|
content = builtins.readFile ./core/go.mod;
|
||||||
|
lines = builtins.filter builtins.isString (builtins.split "\n" content);
|
||||||
|
goLines = builtins.filter (l: builtins.match "go [0-9]+\\..*" l != null) lines;
|
||||||
|
matched =
|
||||||
|
if goLines != [ ] then builtins.match "go ([0-9]+)\\.([0-9]+).*" (builtins.head goLines) else null;
|
||||||
|
in
|
||||||
|
if matched != null then
|
||||||
|
{
|
||||||
|
major = builtins.elemAt matched 0;
|
||||||
|
minor = builtins.elemAt matched 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
major = "1";
|
||||||
|
minor = "25";
|
||||||
|
};
|
||||||
|
goForPkgs = pkgs: pkgs.${"go_${goModVersion.major}_${goModVersion.minor}"};
|
||||||
forEachSystem =
|
forEachSystem =
|
||||||
fn:
|
fn:
|
||||||
nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ] (
|
nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ] (
|
||||||
@@ -72,76 +91,82 @@
|
|||||||
"${cleanVersion}${dateSuffix}${revSuffix}";
|
"${cleanVersion}${dateSuffix}${revSuffix}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
dms-shell = pkgs.buildGoModule (
|
dms-shell = pkgs.lib.makeOverridable (
|
||||||
let
|
|
||||||
rootSrc = ./.;
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
inherit version;
|
extraQtPackages ? [ ],
|
||||||
pname = "dms-shell";
|
}:
|
||||||
src = ./core;
|
(pkgs.buildGoModule.override { go = goForPkgs pkgs; }) (
|
||||||
vendorHash = "sha256-dEk7IOd6aQwaxZruxQclN7TGMyb8EJOl6NBWRsoZ9HQ=";
|
let
|
||||||
|
rootSrc = ./.;
|
||||||
|
qtPackages = (qmlPkgs pkgs) ++ extraQtPackages;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit version;
|
||||||
|
pname = "dms-shell";
|
||||||
|
src = ./core;
|
||||||
|
vendorHash = "sha256-cVUJXgzYMRSM0od1xzDVkMTdxHu3OIQX2bQ8AJbGQ1Q=";
|
||||||
|
|
||||||
subPackages = [ "cmd/dms" ];
|
subPackages = [ "cmd/dms" ];
|
||||||
|
|
||||||
ldflags = [
|
ldflags = [
|
||||||
"-s"
|
"-s"
|
||||||
"-w"
|
"-w"
|
||||||
"-X 'main.Version=${version}'"
|
"-X 'main.Version=${version}'"
|
||||||
];
|
];
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
installShellFiles
|
installShellFiles
|
||||||
makeWrapper
|
makeWrapper
|
||||||
];
|
];
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
mkdir -p $out/share/quickshell/dms
|
mkdir -p $out/share/quickshell/dms
|
||||||
cp -r ${rootSrc}/quickshell/. $out/share/quickshell/dms/
|
cp -r ${rootSrc}/quickshell/. $out/share/quickshell/dms/
|
||||||
|
|
||||||
chmod u+w $out/share/quickshell/dms/VERSION
|
chmod u+w $out/share/quickshell/dms/VERSION
|
||||||
echo "${version}" > $out/share/quickshell/dms/VERSION
|
echo "${version}" > $out/share/quickshell/dms/VERSION
|
||||||
|
|
||||||
# Install desktop file and icon
|
# Install desktop file and icon
|
||||||
install -D ${rootSrc}/assets/dms-open.desktop \
|
install -D ${rootSrc}/assets/dms-open.desktop \
|
||||||
$out/share/applications/dms-open.desktop
|
$out/share/applications/dms-open.desktop
|
||||||
install -D ${rootSrc}/core/assets/danklogo.svg \
|
install -D ${rootSrc}/core/assets/danklogo.svg \
|
||||||
$out/share/hicolor/scalable/apps/danklogo.svg
|
$out/share/hicolor/scalable/apps/danklogo.svg
|
||||||
|
|
||||||
wrapProgram $out/bin/dms \
|
wrapProgram $out/bin/dms \
|
||||||
--add-flags "-c $out/share/quickshell/dms" \
|
--add-flags "-c $out/share/quickshell/dms" \
|
||||||
--prefix "NIXPKGS_QT6_QML_IMPORT_PATH" ":" "${mkQmlImportPath pkgs (qmlPkgs pkgs)}" \
|
--prefix "NIXPKGS_QT6_QML_IMPORT_PATH" ":" "${mkQmlImportPath pkgs qtPackages}" \
|
||||||
--prefix "QT_PLUGIN_PATH" ":" "${mkQtPluginPath pkgs (qmlPkgs pkgs)}"
|
--prefix "QT_PLUGIN_PATH" ":" "${mkQtPluginPath pkgs qtPackages}"
|
||||||
|
|
||||||
install -Dm644 ${rootSrc}/assets/systemd/dms.service \
|
install -Dm644 ${rootSrc}/assets/systemd/dms.service \
|
||||||
$out/lib/systemd/user/dms.service
|
$out/lib/systemd/user/dms.service
|
||||||
|
|
||||||
substituteInPlace $out/lib/systemd/user/dms.service \
|
substituteInPlace $out/lib/systemd/user/dms.service \
|
||||||
--replace-fail /usr/bin/dms $out/bin/dms \
|
--replace-fail /usr/bin/dms $out/bin/dms \
|
||||||
--replace-fail /usr/bin/pkill ${pkgs.procps}/bin/pkill
|
--replace-fail /usr/bin/pkill ${pkgs.procps}/bin/pkill
|
||||||
|
|
||||||
substituteInPlace $out/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
|
substituteInPlace $out/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
|
||||||
--replace-fail /bin/bash ${pkgs.bashInteractive}/bin/bash
|
--replace-fail /bin/bash ${pkgs.bashInteractive}/bin/bash
|
||||||
|
|
||||||
substituteInPlace $out/share/quickshell/dms/assets/pam/fprint \
|
substituteInPlace $out/share/quickshell/dms/assets/pam/fprint \
|
||||||
--replace-fail pam_fprintd.so ${pkgs.fprintd}/lib/security/pam_fprintd.so
|
--replace-fail pam_fprintd.so ${pkgs.fprintd}/lib/security/pam_fprintd.so
|
||||||
|
|
||||||
installShellCompletion --cmd dms \
|
installShellCompletion --cmd dms \
|
||||||
--bash <($out/bin/dms completion bash) \
|
--bash <($out/bin/dms completion bash) \
|
||||||
--fish <($out/bin/dms completion fish) \
|
--fish <($out/bin/dms completion fish) \
|
||||||
--zsh <($out/bin/dms completion zsh)
|
--zsh <($out/bin/dms completion zsh)
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
description = "Desktop shell for wayland compositors built with Quickshell & GO";
|
description = "Desktop shell for wayland compositors built with Quickshell & GO";
|
||||||
homepage = "https://danklinux.com";
|
homepage = "https://danklinux.com";
|
||||||
changelog = "https://github.com/AvengeMedia/DankMaterialShell/releases/tag/v${version}";
|
changelog = "https://github.com/AvengeMedia/DankMaterialShell/releases/tag/v${version}";
|
||||||
license = pkgs.lib.licenses.mit;
|
license = pkgs.lib.licenses.mit;
|
||||||
mainProgram = "dms";
|
mainProgram = "dms";
|
||||||
platforms = pkgs.lib.platforms.linux;
|
platforms = pkgs.lib.platforms.linux;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
) { };
|
||||||
|
|
||||||
quickshell = quickshell.packages.${system}.default;
|
quickshell = quickshell.packages.${system}.default;
|
||||||
|
|
||||||
@@ -181,7 +206,7 @@
|
|||||||
buildInputs =
|
buildInputs =
|
||||||
with pkgs;
|
with pkgs;
|
||||||
[
|
[
|
||||||
go_1_25
|
(goForPkgs pkgs)
|
||||||
gopls
|
gopls
|
||||||
delve
|
delve
|
||||||
go-tools
|
go-tools
|
||||||
|
|||||||
@@ -71,15 +71,40 @@ Singleton {
|
|||||||
return appId;
|
return appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveIconPath(iconName: string): string {
|
||||||
|
if (!iconName) return "";
|
||||||
|
const moddedId = moddedAppId(iconName);
|
||||||
|
if (moddedId !== iconName) {
|
||||||
|
if (moddedId.startsWith("~") || moddedId.startsWith("/"))
|
||||||
|
return toFileUrl(expandTilde(moddedId));
|
||||||
|
if (moddedId.startsWith("file://"))
|
||||||
|
return moddedId;
|
||||||
|
return Quickshell.iconPath(moddedId, true);
|
||||||
|
}
|
||||||
|
return Quickshell.iconPath(iconName, true) || DesktopService.resolveIconPath(iconName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveIconUrl(iconName: string): string {
|
||||||
|
if (!iconName) return "";
|
||||||
|
const moddedId = moddedAppId(iconName);
|
||||||
|
if (moddedId !== iconName) {
|
||||||
|
if (moddedId.startsWith("~") || moddedId.startsWith("/"))
|
||||||
|
return toFileUrl(expandTilde(moddedId));
|
||||||
|
if (moddedId.startsWith("file://"))
|
||||||
|
return moddedId;
|
||||||
|
return "image://icon/" + moddedId;
|
||||||
|
}
|
||||||
|
return "image://icon/" + iconName;
|
||||||
|
}
|
||||||
|
|
||||||
function getAppIcon(appId: string, desktopEntry: var): string {
|
function getAppIcon(appId: string, desktopEntry: var): string {
|
||||||
if (appId === "org.quickshell") {
|
if (appId === "org.quickshell") {
|
||||||
return Qt.resolvedUrl("../assets/danklogo.svg");
|
return Qt.resolvedUrl("../assets/danklogo.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
const moddedId = moddedAppId(appId);
|
const moddedId = moddedAppId(appId);
|
||||||
if (moddedId !== appId) {
|
if (moddedId !== appId)
|
||||||
return Quickshell.iconPath(moddedId, true);
|
return resolveIconPath(appId);
|
||||||
}
|
|
||||||
|
|
||||||
if (desktopEntry && desktopEntry.icon) {
|
if (desktopEntry && desktopEntry.icon) {
|
||||||
return Quickshell.iconPath(desktopEntry.icon, true);
|
return Quickshell.iconPath(desktopEntry.icon, true);
|
||||||
|
|||||||
@@ -575,14 +575,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newSettings[identifier]) {
|
newSettings[identifier] = getMonitorCyclingSettings(screenName);
|
||||||
newSettings[identifier] = {
|
|
||||||
"enabled": false,
|
|
||||||
"mode": "interval",
|
|
||||||
"interval": 300,
|
|
||||||
"time": "06:00"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newSettings[identifier].enabled = enabled;
|
newSettings[identifier].enabled = enabled;
|
||||||
monitorCyclingSettings = newSettings;
|
monitorCyclingSettings = newSettings;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
@@ -613,14 +606,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newSettings[identifier]) {
|
newSettings[identifier] = getMonitorCyclingSettings(screenName);
|
||||||
newSettings[identifier] = {
|
|
||||||
"enabled": false,
|
|
||||||
"mode": "interval",
|
|
||||||
"interval": 300,
|
|
||||||
"time": "06:00"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newSettings[identifier].mode = mode;
|
newSettings[identifier].mode = mode;
|
||||||
monitorCyclingSettings = newSettings;
|
monitorCyclingSettings = newSettings;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
@@ -651,14 +637,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newSettings[identifier]) {
|
newSettings[identifier] = getMonitorCyclingSettings(screenName);
|
||||||
newSettings[identifier] = {
|
|
||||||
"enabled": false,
|
|
||||||
"mode": "interval",
|
|
||||||
"interval": 300,
|
|
||||||
"time": "06:00"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newSettings[identifier].interval = interval;
|
newSettings[identifier].interval = interval;
|
||||||
monitorCyclingSettings = newSettings;
|
monitorCyclingSettings = newSettings;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
@@ -689,14 +668,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newSettings[identifier]) {
|
newSettings[identifier] = getMonitorCyclingSettings(screenName);
|
||||||
newSettings[identifier] = {
|
|
||||||
"enabled": false,
|
|
||||||
"mode": "interval",
|
|
||||||
"interval": 300,
|
|
||||||
"time": "06:00"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newSettings[identifier].time = time;
|
newSettings[identifier].time = time;
|
||||||
monitorCyclingSettings = newSettings;
|
monitorCyclingSettings = newSettings;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
@@ -1205,7 +1177,7 @@ Singleton {
|
|||||||
"time": "06:00"
|
"time": "06:00"
|
||||||
};
|
};
|
||||||
var value = _findMonitorValue(monitorCyclingSettings, screenName);
|
var value = _findMonitorValue(monitorCyclingSettings, screenName);
|
||||||
return value !== undefined ? value : defaults;
|
return Object.assign({}, defaults, value !== undefined ? value : {});
|
||||||
}
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
|
|||||||
@@ -437,13 +437,14 @@ Singleton {
|
|||||||
property bool matugenTemplateGhostty: true
|
property bool matugenTemplateGhostty: true
|
||||||
property bool matugenTemplateKitty: true
|
property bool matugenTemplateKitty: true
|
||||||
property bool matugenTemplateFoot: true
|
property bool matugenTemplateFoot: true
|
||||||
property bool matugenTemplateNeovim: true
|
property bool matugenTemplateNeovim: false
|
||||||
property bool matugenTemplateAlacritty: true
|
property bool matugenTemplateAlacritty: true
|
||||||
property bool matugenTemplateWezterm: true
|
property bool matugenTemplateWezterm: true
|
||||||
property bool matugenTemplateDgop: true
|
property bool matugenTemplateDgop: true
|
||||||
property bool matugenTemplateKcolorscheme: true
|
property bool matugenTemplateKcolorscheme: true
|
||||||
property bool matugenTemplateVscode: true
|
property bool matugenTemplateVscode: true
|
||||||
property bool matugenTemplateEmacs: true
|
property bool matugenTemplateEmacs: true
|
||||||
|
property bool matugenTemplateZed: true
|
||||||
|
|
||||||
property bool showDock: false
|
property bool showDock: false
|
||||||
property bool dockAutoHide: false
|
property bool dockAutoHide: false
|
||||||
@@ -1221,10 +1222,47 @@ Singleton {
|
|||||||
return JSON.stringify(Store.toJson(root), null, 2);
|
return JSON.stringify(Store.toJson(root), null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _resetPluginSettings() {
|
||||||
|
_pluginParseError = false;
|
||||||
|
pluginSettings = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _pluginSettingsErrorCode(error) {
|
||||||
|
if (typeof error === "number")
|
||||||
|
return error;
|
||||||
|
if (error && typeof error === "object") {
|
||||||
|
if (typeof error.code === "number")
|
||||||
|
return error.code;
|
||||||
|
if (typeof error.errno === "number")
|
||||||
|
return error.errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
const msg = String(error || "").trim();
|
||||||
|
if (/^\d+$/.test(msg))
|
||||||
|
return Number(msg);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isMissingPluginSettingsError(error) {
|
||||||
|
if (_pluginSettingsErrorCode(error) === 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const msg = String(error || "").toLowerCase();
|
||||||
|
return msg.indexOf("file does not exist") !== -1
|
||||||
|
|| msg.indexOf("no such file") !== -1
|
||||||
|
|| msg.indexOf("enoent") !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
function loadPluginSettings() {
|
function loadPluginSettings() {
|
||||||
_pluginSettingsLoading = true;
|
try {
|
||||||
parsePluginSettings(pluginSettingsFile.text());
|
parsePluginSettings(pluginSettingsFile.text());
|
||||||
_pluginSettingsLoading = false;
|
} catch (e) {
|
||||||
|
const msg = e.message || String(e);
|
||||||
|
if (!_isMissingPluginSettingsError(e))
|
||||||
|
console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg);
|
||||||
|
_resetPluginSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePluginSettings(content) {
|
function parsePluginSettings(content) {
|
||||||
@@ -2660,6 +2698,7 @@ Singleton {
|
|||||||
blockLoading: true
|
blockLoading: true
|
||||||
blockWrites: true
|
blockWrites: true
|
||||||
atomicWrites: true
|
atomicWrites: true
|
||||||
|
printErrors: false
|
||||||
watchChanges: !isGreeterMode
|
watchChanges: !isGreeterMode
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
@@ -2668,7 +2707,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
pluginSettings = {};
|
const msg = String(error || "");
|
||||||
|
if (!_isMissingPluginSettingsError(error))
|
||||||
|
console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg);
|
||||||
|
_resetPluginSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1325,7 +1325,7 @@ Singleton {
|
|||||||
if (typeof SettingsData !== "undefined") {
|
if (typeof SettingsData !== "undefined") {
|
||||||
const skipTemplates = [];
|
const skipTemplates = [];
|
||||||
if (!SettingsData.runDmsMatugenTemplates) {
|
if (!SettingsData.runDmsMatugenTemplates) {
|
||||||
skipTemplates.push("gtk", "nvim", "niri", "qt5ct", "qt6ct", "firefox", "pywalfox", "zenbrowser", "vesktop", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode", "emacs");
|
skipTemplates.push("gtk", "nvim", "niri", "qt5ct", "qt6ct", "firefox", "pywalfox", "zenbrowser", "vesktop", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode", "emacs", "zed");
|
||||||
} else {
|
} else {
|
||||||
if (!SettingsData.matugenTemplateGtk)
|
if (!SettingsData.matugenTemplateGtk)
|
||||||
skipTemplates.push("gtk");
|
skipTemplates.push("gtk");
|
||||||
@@ -1369,6 +1369,8 @@ Singleton {
|
|||||||
skipTemplates.push("vscode");
|
skipTemplates.push("vscode");
|
||||||
if (!SettingsData.matugenTemplateEmacs)
|
if (!SettingsData.matugenTemplateEmacs)
|
||||||
skipTemplates.push("emacs");
|
skipTemplates.push("emacs");
|
||||||
|
if (!SettingsData.matugenTemplateZed)
|
||||||
|
skipTemplates.push("zed");
|
||||||
}
|
}
|
||||||
if (skipTemplates.length > 0) {
|
if (skipTemplates.length > 0) {
|
||||||
args.push("--skip-templates", skipTemplates.join(","));
|
args.push("--skip-templates", skipTemplates.join(","));
|
||||||
|
|||||||
@@ -262,12 +262,13 @@ var SPEC = {
|
|||||||
matugenTemplateKitty: { def: true },
|
matugenTemplateKitty: { def: true },
|
||||||
matugenTemplateFoot: { def: true },
|
matugenTemplateFoot: { def: true },
|
||||||
matugenTemplateAlacritty: { def: true },
|
matugenTemplateAlacritty: { def: true },
|
||||||
matugenTemplateNeovim: { def: true },
|
matugenTemplateNeovim: { def: false },
|
||||||
matugenTemplateWezterm: { def: true },
|
matugenTemplateWezterm: { def: true },
|
||||||
matugenTemplateDgop: { def: true },
|
matugenTemplateDgop: { def: true },
|
||||||
matugenTemplateKcolorscheme: { def: true },
|
matugenTemplateKcolorscheme: { def: true },
|
||||||
matugenTemplateVscode: { def: true },
|
matugenTemplateVscode: { def: true },
|
||||||
matugenTemplateEmacs: { def: true },
|
matugenTemplateEmacs: { def: true },
|
||||||
|
matugenTemplateZed: { def: true },
|
||||||
|
|
||||||
showDock: { def: false },
|
showDock: { def: false },
|
||||||
dockAutoHide: { def: false },
|
dockAutoHide: { def: false },
|
||||||
|
|||||||
@@ -154,18 +154,18 @@ Item {
|
|||||||
|
|
||||||
property string _barLayoutStateJson: {
|
property string _barLayoutStateJson: {
|
||||||
const configs = SettingsData.barConfigs;
|
const configs = SettingsData.barConfigs;
|
||||||
const mapped = configs.map(c => ({
|
const mapped = configs.map((c, i) => ({
|
||||||
id: c.id,
|
id: c.id,
|
||||||
position: c.position,
|
position: c.position,
|
||||||
autoHide: c.autoHide,
|
autoHide: c.autoHide,
|
||||||
visible: c.visible
|
visible: c.visible,
|
||||||
|
_origIndex: i
|
||||||
})).sort((a, b) => {
|
})).sort((a, b) => {
|
||||||
const aVertical = a.position === SettingsData.Position.Left || a.position === SettingsData.Position.Right;
|
const aVertical = a.position === SettingsData.Position.Left || a.position === SettingsData.Position.Right;
|
||||||
const bVertical = b.position === SettingsData.Position.Left || b.position === SettingsData.Position.Right;
|
const bVertical = b.position === SettingsData.Position.Left || b.position === SettingsData.Position.Right;
|
||||||
if (aVertical !== bVertical) {
|
if (aVertical !== bVertical)
|
||||||
return aVertical - bVertical;
|
return aVertical - bVertical;
|
||||||
}
|
return a._origIndex - b._origIndex;
|
||||||
return String(a.id).localeCompare(String(b.id));
|
|
||||||
});
|
});
|
||||||
return JSON.stringify(mapped);
|
return JSON.stringify(mapped);
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-31
@@ -21,11 +21,37 @@ Item {
|
|||||||
required property var workspaceRenameModalLoader
|
required property var workspaceRenameModalLoader
|
||||||
required property var windowRuleModalLoader
|
required property var windowRuleModalLoader
|
||||||
|
|
||||||
function getFirstBar() {
|
function getPreferredBar(refPropertyName) {
|
||||||
if (!root.dankBarRepeater || root.dankBarRepeater.count === 0)
|
if (!root.dankBarRepeater || root.dankBarRepeater.count === 0)
|
||||||
return null;
|
return null;
|
||||||
const firstLoader = root.dankBarRepeater.itemAt(0);
|
|
||||||
return firstLoader ? firstLoader.item : null;
|
const focusedScreenName = BarWidgetService.getFocusedScreenName();
|
||||||
|
|
||||||
|
const loaders = Array.from({
|
||||||
|
length: root.dankBarRepeater.count
|
||||||
|
}, (_, i) => root.dankBarRepeater.itemAt(i));
|
||||||
|
|
||||||
|
let currentBar = null;
|
||||||
|
|
||||||
|
for (const loader of loaders) {
|
||||||
|
const instances = loader?.item?.barVariants?.instances || [];
|
||||||
|
for (const bar of instances) {
|
||||||
|
if (!bar)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const onFocusedScreen = focusedScreenName && bar.modelData?.name === focusedScreenName;
|
||||||
|
const hasRef = !refPropertyName || !!bar[refPropertyName];
|
||||||
|
|
||||||
|
if (hasRef) {
|
||||||
|
currentBar = bar;
|
||||||
|
|
||||||
|
if (onFocusedScreen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
@@ -97,9 +123,9 @@ Item {
|
|||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function open(): string {
|
function open(): string {
|
||||||
const bar = root.getFirstBar();
|
const bar = root.getPreferredBar("controlCenterButtonRef");
|
||||||
if (bar) {
|
if (bar) {
|
||||||
bar.triggerControlCenterOnFocusedScreen();
|
bar.triggerControlCenter();
|
||||||
return "CONTROL_CENTER_OPEN_SUCCESS";
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
||||||
}
|
}
|
||||||
return "CONTROL_CENTER_OPEN_FAILED";
|
return "CONTROL_CENTER_OPEN_FAILED";
|
||||||
@@ -114,9 +140,14 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggle(): string {
|
function toggle(): string {
|
||||||
const bar = root.getFirstBar();
|
if (root.controlCenterLoader.item?.shouldBeVisible) {
|
||||||
|
root.controlCenterLoader.item.close();
|
||||||
|
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
const bar = root.getPreferredBar("controlCenterButtonRef");
|
||||||
if (bar) {
|
if (bar) {
|
||||||
bar.triggerControlCenterOnFocusedScreen();
|
bar.triggerControlCenter();
|
||||||
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
||||||
}
|
}
|
||||||
return "CONTROL_CENTER_TOGGLE_FAILED";
|
return "CONTROL_CENTER_TOGGLE_FAILED";
|
||||||
@@ -131,27 +162,37 @@ Item {
|
|||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function open(tab: string): string {
|
function open(tab: string): string {
|
||||||
root.dankDashPopoutLoader.active = true;
|
const bar = root.getPreferredBar("clockButtonRef");
|
||||||
if (root.dankDashPopoutLoader.item) {
|
if (!bar)
|
||||||
switch (tab.toLowerCase()) {
|
return "DASH_OPEN_FAILED";
|
||||||
case "media":
|
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = 1;
|
const dash = root.dankDashPopoutLoader.item;
|
||||||
break;
|
const onSameScreen = dash && dash.shouldBeVisible && dash.triggerScreen?.name === bar.screen?.name;
|
||||||
case "wallpaper":
|
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = 2;
|
if (!onSameScreen) {
|
||||||
break;
|
bar.triggerWallpaperBrowser();
|
||||||
case "weather":
|
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen);
|
|
||||||
root.dankDashPopoutLoader.item.dashVisible = true;
|
|
||||||
return "DASH_OPEN_SUCCESS";
|
|
||||||
}
|
}
|
||||||
return "DASH_OPEN_FAILED";
|
|
||||||
|
if (!root.dankDashPopoutLoader.item)
|
||||||
|
return "DASH_OPEN_FAILED";
|
||||||
|
|
||||||
|
switch (tab.toLowerCase()) {
|
||||||
|
case "media":
|
||||||
|
root.dankDashPopoutLoader.item.currentTabIndex = 1;
|
||||||
|
break;
|
||||||
|
case "wallpaper":
|
||||||
|
root.dankDashPopoutLoader.item.currentTabIndex = 2;
|
||||||
|
break;
|
||||||
|
case "weather":
|
||||||
|
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
root.dankDashPopoutLoader.item.currentTabIndex = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.dankDashPopoutLoader.item.dashVisible = true;
|
||||||
|
return "DASH_OPEN_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
function close(): string {
|
function close(): string {
|
||||||
@@ -163,8 +204,14 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggle(tab: string): string {
|
function toggle(tab: string): string {
|
||||||
const bar = root.getFirstBar();
|
if (root.dankDashPopoutLoader.item?.dashVisible) {
|
||||||
if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
|
root.dankDashPopoutLoader.item.dashVisible = false;
|
||||||
|
return "DASH_TOGGLE_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
const bar = root.getPreferredBar("clockButtonRef");
|
||||||
|
if (bar) {
|
||||||
|
bar.triggerWallpaperBrowser();
|
||||||
if (root.dankDashPopoutLoader.item) {
|
if (root.dankDashPopoutLoader.item) {
|
||||||
switch (tab.toLowerCase()) {
|
switch (tab.toLowerCase()) {
|
||||||
case "media":
|
case "media":
|
||||||
@@ -521,8 +568,9 @@ Item {
|
|||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function wallpaper(): string {
|
function wallpaper(): string {
|
||||||
const bar = root.getFirstBar();
|
const bar = root.getPreferredBar("clockButtonRef");
|
||||||
if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
|
if (bar) {
|
||||||
|
bar.triggerWallpaperBrowser();
|
||||||
return "SUCCESS: Toggled wallpaper browser";
|
return "SUCCESS: Toggled wallpaper browser";
|
||||||
}
|
}
|
||||||
return "ERROR: Failed to toggle wallpaper browser";
|
return "ERROR: Failed to toggle wallpaper browser";
|
||||||
|
|||||||
@@ -875,9 +875,7 @@ Item {
|
|||||||
_applyHighlights(newSections, searchQuery);
|
_applyHighlights(newSections, searchQuery);
|
||||||
flatModel = Scorer.flattenSections(newSections);
|
flatModel = Scorer.flattenSections(newSections);
|
||||||
sections = newSections;
|
sections = newSections;
|
||||||
if (selectedFlatIndex >= flatModel.length) {
|
selectedFlatIndex = getFirstItemIndex();
|
||||||
selectedFlatIndex = getFirstItemIndex();
|
|
||||||
}
|
|
||||||
updateSelectedItem();
|
updateSelectedItem();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ Item {
|
|||||||
property var spotlightContent: launcherContentLoader.item
|
property var spotlightContent: launcherContentLoader.item
|
||||||
property bool openedFromOverview: false
|
property bool openedFromOverview: false
|
||||||
property bool isClosing: false
|
property bool isClosing: false
|
||||||
property bool _windowEnabled: true
|
|
||||||
property bool _pendingInitialize: false
|
property bool _pendingInitialize: false
|
||||||
property string _pendingQuery: ""
|
property string _pendingQuery: ""
|
||||||
property string _pendingMode: ""
|
property string _pendingMode: ""
|
||||||
@@ -262,38 +261,26 @@ Item {
|
|||||||
if (Quickshell.screens.length === 0)
|
if (Quickshell.screens.length === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const screen = launcherWindow.screen;
|
const screenName = launcherWindow.screen?.name;
|
||||||
const screenName = screen?.name;
|
if (screenName) {
|
||||||
|
|
||||||
let needsReset = !screen || !screenName;
|
|
||||||
if (!needsReset) {
|
|
||||||
needsReset = true;
|
|
||||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||||
if (Quickshell.screens[i].name === screenName) {
|
if (Quickshell.screens[i].name === screenName)
|
||||||
needsReset = false;
|
return;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needsReset)
|
if (spotlightOpen)
|
||||||
return;
|
hide();
|
||||||
|
|
||||||
const newScreen = CompositorService.getFocusedScreen() ?? Quickshell.screens[0];
|
const newScreen = CompositorService.getFocusedScreen() ?? Quickshell.screens[0];
|
||||||
if (!newScreen)
|
if (newScreen)
|
||||||
return;
|
launcherWindow.screen = newScreen;
|
||||||
|
|
||||||
root._windowEnabled = false;
|
|
||||||
launcherWindow.screen = newScreen;
|
|
||||||
Qt.callLater(() => {
|
|
||||||
root._windowEnabled = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: launcherWindow
|
id: launcherWindow
|
||||||
visible: root._windowEnabled && (spotlightOpen || isClosing)
|
visible: spotlightOpen || isClosing
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
exclusionMode: ExclusionMode.Ignore
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ FocusScope {
|
|||||||
Image {
|
Image {
|
||||||
width: 40
|
width: 40
|
||||||
height: 40
|
height: 40
|
||||||
source: editingApp?.icon ? "image://icon/" + editingApp.icon : "image://icon/application-x-executable"
|
source: Paths.resolveIconUrl(editingApp?.icon || "application-x-executable")
|
||||||
sourceSize.width: 40
|
sourceSize.width: 40
|
||||||
sourceSize.height: 40
|
sourceSize.height: 40
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ Item {
|
|||||||
switch (mode) {
|
switch (mode) {
|
||||||
case "files":
|
case "files":
|
||||||
if (!DSearchService.dsearchAvailable)
|
if (!DSearchService.dsearchAvailable)
|
||||||
return I18n.tr("File search requires dsearch\nInstall from github.com/morelazers/dsearch");
|
return I18n.tr("File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch");
|
||||||
if (!hasQuery)
|
if (!hasQuery)
|
||||||
return I18n.tr("Type to search files");
|
return I18n.tr("Type to search files");
|
||||||
if (root.controller.searchQuery.length < 2)
|
if (root.controller.searchQuery.length < 2)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ DankPopout {
|
|||||||
|
|
||||||
layerNamespace: "dms:app-launcher"
|
layerNamespace: "dms:app-launcher"
|
||||||
|
|
||||||
|
readonly property real screenWidth: screen?.width ?? 1920
|
||||||
|
readonly property real screenHeight: screen?.height ?? 1080
|
||||||
|
|
||||||
property string _pendingMode: ""
|
property string _pendingMode: ""
|
||||||
property string _pendingQuery: ""
|
property string _pendingQuery: ""
|
||||||
|
|
||||||
@@ -41,8 +44,35 @@ DankPopout {
|
|||||||
openWithQuery(query);
|
openWithQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
popupWidth: 560
|
readonly property int _baseWidth: {
|
||||||
popupHeight: 640
|
switch (SettingsData.dankLauncherV2Size) {
|
||||||
|
case "micro":
|
||||||
|
return 500;
|
||||||
|
case "medium":
|
||||||
|
return 720;
|
||||||
|
case "large":
|
||||||
|
return 860;
|
||||||
|
default:
|
||||||
|
return 620;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int _baseHeight: {
|
||||||
|
switch (SettingsData.dankLauncherV2Size) {
|
||||||
|
case "micro":
|
||||||
|
return 480;
|
||||||
|
case "medium":
|
||||||
|
return 720;
|
||||||
|
case "large":
|
||||||
|
return 860;
|
||||||
|
default:
|
||||||
|
return 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popupWidth: Math.min(_baseWidth, screenWidth - 100)
|
||||||
|
popupHeight: Math.min(_baseHeight, screenHeight - 100)
|
||||||
|
|
||||||
triggerWidth: 40
|
triggerWidth: 40
|
||||||
positioning: ""
|
positioning: ""
|
||||||
contentHandlesKeys: contentLoader.item?.launcherContent?.editMode ?? false
|
contentHandlesKeys: contentLoader.item?.launcherContent?.editMode ?? false
|
||||||
|
|||||||
@@ -86,11 +86,7 @@ Variants {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (typeof blurWallpaperWindow.updatesEnabled !== "undefined")
|
if (typeof blurWallpaperWindow.updatesEnabled !== "undefined")
|
||||||
blurWallpaperWindow.updatesEnabled = Qt.binding(() => root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
|
blurWallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
|
||||||
|
|
||||||
if (!source) {
|
|
||||||
root._renderSettling = false;
|
|
||||||
}
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +109,7 @@ Variants {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: renderSettleTimer
|
id: renderSettleTimer
|
||||||
interval: 100
|
interval: 1000
|
||||||
onTriggered: root._renderSettling = false
|
onTriggered: root._renderSettling = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +167,8 @@ Variants {
|
|||||||
transitionAnimation.stop();
|
transitionAnimation.stop();
|
||||||
root.transitionProgress = 0;
|
root.transitionProgress = 0;
|
||||||
root.effectActive = false;
|
root.effectActive = false;
|
||||||
|
root._renderSettling = true;
|
||||||
|
renderSettleTimer.restart();
|
||||||
currentWallpaper.source = nextWallpaper.source;
|
currentWallpaper.source = nextWallpaper.source;
|
||||||
nextWallpaper.source = "";
|
nextWallpaper.source = "";
|
||||||
}
|
}
|
||||||
@@ -179,6 +177,9 @@ Variants {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root._renderSettling = true;
|
||||||
|
renderSettleTimer.restart();
|
||||||
|
|
||||||
nextWallpaper.source = newPath;
|
nextWallpaper.source = newPath;
|
||||||
|
|
||||||
if (nextWallpaper.status === Image.Ready)
|
if (nextWallpaper.status === Image.Ready)
|
||||||
|
|||||||
@@ -70,6 +70,16 @@ DankPopout {
|
|||||||
|
|
||||||
backgroundInteractive: !anyModalOpen
|
backgroundInteractive: !anyModalOpen
|
||||||
|
|
||||||
|
onCredentialsPromptOpenChanged: {
|
||||||
|
if (credentialsPromptOpen && shouldBeVisible)
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onPolkitModalOpenChanged: {
|
||||||
|
if (polkitModalOpen && shouldBeVisible)
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
customKeyboardFocus: {
|
customKeyboardFocus: {
|
||||||
if (!shouldBeVisible)
|
if (!shouldBeVisible)
|
||||||
return WlrKeyboardFocus.None;
|
return WlrKeyboardFocus.None;
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ PanelWindow {
|
|||||||
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
||||||
if (!onThisScreen)
|
if (!onThisScreen)
|
||||||
return false;
|
return false;
|
||||||
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
|
if (bc.showOnLastDisplay && screenName !== barWindow.screenName)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -298,7 +298,7 @@ PanelWindow {
|
|||||||
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
||||||
if (!onThisScreen)
|
if (!onThisScreen)
|
||||||
return false;
|
return false;
|
||||||
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
|
if (bc.showOnLastDisplay && screenName !== barWindow.screenName)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -322,7 +322,7 @@ PanelWindow {
|
|||||||
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
||||||
if (!onThisScreen)
|
if (!onThisScreen)
|
||||||
return false;
|
return false;
|
||||||
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
|
if (bc.showOnLastDisplay && screenName !== barWindow.screenName)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -346,7 +346,7 @@ PanelWindow {
|
|||||||
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
|
||||||
if (!onThisScreen)
|
if (!onThisScreen)
|
||||||
return false;
|
return false;
|
||||||
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
|
if (bc.showOnLastDisplay && screenName !== barWindow.screenName)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -552,8 +552,9 @@ PanelWindow {
|
|||||||
readonly property var _leftSection: topBarContent ? (barWindow.isVertical ? topBarContent.vLeftSection : topBarContent.hLeftSection) : null
|
readonly property var _leftSection: topBarContent ? (barWindow.isVertical ? topBarContent.vLeftSection : topBarContent.hLeftSection) : null
|
||||||
readonly property var _centerSection: topBarContent ? (barWindow.isVertical ? topBarContent.vCenterSection : topBarContent.hCenterSection) : null
|
readonly property var _centerSection: topBarContent ? (barWindow.isVertical ? topBarContent.vCenterSection : topBarContent.hCenterSection) : null
|
||||||
readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null
|
readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null
|
||||||
|
readonly property real _revealProgress: topBarSlide.x + topBarSlide.y
|
||||||
|
|
||||||
function sectionRect(section, isCenter) {
|
function sectionRect(section, isCenter, _dep) {
|
||||||
if (!section)
|
if (!section)
|
||||||
return {
|
return {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
@@ -582,7 +583,7 @@ PanelWindow {
|
|||||||
item: clickThroughEnabled ? null : inputMask
|
item: clickThroughEnabled ? null : inputMask
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._leftSection, false) : {
|
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._leftSection, false, barWindow._revealProgress) : {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 0,
|
"w": 0,
|
||||||
@@ -595,7 +596,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._centerSection, true) : {
|
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._centerSection, true, barWindow._revealProgress) : {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 0,
|
"w": 0,
|
||||||
@@ -608,7 +609,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._rightSection, false) : {
|
readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._rightSection, false, barWindow._revealProgress) : {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 0,
|
"w": 0,
|
||||||
@@ -619,6 +620,14 @@ PanelWindow {
|
|||||||
width: r.w
|
width: r.w
|
||||||
height: r.h
|
height: r.h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Region {
|
||||||
|
readonly property bool active: barWindow.clickThroughEnabled && !inputMask.showing
|
||||||
|
x: active ? inputMask.x : 0
|
||||||
|
y: active ? inputMask.y : 0
|
||||||
|
width: active ? inputMask.width : 0
|
||||||
|
height: active ? inputMask.height : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -631,7 +640,7 @@ PanelWindow {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: revealHold
|
id: revealHold
|
||||||
interval: barConfig?.autoHideDelay ?? 250
|
interval: barWindow.clickThroughEnabled ? Math.max((barConfig?.autoHideDelay ?? 250) * 6, 1500) : (barConfig?.autoHideDelay ?? 250)
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) {
|
if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) {
|
||||||
@@ -663,6 +672,7 @@ PanelWindow {
|
|||||||
onHasActivePopoutChanged: evaluateReveal()
|
onHasActivePopoutChanged: evaluateReveal()
|
||||||
|
|
||||||
function updateActivePopoutState() {
|
function updateActivePopoutState() {
|
||||||
|
if (!barWindow.screen) return;
|
||||||
const screenName = barWindow.screen.name;
|
const screenName = barWindow.screen.name;
|
||||||
const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
|
const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
|
||||||
const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
|
const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
|
||||||
@@ -689,7 +699,6 @@ PanelWindow {
|
|||||||
Connections {
|
Connections {
|
||||||
function onBarConfigChanged() {
|
function onBarConfigChanged() {
|
||||||
topBarCore.autoHide = barConfig?.autoHide ?? false;
|
topBarCore.autoHide = barConfig?.autoHide ?? false;
|
||||||
revealHold.interval = barConfig?.autoHideDelay ?? 250;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target: rootWindow
|
target: rootWindow
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ PanelWindow {
|
|||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: modelData.icon ? Quickshell.iconPath(modelData.icon, true) : ""
|
source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : ""
|
||||||
smooth: true
|
smooth: true
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
visible: status === Image.Ready
|
visible: status === Image.Ready
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ BasePill {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: root.vIconSize + (root.showAudioPercent ? audioPercentV.implicitHeight + 2 : 0)
|
height: root.vIconSize + (audioPercentV.visible ? audioPercentV.implicitHeight + 2 : 0)
|
||||||
visible: root.showAudioIcon
|
visible: root.showAudioIcon
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
@@ -392,7 +392,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: audioPercentV
|
id: audioPercentV
|
||||||
visible: root.showAudioPercent
|
visible: root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume)
|
||||||
text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%"
|
text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
@@ -404,7 +404,7 @@ BasePill {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: root.vIconSize + (root.showMicPercent ? micPercentV.implicitHeight + 2 : 0)
|
height: root.vIconSize + (micPercentV.visible ? micPercentV.implicitHeight + 2 : 0)
|
||||||
visible: root.showMicIcon
|
visible: root.showMicIcon
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
@@ -418,7 +418,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: micPercentV
|
id: micPercentV
|
||||||
visible: root.showMicPercent
|
visible: root.showMicPercent && isFinite(AudioService.source?.audio?.volume)
|
||||||
text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%"
|
text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
@@ -430,7 +430,7 @@ BasePill {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: root.vIconSize + (root.showBrightnessPercent ? brightnessPercentV.implicitHeight + 2 : 0)
|
height: root.vIconSize + (brightnessPercentV.visible ? brightnessPercentV.implicitHeight + 2 : 0)
|
||||||
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
|
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
@@ -444,7 +444,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: brightnessPercentV
|
id: brightnessPercentV
|
||||||
visible: root.showBrightnessPercent
|
visible: root.showBrightnessPercent && isFinite(getBrightness())
|
||||||
text: Math.round(getBrightness() * 100) + "%"
|
text: Math.round(getBrightness() * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
@@ -554,7 +554,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: audioPercent
|
id: audioPercent
|
||||||
visible: root.showAudioPercent
|
visible: root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume)
|
||||||
text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%"
|
text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
@@ -583,7 +583,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: micPercent
|
id: micPercent
|
||||||
visible: root.showMicPercent
|
visible: root.showMicPercent && isFinite(AudioService.source?.audio?.volume)
|
||||||
text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%"
|
text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
@@ -612,7 +612,7 @@ BasePill {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: brightnessPercent
|
id: brightnessPercent
|
||||||
visible: root.showBrightnessPercent
|
visible: root.showBrightnessPercent && isFinite(getBrightness())
|
||||||
text: Math.round(getBrightness() * 100) + "%"
|
text: Math.round(getBrightness() * 100) + "%"
|
||||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
|
|||||||
@@ -87,11 +87,11 @@ BasePill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId);
|
const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId);
|
||||||
return workspaceWindows.length > 0 && activeWindow && activeWindow.title;
|
return workspaceWindows.length > 0 && activeWindow && (activeWindow.title || activeWindow.appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CompositorService.isHyprland) {
|
if (CompositorService.isHyprland) {
|
||||||
if (!Hyprland.focusedWorkspace || !activeWindow || !activeWindow.title) {
|
if (!Hyprland.focusedWorkspace || !activeWindow || !(activeWindow.title || activeWindow.appId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return activeWindow && activeWindow.title;
|
return activeWindow && (activeWindow.title || activeWindow.appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0
|
width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0
|
||||||
@@ -211,17 +211,20 @@ BasePill {
|
|||||||
text: {
|
text: {
|
||||||
const title = activeWindow && activeWindow.title ? activeWindow.title : "";
|
const title = activeWindow && activeWindow.title ? activeWindow.title : "";
|
||||||
const appName = appText.text;
|
const appName = appText.text;
|
||||||
if (!title || !appName) {
|
|
||||||
|
if (compactMode) {
|
||||||
|
if (!title || title === appName)
|
||||||
|
return title || appName;
|
||||||
|
if (title.endsWith(appName))
|
||||||
|
return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, "") || appName;
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title.endsWith(" - " + appName)) {
|
if (!title || !appName)
|
||||||
return title.substring(0, title.length - (" - " + appName).length);
|
return title;
|
||||||
}
|
|
||||||
|
|
||||||
if (title.endsWith(appName)) {
|
if (title.endsWith(appName))
|
||||||
return title.substring(0, title.length - appName.length).replace(/ - $/, "");
|
return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, "");
|
||||||
}
|
|
||||||
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ BasePill {
|
|||||||
return `${id}::${tooltipTitle}`;
|
return `${id}::${tooltipTitle}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ! TODO - replace with either native dbus client (like plugins use) or just a DMS cli or something
|
||||||
|
function callContextMenuFallback(trayItemId, globalX, globalY) {
|
||||||
|
const script = ['ITEMS=$(dbus-send --session --print-reply --dest=org.kde.StatusNotifierWatcher /StatusNotifierWatcher org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierWatcher string:RegisteredStatusNotifierItems 2>/dev/null)', 'while IFS= read -r line; do', ' line="${line#*\\\"}"', ' line="${line%\\\"*}"', ' [ -z "$line" ] && continue', ' BUS="${line%%/*}"', ' OBJ="/${line#*/}"', ' ID=$(dbus-send --session --print-reply --dest="$BUS" "$OBJ" org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierItem string:Id 2>/dev/null | grep -oP "(?<=\\\")(.*?)(?=\\\")" | tail -1)', ' if [ "$ID" = "$1" ]; then', ' dbus-send --session --type=method_call --dest="$BUS" "$OBJ" org.kde.StatusNotifierItem.ContextMenu int32:"$2" int32:"$3"', ' exit 0', ' fi', 'done <<< "$ITEMS"',].join("\n");
|
||||||
|
Quickshell.execDetached(["bash", "-c", script, "_", trayItemId, String(globalX), String(globalY)]);
|
||||||
|
}
|
||||||
|
|
||||||
property int _trayOrderTrigger: 0
|
property int _trayOrderTrigger: 0
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -380,8 +386,11 @@ BasePill {
|
|||||||
return;
|
return;
|
||||||
if (mouse.button !== Qt.RightButton)
|
if (mouse.button !== Qt.RightButton)
|
||||||
return;
|
return;
|
||||||
if (!delegateRoot.trayItem?.hasMenu)
|
if (!delegateRoot.trayItem?.hasMenu) {
|
||||||
|
const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y);
|
||||||
|
root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
root.menuOpen = false;
|
root.menuOpen = false;
|
||||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||||
}
|
}
|
||||||
@@ -637,8 +646,11 @@ BasePill {
|
|||||||
return;
|
return;
|
||||||
if (mouse.button !== Qt.RightButton)
|
if (mouse.button !== Qt.RightButton)
|
||||||
return;
|
return;
|
||||||
if (!delegateRoot.trayItem?.hasMenu)
|
if (!delegateRoot.trayItem?.hasMenu) {
|
||||||
|
const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y);
|
||||||
|
root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
root.menuOpen = false;
|
root.menuOpen = false;
|
||||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||||
}
|
}
|
||||||
@@ -1065,9 +1077,11 @@ BasePill {
|
|||||||
root.menuOpen = false;
|
root.menuOpen = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!trayItem.hasMenu) {
|
||||||
if (!trayItem.hasMenu)
|
const gp = itemArea.mapToGlobal(mouse.x, mouse.y);
|
||||||
|
root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -775,6 +775,11 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onWheel: wheel => {
|
onWheel: wheel => {
|
||||||
|
if (Math.abs(wheel.angleDelta.x) > Math.abs(wheel.angleDelta.y)) {
|
||||||
|
wheel.accepted = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (scrollInProgress)
|
if (scrollInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -447,9 +447,8 @@ Variants {
|
|||||||
|
|
||||||
height: {
|
height: {
|
||||||
if (dock.isVertical) {
|
if (dock.isVertical) {
|
||||||
if (!dock.reveal)
|
// Keep the taller hit area regardless of the reveal state to prevent shrinking loop
|
||||||
return Math.min(Math.max(dockBackground.height + 64, 200), screenHeight * 0.5);
|
return Math.min(Math.max(dockBackground.height + 64, 200), screenHeight * 0.5);
|
||||||
return Math.min(dockBackground.height + 8 + dock.borderThickness, maxDockHeight);
|
|
||||||
}
|
}
|
||||||
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
||||||
}
|
}
|
||||||
@@ -457,8 +456,7 @@ Variants {
|
|||||||
if (dock.isVertical) {
|
if (dock.isVertical) {
|
||||||
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
||||||
}
|
}
|
||||||
if (!dock.reveal)
|
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
|
||||||
return Math.min(Math.max(dockBackground.width + 64, 200), screenWidth * 0.5);
|
|
||||||
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
|
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
|
||||||
}
|
}
|
||||||
anchors {
|
anchors {
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ PanelWindow {
|
|||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: modelData.icon ? Quickshell.iconPath(modelData.icon, true) : ""
|
source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : ""
|
||||||
smooth: true
|
smooth: true
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
visible: status === Image.Ready
|
visible: status === Image.Ready
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ Singleton {
|
|||||||
property string lockDateFormat: ""
|
property string lockDateFormat: ""
|
||||||
property bool lockScreenShowPowerActions: true
|
property bool lockScreenShowPowerActions: true
|
||||||
property bool lockScreenShowProfileImage: true
|
property bool lockScreenShowProfileImage: true
|
||||||
|
property bool powerActionConfirm: true
|
||||||
|
property real powerActionHoldDuration: 0.5
|
||||||
|
property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]
|
||||||
|
property string powerMenuDefaultAction: "logout"
|
||||||
|
property bool powerMenuGridLayout: false
|
||||||
property var screenPreferences: ({})
|
property var screenPreferences: ({})
|
||||||
property int animationSpeed: 2
|
property int animationSpeed: 2
|
||||||
property string wallpaperFillMode: "Fill"
|
property string wallpaperFillMode: "Fill"
|
||||||
@@ -75,6 +80,11 @@ Singleton {
|
|||||||
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : "";
|
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : "";
|
||||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true;
|
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true;
|
||||||
lockScreenShowProfileImage = settings.lockScreenShowProfileImage !== undefined ? settings.lockScreenShowProfileImage : true;
|
lockScreenShowProfileImage = settings.lockScreenShowProfileImage !== undefined ? settings.lockScreenShowProfileImage : true;
|
||||||
|
powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true;
|
||||||
|
powerActionHoldDuration = settings.powerActionHoldDuration !== undefined ? settings.powerActionHoldDuration : 0.5;
|
||||||
|
powerMenuActions = settings.powerMenuActions !== undefined ? settings.powerMenuActions : ["reboot", "logout", "poweroff", "lock", "suspend", "restart"];
|
||||||
|
powerMenuDefaultAction = settings.powerMenuDefaultAction !== undefined ? settings.powerMenuDefaultAction : "logout";
|
||||||
|
powerMenuGridLayout = settings.powerMenuGridLayout !== undefined ? settings.powerMenuGridLayout : false;
|
||||||
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({});
|
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({});
|
||||||
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2;
|
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2;
|
||||||
wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill";
|
wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill";
|
||||||
|
|||||||
@@ -1231,6 +1231,12 @@ Item {
|
|||||||
LockPowerMenu {
|
LockPowerMenu {
|
||||||
id: powerMenu
|
id: powerMenu
|
||||||
showLogout: false
|
showLogout: false
|
||||||
|
powerActionConfirmOverride: GreetdSettings.powerActionConfirm
|
||||||
|
powerActionHoldDurationOverride: GreetdSettings.powerActionHoldDuration
|
||||||
|
powerMenuActionsOverride: GreetdSettings.powerMenuActions
|
||||||
|
powerMenuDefaultActionOverride: GreetdSettings.powerMenuDefaultAction
|
||||||
|
powerMenuGridLayoutOverride: GreetdSettings.powerMenuGridLayout
|
||||||
|
requiredActions: ["poweroff"]
|
||||||
onClosed: {
|
onClosed: {
|
||||||
if (isPrimaryScreen && inputField && inputField.forceActiveFocus) {
|
if (isPrimaryScreen && inputField && inputField.forceActiveFocus) {
|
||||||
Qt.callLater(() => inputField.forceActiveFocus());
|
Qt.callLater(() => inputField.forceActiveFocus());
|
||||||
|
|||||||
@@ -24,13 +24,20 @@ Rectangle {
|
|||||||
property real holdProgress: 0
|
property real holdProgress: 0
|
||||||
property bool showHoldHint: false
|
property bool showHoldHint: false
|
||||||
|
|
||||||
readonly property bool needsConfirmation: SettingsData.powerActionConfirm
|
property var powerActionConfirmOverride: undefined
|
||||||
readonly property int holdDurationMs: SettingsData.powerActionHoldDuration * 1000
|
property var powerActionHoldDurationOverride: undefined
|
||||||
|
property var powerMenuActionsOverride: undefined
|
||||||
|
property var powerMenuDefaultActionOverride: undefined
|
||||||
|
property var powerMenuGridLayoutOverride: undefined
|
||||||
|
property var requiredActions: []
|
||||||
|
|
||||||
|
readonly property bool needsConfirmation: powerActionConfirmOverride !== undefined ? powerActionConfirmOverride : SettingsData.powerActionConfirm
|
||||||
|
readonly property int holdDurationMs: (powerActionHoldDurationOverride !== undefined ? powerActionHoldDurationOverride : SettingsData.powerActionHoldDuration) * 1000
|
||||||
|
|
||||||
signal closed
|
signal closed
|
||||||
|
|
||||||
function updateVisibleActions() {
|
function updateVisibleActions() {
|
||||||
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"];
|
const allActions = powerMenuActionsOverride !== undefined ? powerMenuActionsOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"]);
|
||||||
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false;
|
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false;
|
||||||
let filtered = allActions.filter(action => {
|
let filtered = allActions.filter(action => {
|
||||||
if (action === "hibernate" && !hibernateSupported)
|
if (action === "hibernate" && !hibernateSupported)
|
||||||
@@ -44,9 +51,14 @@ Rectangle {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const action of requiredActions) {
|
||||||
|
if (!filtered.includes(action))
|
||||||
|
filtered.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
visibleActions = filtered;
|
visibleActions = filtered;
|
||||||
|
|
||||||
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false;
|
useGridLayout = powerMenuGridLayoutOverride !== undefined ? powerMenuGridLayoutOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false);
|
||||||
if (!useGridLayout)
|
if (!useGridLayout)
|
||||||
return;
|
return;
|
||||||
const count = visibleActions.length;
|
const count = visibleActions.length;
|
||||||
@@ -73,7 +85,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultActionIndex() {
|
function getDefaultActionIndex() {
|
||||||
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend";
|
const defaultAction = powerMenuDefaultActionOverride !== undefined ? powerMenuDefaultActionOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend");
|
||||||
const index = visibleActions.indexOf(defaultAction);
|
const index = visibleActions.indexOf(defaultAction);
|
||||||
return index >= 0 ? index : 0;
|
return index >= 0 ? index : 0;
|
||||||
}
|
}
|
||||||
@@ -780,8 +792,9 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
readonly property real totalMs: SettingsData.powerActionHoldDuration * 1000
|
readonly property real totalMs: root.holdDurationMs
|
||||||
readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress))
|
readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress))
|
||||||
|
readonly property real durationSec: root.holdDurationMs / 1000
|
||||||
text: {
|
text: {
|
||||||
if (root.showHoldHint)
|
if (root.showHoldHint)
|
||||||
return I18n.tr("Hold longer to confirm");
|
return I18n.tr("Hold longer to confirm");
|
||||||
@@ -792,7 +805,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
if (totalMs < 1000)
|
if (totalMs < 1000)
|
||||||
return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs);
|
return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs);
|
||||||
return I18n.tr("Hold to confirm (%1s)").arg(SettingsData.powerActionHoldDuration);
|
return I18n.tr("Hold to confirm (%1s)").arg(durationSec);
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
|
|||||||
@@ -122,12 +122,12 @@ Rectangle {
|
|||||||
return "";
|
return "";
|
||||||
const appIcon = historyItem.appIcon;
|
const appIcon = historyItem.appIcon;
|
||||||
if (!appIcon)
|
if (!appIcon)
|
||||||
return iconFromImage ? "image://icon/" + iconFromImage : "";
|
return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : "";
|
||||||
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
||||||
return appIcon;
|
return appIcon;
|
||||||
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
||||||
return "";
|
return "";
|
||||||
return Quickshell.iconPath(appIcon, true);
|
return Paths.resolveIconPath(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasImage: hasNotificationImage
|
hasImage: hasNotificationImage
|
||||||
|
|||||||
@@ -169,12 +169,12 @@ Rectangle {
|
|||||||
return "";
|
return "";
|
||||||
const appIcon = notificationGroup?.latestNotification?.appIcon;
|
const appIcon = notificationGroup?.latestNotification?.appIcon;
|
||||||
if (!appIcon)
|
if (!appIcon)
|
||||||
return iconFromImage ? "image://icon/" + iconFromImage : "";
|
return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : "";
|
||||||
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
||||||
return appIcon;
|
return appIcon;
|
||||||
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
||||||
return "";
|
return "";
|
||||||
return Quickshell.iconPath(appIcon, true);
|
return Paths.resolveIconPath(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasImage: hasNotificationImage
|
hasImage: hasNotificationImage
|
||||||
@@ -503,12 +503,12 @@ Rectangle {
|
|||||||
return "";
|
return "";
|
||||||
const appIcon = modelData?.appIcon;
|
const appIcon = modelData?.appIcon;
|
||||||
if (!appIcon)
|
if (!appIcon)
|
||||||
return iconFromImage ? "image://icon/" + iconFromImage : "";
|
return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : "";
|
||||||
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
||||||
return appIcon;
|
return appIcon;
|
||||||
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
||||||
return "";
|
return "";
|
||||||
return Quickshell.iconPath(appIcon, true);
|
return Paths.resolveIconPath(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
fallbackIcon: {
|
fallbackIcon: {
|
||||||
|
|||||||
@@ -479,12 +479,12 @@ PanelWindow {
|
|||||||
return "";
|
return "";
|
||||||
const appIcon = notificationData.appIcon;
|
const appIcon = notificationData.appIcon;
|
||||||
if (!appIcon)
|
if (!appIcon)
|
||||||
return iconFromImage ? "image://icon/" + iconFromImage : "";
|
return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : "";
|
||||||
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/"))
|
||||||
return appIcon;
|
return appIcon;
|
||||||
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:"))
|
||||||
return "";
|
return "";
|
||||||
return Quickshell.iconPath(appIcon, true);
|
return Paths.resolveIconPath(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasImage: hasNotificationImage
|
hasImage: hasNotificationImage
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ DankOSD {
|
|||||||
let icon = "music_note";
|
let icon = "music_note";
|
||||||
switch (player.playbackState) {
|
switch (player.playbackState) {
|
||||||
case MprisPlaybackState.Playing:
|
case MprisPlaybackState.Playing:
|
||||||
icon = "play_arrow";
|
icon = "pause";
|
||||||
break;
|
break;
|
||||||
case MprisPlaybackState.Paused:
|
case MprisPlaybackState.Paused:
|
||||||
case MprisPlaybackState.Stopped:
|
case MprisPlaybackState.Stopped:
|
||||||
icon = "pause";
|
icon = "play_arrow";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (icon === _displayIcon)
|
if (icon === _displayIcon)
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ Item {
|
|||||||
Loader {
|
Loader {
|
||||||
id: contentLoader
|
id: contentLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
active: root.widgetEnabled && root.activeComponent !== null
|
||||||
sourceComponent: root.activeComponent
|
sourceComponent: root.activeComponent
|
||||||
|
|
||||||
function reloadComponent() {
|
function reloadComponent() {
|
||||||
|
|||||||
@@ -897,7 +897,7 @@ Item {
|
|||||||
Image {
|
Image {
|
||||||
width: 24
|
width: 24
|
||||||
height: 24
|
height: 24
|
||||||
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
|
source: Paths.resolveIconUrl(modelData.icon || "application-x-executable")
|
||||||
sourceSize.width: 24
|
sourceSize.width: 24
|
||||||
sourceSize.height: 24
|
sourceSize.height: 24
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
@@ -1008,7 +1008,7 @@ Item {
|
|||||||
Image {
|
Image {
|
||||||
width: 24
|
width: 24
|
||||||
height: 24
|
height: 24
|
||||||
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
|
source: Paths.resolveIconUrl(modelData.icon || "application-x-executable")
|
||||||
sourceSize.width: 24
|
sourceSize.width: 24
|
||||||
sourceSize.height: 24
|
sourceSize.height: 24
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
@@ -1154,7 +1154,7 @@ Item {
|
|||||||
Image {
|
Image {
|
||||||
width: 24
|
width: 24
|
||||||
height: 24
|
height: 24
|
||||||
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
|
source: Paths.resolveIconUrl(modelData.icon || "application-x-executable")
|
||||||
sourceSize.width: 24
|
sourceSize.width: 24
|
||||||
sourceSize.height: 24
|
sourceSize.height: 24
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ Item {
|
|||||||
var out = [];
|
var out = [];
|
||||||
for (var i = 0; i < rules.length; i++) {
|
for (var i = 0; i < rules.length; i++) {
|
||||||
if ((rules[i].action || "").toString().toLowerCase() === "mute")
|
if ((rules[i].action || "").toString().toLowerCase() === "mute")
|
||||||
out.push({ rule: rules[i], index: i });
|
out.push({
|
||||||
|
rule: rules[i],
|
||||||
|
index: i
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -340,6 +343,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
|
id: animationDurationSlider
|
||||||
settingKey: "notificationCustomAnimationDuration"
|
settingKey: "notificationCustomAnimationDuration"
|
||||||
tags: ["notification", "animation", "duration", "custom", "speed"]
|
tags: ["notification", "animation", "duration", "custom", "speed"]
|
||||||
text: I18n.tr("Duration")
|
text: I18n.tr("Duration")
|
||||||
@@ -355,6 +359,13 @@ Item {
|
|||||||
}
|
}
|
||||||
SettingsData.set("notificationCustomAnimationDuration", newValue);
|
SettingsData.set("notificationCustomAnimationDuration", newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Theme
|
||||||
|
function onNotificationAnimationBaseDurationChanged() {
|
||||||
|
animationDurationSlider.value = Theme.notificationAnimationBaseDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -408,6 +408,8 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
clip: true
|
clip: true
|
||||||
visible: !root.isLoading
|
visible: !root.isLoading
|
||||||
|
add: null
|
||||||
|
displaced: null
|
||||||
|
|
||||||
ScrollBar.vertical: DankScrollbar {
|
ScrollBar.vertical: DankScrollbar {
|
||||||
id: browserScrollbar
|
id: browserScrollbar
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import QtCore
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.FileBrowser
|
import qs.Modals.FileBrowser
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -742,234 +741,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
|
||||||
id: variantSelector
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
visible: activeThemeId !== "" && activeThemeVariants !== null && (isMultiVariant || (activeThemeVariants.options && activeThemeVariants.options.length > 0))
|
|
||||||
|
|
||||||
property string activeThemeId: {
|
|
||||||
if (Theme.currentThemeCategory !== "registry" || Theme.currentTheme !== "custom")
|
|
||||||
return "";
|
|
||||||
for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) {
|
|
||||||
var t = themeColorsTab.installedRegistryThemes[i];
|
|
||||||
if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json"))
|
|
||||||
return t.id;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
property var activeThemeVariants: {
|
|
||||||
if (!activeThemeId)
|
|
||||||
return null;
|
|
||||||
for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) {
|
|
||||||
var t = themeColorsTab.installedRegistryThemes[i];
|
|
||||||
if (t.id === activeThemeId && t.hasVariants)
|
|
||||||
return t.variants;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
property bool isMultiVariant: activeThemeVariants?.type === "multi"
|
|
||||||
property string colorMode: Theme.isLightMode ? "light" : "dark"
|
|
||||||
property var multiDefaults: {
|
|
||||||
if (!isMultiVariant || !activeThemeVariants?.defaults)
|
|
||||||
return {};
|
|
||||||
return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {};
|
|
||||||
}
|
|
||||||
property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults, colorMode) : multiDefaults
|
|
||||||
property string selectedFlavor: {
|
|
||||||
var sf = storedMulti.flavor || multiDefaults.flavor || "";
|
|
||||||
for (var i = 0; i < flavorOptions.length; i++) {
|
|
||||||
if (flavorOptions[i].id === sf)
|
|
||||||
return sf;
|
|
||||||
}
|
|
||||||
if (flavorOptions.length > 0)
|
|
||||||
return flavorOptions[0].id;
|
|
||||||
return sf;
|
|
||||||
}
|
|
||||||
property string selectedAccent: storedMulti.accent || multiDefaults.accent || ""
|
|
||||||
property var flavorOptions: {
|
|
||||||
if (!isMultiVariant || !activeThemeVariants?.flavors)
|
|
||||||
return [];
|
|
||||||
return activeThemeVariants.flavors.filter(f => {
|
|
||||||
if (f.mode)
|
|
||||||
return f.mode === colorMode || f.mode === "both";
|
|
||||||
return !!f[colorMode];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
property var flavorNames: flavorOptions.map(f => f.name)
|
|
||||||
property int flavorIndex: {
|
|
||||||
for (var i = 0; i < flavorOptions.length; i++) {
|
|
||||||
if (flavorOptions[i].id === selectedFlavor)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
property string selectedVariant: activeThemeId ? SettingsData.getRegistryThemeVariant(activeThemeId, activeThemeVariants?.default || "") : ""
|
|
||||||
property var variantNames: {
|
|
||||||
if (!activeThemeVariants?.options)
|
|
||||||
return [];
|
|
||||||
return activeThemeVariants.options.map(v => v.name);
|
|
||||||
}
|
|
||||||
property int selectedIndex: {
|
|
||||||
if (!activeThemeVariants?.options || !selectedVariant)
|
|
||||||
return 0;
|
|
||||||
for (var i = 0; i < activeThemeVariants.options.length; i++) {
|
|
||||||
if (activeThemeVariants.options[i].id === selectedVariant)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: flavorButtonGroup.implicitHeight
|
|
||||||
clip: true
|
|
||||||
visible: variantSelector.isMultiVariant && variantSelector.flavorOptions.length > 1
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
id: flavorButtonGroup
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
property int _count: variantSelector.flavorNames.length
|
|
||||||
property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width
|
|
||||||
buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL)
|
|
||||||
minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem)))
|
|
||||||
textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium)
|
|
||||||
checkEnabled: _maxPerItem >= 55
|
|
||||||
property int pendingIndex: -1
|
|
||||||
model: variantSelector.flavorNames
|
|
||||||
currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.flavorIndex
|
|
||||||
selectionMode: "single"
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
pendingIndex = index;
|
|
||||||
}
|
|
||||||
onAnimationCompleted: {
|
|
||||||
if (pendingIndex < 0 || pendingIndex >= variantSelector.flavorOptions.length)
|
|
||||||
return;
|
|
||||||
const flavorId = variantSelector.flavorOptions[pendingIndex]?.id;
|
|
||||||
const idx = pendingIndex;
|
|
||||||
pendingIndex = -1;
|
|
||||||
if (!flavorId || flavorId === variantSelector.selectedFlavor)
|
|
||||||
return;
|
|
||||||
Theme.screenTransition();
|
|
||||||
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent, variantSelector.colorMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: accentColorsGrid.implicitHeight
|
|
||||||
visible: variantSelector.isMultiVariant && variantSelector.activeThemeVariants?.accents?.length > 0
|
|
||||||
|
|
||||||
Grid {
|
|
||||||
id: accentColorsGrid
|
|
||||||
property int accentCount: variantSelector.activeThemeVariants?.accents?.length ?? 0
|
|
||||||
property int dotSize: parent.width < 300 ? 28 : 32
|
|
||||||
columns: accentCount > 0 ? Math.ceil(accentCount / 2) : 1
|
|
||||||
rowSpacing: Theme.spacingS
|
|
||||||
columnSpacing: Theme.spacingS
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: variantSelector.activeThemeVariants?.accents || []
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
required property var modelData
|
|
||||||
required property int index
|
|
||||||
property string accentId: modelData.id
|
|
||||||
property bool isSelected: accentId === variantSelector.selectedAccent
|
|
||||||
width: accentColorsGrid.dotSize
|
|
||||||
height: accentColorsGrid.dotSize
|
|
||||||
radius: width / 2
|
|
||||||
color: modelData.color || Theme.primary
|
|
||||||
border.color: Theme.outline
|
|
||||||
border.width: isSelected ? 2 : 1
|
|
||||||
scale: isSelected ? 1.1 : 1
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: accentNameText.contentWidth + Theme.spacingS * 2
|
|
||||||
height: accentNameText.contentHeight + Theme.spacingXS * 2
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
anchors.bottom: parent.top
|
|
||||||
anchors.bottomMargin: Theme.spacingXS
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: accentMouseArea.containsMouse
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: accentNameText
|
|
||||||
text: modelData.name
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: accentMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (parent.isSelected)
|
|
||||||
return;
|
|
||||||
Theme.screenTransition();
|
|
||||||
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId, variantSelector.colorMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on scale {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: variantButtonGroup.implicitHeight
|
|
||||||
clip: true
|
|
||||||
visible: !variantSelector.isMultiVariant && variantSelector.variantNames.length > 0
|
|
||||||
|
|
||||||
DankButtonGroup {
|
|
||||||
id: variantButtonGroup
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
property int _count: variantSelector.variantNames.length
|
|
||||||
property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width
|
|
||||||
buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL)
|
|
||||||
minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem)))
|
|
||||||
textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium)
|
|
||||||
checkEnabled: _maxPerItem >= 55
|
|
||||||
property int pendingIndex: -1
|
|
||||||
model: variantSelector.variantNames
|
|
||||||
currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.selectedIndex
|
|
||||||
selectionMode: "single"
|
|
||||||
onSelectionChanged: (index, selected) => {
|
|
||||||
if (!selected)
|
|
||||||
return;
|
|
||||||
pendingIndex = index;
|
|
||||||
}
|
|
||||||
onAnimationCompleted: {
|
|
||||||
if (pendingIndex < 0 || !variantSelector.activeThemeVariants?.options)
|
|
||||||
return;
|
|
||||||
const variantId = variantSelector.activeThemeVariants.options[pendingIndex]?.id;
|
|
||||||
const idx = pendingIndex;
|
|
||||||
pendingIndex = -1;
|
|
||||||
if (!variantId || variantId === variantSelector.selectedVariant)
|
|
||||||
return;
|
|
||||||
Theme.screenTransition();
|
|
||||||
SettingsData.setRegistryThemeVariant(variantSelector.activeThemeId, variantId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("No themes installed. Browse themes to install from the registry.", "no registry themes installed hint")
|
text: I18n.tr("No themes installed. Browse themes to install from the registry.", "no registry themes installed hint")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
@@ -987,6 +758,248 @@ Item {
|
|||||||
onClicked: showThemeBrowser()
|
onClicked: showThemeBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: variantSelector
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
visible: activeThemeId !== "" && activeThemeVariants !== null && (isMultiVariant || (activeThemeVariants.options && activeThemeVariants.options.length > 0))
|
||||||
|
|
||||||
|
property string activeThemeId: {
|
||||||
|
switch (Theme.currentThemeCategory) {
|
||||||
|
case "registry":
|
||||||
|
if (Theme.currentTheme !== "custom")
|
||||||
|
return "";
|
||||||
|
for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) {
|
||||||
|
var t = themeColorsTab.installedRegistryThemes[i];
|
||||||
|
if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json"))
|
||||||
|
return t.id;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
case "custom":
|
||||||
|
return Theme.currentThemeId || "";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var activeThemeVariants: {
|
||||||
|
if (!activeThemeId)
|
||||||
|
return null;
|
||||||
|
switch (Theme.currentThemeCategory) {
|
||||||
|
case "registry":
|
||||||
|
for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) {
|
||||||
|
var t = themeColorsTab.installedRegistryThemes[i];
|
||||||
|
if (t.id === activeThemeId && t.hasVariants)
|
||||||
|
return t.variants;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
case "custom":
|
||||||
|
return Theme.currentThemeVariants || null;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property bool isMultiVariant: activeThemeVariants?.type === "multi"
|
||||||
|
property string colorMode: Theme.isLightMode ? "light" : "dark"
|
||||||
|
property var multiDefaults: {
|
||||||
|
if (!isMultiVariant || !activeThemeVariants?.defaults)
|
||||||
|
return {};
|
||||||
|
return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {};
|
||||||
|
}
|
||||||
|
property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults, colorMode) : multiDefaults
|
||||||
|
property string selectedFlavor: {
|
||||||
|
var sf = storedMulti.flavor || multiDefaults.flavor || "";
|
||||||
|
for (var i = 0; i < flavorOptions.length; i++) {
|
||||||
|
if (flavorOptions[i].id === sf)
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
if (flavorOptions.length > 0)
|
||||||
|
return flavorOptions[0].id;
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
property string selectedAccent: storedMulti.accent || multiDefaults.accent || ""
|
||||||
|
property var flavorOptions: {
|
||||||
|
if (!isMultiVariant || !activeThemeVariants?.flavors)
|
||||||
|
return [];
|
||||||
|
return activeThemeVariants.flavors.filter(f => {
|
||||||
|
if (f.mode)
|
||||||
|
return f.mode === colorMode || f.mode === "both";
|
||||||
|
return !!f[colorMode];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
property var flavorNames: flavorOptions.map(f => f.name)
|
||||||
|
property int flavorIndex: {
|
||||||
|
for (var i = 0; i < flavorOptions.length; i++) {
|
||||||
|
if (flavorOptions[i].id === selectedFlavor)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
property string selectedVariant: activeThemeId ? SettingsData.getRegistryThemeVariant(activeThemeId, activeThemeVariants?.default || "") : ""
|
||||||
|
property var variantNames: {
|
||||||
|
if (!activeThemeVariants?.options)
|
||||||
|
return [];
|
||||||
|
return activeThemeVariants.options.map(v => v.name);
|
||||||
|
}
|
||||||
|
property int selectedIndex: {
|
||||||
|
if (!activeThemeVariants?.options || !selectedVariant)
|
||||||
|
return 0;
|
||||||
|
for (var i = 0; i < activeThemeVariants.options.length; i++) {
|
||||||
|
if (activeThemeVariants.options[i].id === selectedVariant)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: flavorButtonGroup.implicitHeight
|
||||||
|
clip: true
|
||||||
|
visible: variantSelector.isMultiVariant && variantSelector.flavorOptions.length > 1
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: flavorButtonGroup
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
property int _count: variantSelector.flavorNames.length
|
||||||
|
property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width
|
||||||
|
buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL)
|
||||||
|
minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem)))
|
||||||
|
textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium)
|
||||||
|
checkEnabled: _maxPerItem >= 55
|
||||||
|
property int pendingIndex: -1
|
||||||
|
model: variantSelector.flavorNames
|
||||||
|
currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.flavorIndex
|
||||||
|
selectionMode: "single"
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
pendingIndex = index;
|
||||||
|
}
|
||||||
|
onAnimationCompleted: {
|
||||||
|
if (pendingIndex < 0 || pendingIndex >= variantSelector.flavorOptions.length)
|
||||||
|
return;
|
||||||
|
const flavorId = variantSelector.flavorOptions[pendingIndex]?.id;
|
||||||
|
const idx = pendingIndex;
|
||||||
|
pendingIndex = -1;
|
||||||
|
if (!flavorId || flavorId === variantSelector.selectedFlavor)
|
||||||
|
return;
|
||||||
|
Theme.screenTransition();
|
||||||
|
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent, variantSelector.colorMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: accentColorsGrid.implicitHeight
|
||||||
|
visible: variantSelector.isMultiVariant && variantSelector.activeThemeVariants?.accents?.length > 0
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: accentColorsGrid
|
||||||
|
property int accentCount: variantSelector.activeThemeVariants?.accents?.length ?? 0
|
||||||
|
property int dotSize: parent.width < 300 ? 28 : 32
|
||||||
|
columns: accentCount > 0 ? Math.ceil(accentCount / 2) : 1
|
||||||
|
rowSpacing: Theme.spacingS
|
||||||
|
columnSpacing: Theme.spacingS
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: variantSelector.activeThemeVariants?.accents || []
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
property string accentId: modelData.id
|
||||||
|
property bool isSelected: accentId === variantSelector.selectedAccent
|
||||||
|
width: accentColorsGrid.dotSize
|
||||||
|
height: accentColorsGrid.dotSize
|
||||||
|
radius: width / 2
|
||||||
|
color: modelData.color || modelData[variantSelector.selectedFlavor]?.primary || Theme.primary
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: isSelected ? 2 : 1
|
||||||
|
scale: isSelected ? 1.1 : 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: accentNameText.contentWidth + Theme.spacingS * 2
|
||||||
|
height: accentNameText.contentHeight + Theme.spacingXS * 2
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: Theme.spacingXS
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
visible: accentMouseArea.containsMouse
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: accentNameText
|
||||||
|
text: modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: accentMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (parent.isSelected)
|
||||||
|
return;
|
||||||
|
Theme.screenTransition();
|
||||||
|
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId, variantSelector.colorMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: variantButtonGroup.implicitHeight
|
||||||
|
clip: true
|
||||||
|
visible: !variantSelector.isMultiVariant && variantSelector.variantNames.length > 0
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: variantButtonGroup
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
property int _count: variantSelector.variantNames.length
|
||||||
|
property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width
|
||||||
|
buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL)
|
||||||
|
minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem)))
|
||||||
|
textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium)
|
||||||
|
checkEnabled: _maxPerItem >= 55
|
||||||
|
property int pendingIndex: -1
|
||||||
|
model: variantSelector.variantNames
|
||||||
|
currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.selectedIndex
|
||||||
|
selectionMode: "single"
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
pendingIndex = index;
|
||||||
|
}
|
||||||
|
onAnimationCompleted: {
|
||||||
|
if (pendingIndex < 0 || !variantSelector.activeThemeVariants?.options)
|
||||||
|
return;
|
||||||
|
const variantId = variantSelector.activeThemeVariants.options[pendingIndex]?.id;
|
||||||
|
const idx = pendingIndex;
|
||||||
|
pendingIndex = -1;
|
||||||
|
if (!variantId || variantId === variantSelector.selectedVariant)
|
||||||
|
return;
|
||||||
|
Theme.screenTransition();
|
||||||
|
SettingsData.setRegistryThemeVariant(variantSelector.activeThemeId, variantId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2416,6 +2429,18 @@ Item {
|
|||||||
checked: SettingsData.matugenTemplateEmacs
|
checked: SettingsData.matugenTemplateEmacs
|
||||||
onToggled: checked => SettingsData.set("matugenTemplateEmacs", checked)
|
onToggled: checked => SettingsData.set("matugenTemplateEmacs", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
tab: "theme"
|
||||||
|
tags: ["matugen", "zed", "template"]
|
||||||
|
settingKey: "matugenTemplateZed"
|
||||||
|
text: "Zed"
|
||||||
|
description: getTemplateDescription("zed", "")
|
||||||
|
descriptionColor: getTemplateDescriptionColor("zed")
|
||||||
|
visible: SettingsData.runDmsMatugenTemplates
|
||||||
|
checked: SettingsData.matugenTemplateZed
|
||||||
|
onToggled: checked => SettingsData.set("matugenTemplateZed", checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ Variants {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: renderSettleTimer
|
id: renderSettleTimer
|
||||||
interval: 100
|
interval: 1000
|
||||||
onTriggered: root._renderSettling = false
|
onTriggered: root._renderSettling = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ Variants {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (typeof wallpaperWindow.updatesEnabled !== "undefined")
|
if (typeof wallpaperWindow.updatesEnabled !== "undefined")
|
||||||
wallpaperWindow.updatesEnabled = Qt.binding(() => root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
|
wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
|
||||||
|
|
||||||
if (!source) {
|
if (!source) {
|
||||||
root._renderSettling = false;
|
root._renderSettling = false;
|
||||||
@@ -265,6 +265,9 @@ Variants {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root._renderSettling = true;
|
||||||
|
renderSettleTimer.restart();
|
||||||
|
|
||||||
nextWallpaper.source = newPath;
|
nextWallpaper.source = newPath;
|
||||||
|
|
||||||
if (nextWallpaper.status === Image.Ready)
|
if (nextWallpaper.status === Image.Ready)
|
||||||
@@ -315,6 +318,8 @@ Variants {
|
|||||||
if (status !== Image.Ready)
|
if (status !== Image.Ready)
|
||||||
return;
|
return;
|
||||||
if (root.actualTransitionType === "none") {
|
if (root.actualTransitionType === "none") {
|
||||||
|
root._renderSettling = true;
|
||||||
|
renderSettleTimer.restart();
|
||||||
currentWallpaper.source = source;
|
currentWallpaper.source = source;
|
||||||
nextWallpaper.source = "";
|
nextWallpaper.source = "";
|
||||||
root.transitionProgress = 0.0;
|
root.transitionProgress = 0.0;
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)
|
readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)
|
||||||
|
|
||||||
// Is the system plugged in (none of the batteries are discharging or empty)
|
// Is the system plugged in (Is not running on battery)
|
||||||
readonly property bool isPluggedIn: batteryAvailable && batteries.every(b => b.state !== UPowerDeviceState.Discharging)
|
readonly property bool isPluggedIn: !UPower.onBattery
|
||||||
readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20
|
readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20
|
||||||
|
|
||||||
onIsPluggedInChanged: {
|
onIsPluggedInChanged: {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
|
|||||||
@@ -93,9 +93,9 @@ Singleton {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor");
|
monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor");
|
||||||
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0);
|
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout > 0 ? root.monitorTimeout : 86400);
|
||||||
monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||||
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout);
|
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0);
|
||||||
monitorOffMonitor.isIdleChanged.connect(function () {
|
monitorOffMonitor.isIdleChanged.connect(function () {
|
||||||
if (monitorOffMonitor.isIdle) {
|
if (monitorOffMonitor.isIdle) {
|
||||||
if (SettingsData.fadeToDpmsEnabled) {
|
if (SettingsData.fadeToDpmsEnabled) {
|
||||||
@@ -112,9 +112,9 @@ Singleton {
|
|||||||
});
|
});
|
||||||
|
|
||||||
lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor");
|
lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor");
|
||||||
lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0);
|
lockMonitor.timeout = Qt.binding(() => root.lockTimeout > 0 ? root.lockTimeout : 86400);
|
||||||
lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||||
lockMonitor.timeout = Qt.binding(() => root.lockTimeout);
|
lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0);
|
||||||
lockMonitor.isIdleChanged.connect(function () {
|
lockMonitor.isIdleChanged.connect(function () {
|
||||||
if (lockMonitor.isIdle) {
|
if (lockMonitor.isIdle) {
|
||||||
if (SettingsData.fadeToLockEnabled) {
|
if (SettingsData.fadeToLockEnabled) {
|
||||||
@@ -130,9 +130,9 @@ Singleton {
|
|||||||
});
|
});
|
||||||
|
|
||||||
suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor");
|
suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor");
|
||||||
suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0);
|
suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout > 0 ? root.suspendTimeout : 86400);
|
||||||
suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||||
suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout);
|
suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0);
|
||||||
suspendMonitor.isIdleChanged.connect(function () {
|
suspendMonitor.isIdleChanged.connect(function () {
|
||||||
if (suspendMonitor.isIdle) {
|
if (suspendMonitor.isIdle) {
|
||||||
root.requestSuspend();
|
root.requestSuspend();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ Singleton {
|
|||||||
readonly property string historyFile: Paths.strip(Paths.cache) + "/notification_history.json"
|
readonly property string historyFile: Paths.strip(Paths.cache) + "/notification_history.json"
|
||||||
readonly property string imageCacheDir: Paths.strip(Paths.cache) + "/notification_images"
|
readonly property string imageCacheDir: Paths.strip(Paths.cache) + "/notification_images"
|
||||||
property bool historyLoaded: false
|
property bool historyLoaded: false
|
||||||
|
property int historyEntryCounter: 0
|
||||||
|
|
||||||
property list<NotifWrapper> notificationQueue: []
|
property list<NotifWrapper> notificationQueue: []
|
||||||
property list<NotifWrapper> visibleNotifications: []
|
property list<NotifWrapper> visibleNotifications: []
|
||||||
@@ -73,6 +74,12 @@ Singleton {
|
|||||||
onTriggered: root.performSaveHistory()
|
onTriggered: root.performSaveHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _makeHistoryEntryId(sourceId, timestamp) {
|
||||||
|
historyEntryCounter += 1;
|
||||||
|
const safeSource = sourceId && sourceId !== "" ? sourceId : "notification";
|
||||||
|
return safeSource + "_" + (timestamp || Date.now()) + "_" + historyEntryCounter;
|
||||||
|
}
|
||||||
|
|
||||||
function getImageCachePath(wrapper) {
|
function getImageCachePath(wrapper) {
|
||||||
const ts = wrapper.time ? wrapper.time.getTime() : Date.now();
|
const ts = wrapper.time ? wrapper.time.getTime() : Date.now();
|
||||||
const id = wrapper.notification?.id?.toString() || "0";
|
const id = wrapper.notification?.id?.toString() || "0";
|
||||||
@@ -80,12 +87,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateHistoryImage(wrapperId, imagePath) {
|
function updateHistoryImage(wrapperId, imagePath) {
|
||||||
const idx = historyList.findIndex(n => n.id === wrapperId);
|
const idx = historyList.findIndex(n => n.sourceNotificationId === wrapperId || n.id === wrapperId);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
return;
|
return;
|
||||||
const item = historyList[idx];
|
const item = historyList[idx];
|
||||||
const updated = {
|
const updated = {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
|
sourceNotificationId: item.sourceNotificationId || item.id,
|
||||||
summary: item.summary,
|
summary: item.summary,
|
||||||
body: item.body,
|
body: item.body,
|
||||||
htmlBody: item.htmlBody,
|
htmlBody: item.htmlBody,
|
||||||
@@ -113,8 +121,11 @@ Singleton {
|
|||||||
} else if (imageUrl && !imageUrl.startsWith("image://qsimage/")) {
|
} else if (imageUrl && !imageUrl.startsWith("image://qsimage/")) {
|
||||||
persistableImage = imageUrl;
|
persistableImage = imageUrl;
|
||||||
}
|
}
|
||||||
|
const sourceNotificationId = wrapper.notification?.id?.toString() || "";
|
||||||
|
const timestamp = wrapper.time.getTime();
|
||||||
const data = {
|
const data = {
|
||||||
id: wrapper.notification?.id?.toString() || Date.now().toString(),
|
id: _makeHistoryEntryId(sourceNotificationId, timestamp),
|
||||||
|
sourceNotificationId: sourceNotificationId,
|
||||||
summary: wrapper.summary || "",
|
summary: wrapper.summary || "",
|
||||||
body: wrapper.body || "",
|
body: wrapper.body || "",
|
||||||
htmlBody: wrapper.htmlBody || wrapper.body || "",
|
htmlBody: wrapper.htmlBody || wrapper.body || "",
|
||||||
@@ -122,7 +133,7 @@ Singleton {
|
|||||||
appIcon: wrapper.appIcon || "",
|
appIcon: wrapper.appIcon || "",
|
||||||
image: persistableImage,
|
image: persistableImage,
|
||||||
urgency: urg,
|
urgency: urg,
|
||||||
timestamp: wrapper.time.getTime(),
|
timestamp: timestamp,
|
||||||
desktopEntry: wrapper.desktopEntry || ""
|
desktopEntry: wrapper.desktopEntry || ""
|
||||||
};
|
};
|
||||||
let newList = [data, ...historyList];
|
let newList = [data, ...historyList];
|
||||||
@@ -152,6 +163,8 @@ Singleton {
|
|||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const maxAgeMs = maxAgeDays > 0 ? maxAgeDays * 24 * 60 * 60 * 1000 : 0;
|
const maxAgeMs = maxAgeDays > 0 ? maxAgeDays * 24 * 60 * 60 * 1000 : 0;
|
||||||
const loaded = [];
|
const loaded = [];
|
||||||
|
const seenIds = {};
|
||||||
|
let needsRewrite = false;
|
||||||
|
|
||||||
for (const item of historyAdapter.notifications || []) {
|
for (const item of historyAdapter.notifications || []) {
|
||||||
if (maxAgeMs > 0 && (now - item.timestamp) > maxAgeMs)
|
if (maxAgeMs > 0 && (now - item.timestamp) > maxAgeMs)
|
||||||
@@ -162,8 +175,18 @@ Singleton {
|
|||||||
if (htmlBody) {
|
if (htmlBody) {
|
||||||
htmlBody = htmlBody.replace(/<img\b[^>]*>/gi, "");
|
htmlBody = htmlBody.replace(/<img\b[^>]*>/gi, "");
|
||||||
}
|
}
|
||||||
|
const sourceNotificationId = (item.sourceNotificationId || item.id || "").toString();
|
||||||
|
let historyId = (item.id || "").toString();
|
||||||
|
if (!historyId || seenIds[historyId]) {
|
||||||
|
historyId = _makeHistoryEntryId(sourceNotificationId, item.timestamp || now);
|
||||||
|
needsRewrite = true;
|
||||||
|
}
|
||||||
|
if (!item.sourceNotificationId)
|
||||||
|
needsRewrite = true;
|
||||||
|
seenIds[historyId] = true;
|
||||||
loaded.push({
|
loaded.push({
|
||||||
id: item.id || "",
|
id: historyId,
|
||||||
|
sourceNotificationId: sourceNotificationId,
|
||||||
summary: item.summary || "",
|
summary: item.summary || "",
|
||||||
body: body,
|
body: body,
|
||||||
htmlBody: htmlBody,
|
htmlBody: htmlBody,
|
||||||
@@ -177,7 +200,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
historyList = loaded;
|
historyList = loaded;
|
||||||
historyLoaded = true;
|
historyLoaded = true;
|
||||||
if (maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length)
|
if ((maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length) || needsRewrite)
|
||||||
saveHistory();
|
saveHistory();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("NotificationService: load history failed:", e);
|
console.warn("NotificationService: load history failed:", e);
|
||||||
|
|||||||
@@ -44,24 +44,26 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var archBasedPMSettings: {
|
readonly property var archBasedPMSettings: function(requiresSudo) {
|
||||||
"listUpdatesSettings": {
|
return {
|
||||||
"params": ["-Qu"],
|
"listUpdatesSettings": {
|
||||||
"correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates
|
"params": ["-Qu"],
|
||||||
},
|
"correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates
|
||||||
"upgradeSettings": {
|
},
|
||||||
"params": ["-Syu"],
|
"upgradeSettings": {
|
||||||
"requiresSudo": false
|
"params": ["-Syu"],
|
||||||
},
|
"requiresSudo": requiresSudo
|
||||||
"parserSettings": {
|
},
|
||||||
"lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/,
|
"parserSettings": {
|
||||||
"entryProducer": function (match) {
|
"lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/,
|
||||||
return {
|
"entryProducer": function (match) {
|
||||||
"name": match[1],
|
return {
|
||||||
"currentVersion": match[2],
|
"name": match[1],
|
||||||
"newVersion": match[3],
|
"currentVersion": match[2],
|
||||||
"description": `${match[1]} ${match[2]} → ${match[3]}`
|
"newVersion": match[3],
|
||||||
};
|
"description": `${match[1]} ${match[2]} → ${match[3]}`
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,8 +94,9 @@ Singleton {
|
|||||||
"checkupdates": archBasedUCSettings
|
"checkupdates": archBasedUCSettings
|
||||||
}
|
}
|
||||||
readonly property var packageManagerParams: {
|
readonly property var packageManagerParams: {
|
||||||
"yay": archBasedPMSettings,
|
"yay": archBasedPMSettings(false),
|
||||||
"paru": archBasedPMSettings,
|
"paru": archBasedPMSettings(false),
|
||||||
|
"pacman": archBasedPMSettings(true),
|
||||||
"dnf": fedoraBasedPMSettings
|
"dnf": fedoraBasedPMSettings
|
||||||
}
|
}
|
||||||
readonly property list<string> supportedDistributions: ["arch", "artix", "cachyos", "manjaro", "endeavouros", "fedora"]
|
readonly property list<string> supportedDistributions: ["arch", "artix", "cachyos", "manjaro", "endeavouros", "fedora"]
|
||||||
@@ -182,7 +185,7 @@ Singleton {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: pkgManagerDetection
|
id: pkgManagerDetection
|
||||||
command: ["sh", "-c", "which paru || which yay || which dnf"]
|
command: ["sh", "-c", "which paru || which yay || which pacman || which dnf"]
|
||||||
|
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
@@ -259,7 +262,7 @@ Singleton {
|
|||||||
const terminal = Quickshell.env("TERMINAL") || "xterm";
|
const terminal = Quickshell.env("TERMINAL") || "xterm";
|
||||||
|
|
||||||
if (SettingsData.updaterUseCustomCommand && SettingsData.updaterCustomCommand.length > 0) {
|
if (SettingsData.updaterUseCustomCommand && SettingsData.updaterCustomCommand.length > 0) {
|
||||||
const updateCommand = `${SettingsData.updaterCustomCommand} && echo "Updates complete! Press Enter to close..." && read`;
|
const updateCommand = `${SettingsData.updaterCustomCommand} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`;
|
||||||
const termClass = SettingsData.updaterTerminalAdditionalParams;
|
const termClass = SettingsData.updaterTerminalAdditionalParams;
|
||||||
|
|
||||||
var finalCommand = [terminal];
|
var finalCommand = [terminal];
|
||||||
@@ -274,7 +277,7 @@ Singleton {
|
|||||||
} else {
|
} else {
|
||||||
const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ");
|
const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ");
|
||||||
const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : "";
|
const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : "";
|
||||||
const updateCommand = `${sudo} ${pkgManager} ${params} && echo "Updates complete! Press Enter to close..." && read`;
|
const updateCommand = `${sudo} ${pkgManager} ${params} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`;
|
||||||
|
|
||||||
updater.command = [terminal, "-e", "sh", "-c", updateCommand];
|
updater.command = [terminal, "-e", "sh", "-c", updateCommand];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process) {
|
if (process) {
|
||||||
process.command = ["sh", "-c", `find "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
||||||
process.targetScreenName = screenName;
|
process.targetScreenName = screenName;
|
||||||
process.currentWallpaper = currentWallpaper;
|
process.currentWallpaper = currentWallpaper;
|
||||||
process.goToPrevious = false;
|
process.goToPrevious = false;
|
||||||
@@ -272,7 +272,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use global process for fallback
|
// Use global process for fallback
|
||||||
cyclingProcess.command = ["sh", "-c", `find "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
cyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
||||||
cyclingProcess.targetScreenName = screenName || "";
|
cyclingProcess.targetScreenName = screenName || "";
|
||||||
cyclingProcess.currentWallpaper = currentWallpaper;
|
cyclingProcess.currentWallpaper = currentWallpaper;
|
||||||
cyclingProcess.running = true;
|
cyclingProcess.running = true;
|
||||||
@@ -296,7 +296,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process) {
|
if (process) {
|
||||||
process.command = ["sh", "-c", `find "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
||||||
process.targetScreenName = screenName;
|
process.targetScreenName = screenName;
|
||||||
process.currentWallpaper = currentWallpaper;
|
process.currentWallpaper = currentWallpaper;
|
||||||
process.goToPrevious = true;
|
process.goToPrevious = true;
|
||||||
@@ -304,7 +304,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use global process for fallback
|
// Use global process for fallback
|
||||||
prevCyclingProcess.command = ["sh", "-c", `find "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
prevCyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
||||||
prevCyclingProcess.targetScreenName = screenName || "";
|
prevCyclingProcess.targetScreenName = screenName || "";
|
||||||
prevCyclingProcess.currentWallpaper = currentWallpaper;
|
prevCyclingProcess.currentWallpaper = currentWallpaper;
|
||||||
prevCyclingProcess.running = true;
|
prevCyclingProcess.running = true;
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
v1.4.3
|
v1.4.4
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Item {
|
|||||||
readonly property string iconPath: {
|
readonly property string iconPath: {
|
||||||
if (hasSpecialPrefix || !iconValue)
|
if (hasSpecialPrefix || !iconValue)
|
||||||
return "";
|
return "";
|
||||||
return Quickshell.iconPath(iconValue, true) || DesktopService.resolveIconPath(iconValue);
|
return Paths.resolveIconPath(iconValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: iconValue !== undefined && iconValue !== ""
|
visible: iconValue !== undefined && iconValue !== ""
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (typeof updatesEnabled !== "undefined")
|
if (typeof updatesEnabled !== "undefined" && !root.overlayContent)
|
||||||
updatesEnabled = false;
|
updatesEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,8 +407,8 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
x: contentContainer.x - root.shadowBuffer
|
x: contentContainer.x - root.shadowBuffer
|
||||||
y: contentContainer.y - root.shadowBuffer
|
y: contentContainer.y - root.shadowBuffer
|
||||||
width: root.alignedWidth + root.shadowBuffer * 2
|
width: shouldBeVisible ? root.alignedWidth + root.shadowBuffer * 2 : 0
|
||||||
height: root.alignedHeight + root.shadowBuffer * 2
|
height: shouldBeVisible ? root.alignedHeight + root.shadowBuffer * 2 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[templates.dmszed]
|
||||||
|
input_path = 'SHELL_DIR/matugen/templates/dank-zed.json'
|
||||||
|
output_path = 'CONFIG_DIR/zed/themes/dank-zed-theme.json'
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
[colors]
|
[colors-dark]
|
||||||
foreground={{colors.on_surface.default.hex_stripped}}
|
foreground={{colors.on_surface.default.hex_stripped}}
|
||||||
background={{colors.background.default.hex_stripped}}
|
background={{colors.background.default.hex_stripped}}
|
||||||
selection-foreground={{colors.on_surface.default.hex_stripped}}
|
selection-foreground={{colors.on_surface.default.hex_stripped}}
|
||||||
|
|||||||
@@ -92,3 +92,21 @@ toolbar .toolbarbutton-1 {
|
|||||||
#zen-appcontent-navbar-container {
|
#zen-appcontent-navbar-container {
|
||||||
background-color: {{colors.background.default.hex}} !important;
|
background-color: {{colors.background.default.hex}} !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#PanelUI-menu-button .toolbarbutton-icon,
|
||||||
|
#downloads-button .toolbarbutton-icon,
|
||||||
|
#unified-extensions-button .toolbarbutton-icon {
|
||||||
|
fill: {{colors.primary.default.hex}} !important;
|
||||||
|
color: {{colors.primary.default.hex}} !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#PanelUI-menu-button .toolbarbutton-badge-stack,
|
||||||
|
#downloads-button .toolbarbutton-badge-stack,
|
||||||
|
#unified-extensions-button .toolbarbutton-badge-stack {
|
||||||
|
fill: {{colors.primary.default.hex}} !important;
|
||||||
|
color: {{colors.primary.default.hex}} !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbar .toolbarbutton-1 > .toolbarbutton-icon {
|
||||||
|
fill: {{colors.primary.default.hex}} !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4452,8 +4452,8 @@
|
|||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"term": "File search requires dsearch\nInstall from github.com/morelazers/dsearch",
|
"term": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch",
|
||||||
"context": "File search requires dsearch\nInstall from github.com/morelazers/dsearch",
|
"context": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch",
|
||||||
"reference": "Modals/DankLauncherV2/ResultsList.qml:471",
|
"reference": "Modals/DankLauncherV2/ResultsList.qml:471",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Información del archivo"
|
"File Information": "Información del archivo"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Archivos"
|
"Files": "Archivos"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "اطلاعات فایل"
|
"File Information": "اطلاعات فایل"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "جستجوی فایل به dsearch نیاز دارد\nاز github.com/morelazers/dsearch نصب کنید"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "جستجوی فایل به dsearch نیاز دارد\nاز github.com/AvengeMedia/danksearch نصب کنید"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "جستجوی نیاز به dsearch دارد\\nاز github.com/morelazers/dsearch نصب کنید"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "جستجوی نیاز به dsearch دارد\\nاز github.com/AvengeMedia/danksearch نصب کنید"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "فایلها"
|
"Files": "فایلها"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Informations sur le fichier"
|
"File Information": "Informations sur le fichier"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "La recherche de fichiers nécessite dsearch\nInstallez-le depuis github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "La recherche de fichiers nécessite dsearch\nInstallez-le depuis github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "La recherche de fichiers nécessite dsearch\\nInstallez-le depuis github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "La recherche de fichiers nécessite dsearch\\nInstallez-le depuis github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Fichiers"
|
"Files": "Fichiers"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "פרטי קובץ"
|
"File Information": "פרטי קובץ"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "חיפוש קבצים הכלי dsearch נדרש כדי לבצע חיפוש של קבצים.\nהתקן/י אותו מ: github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "חיפוש קבצים הכלי dsearch נדרש כדי לבצע חיפוש של קבצים.\nהתקן/י אותו מ: github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "חיפוש קבצים הכלי dsearch נדרש כדי לבצע חיפוש של קבצים.\\nהתקן/י אותו מ: github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "חיפוש קבצים הכלי dsearch נדרש כדי לבצע חיפוש של קבצים.\\nהתקן/י אותו מ: github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "קבצים"
|
"Files": "קבצים"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Fájlinformáció"
|
"File Information": "Fájlinformáció"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "A fájlkereséshez dsearch szükséges\nTelepítsd innen: github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "A fájlkereséshez dsearch szükséges\nTelepítsd innen: github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "A fájlkereséshez dsearch szükséges\\nTelepítsd innen: github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "A fájlkereséshez dsearch szükséges\\nTelepítsd innen: github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Fájlok"
|
"Files": "Fájlok"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Informazioni File"
|
"File Information": "Informazioni File"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "La ricerca file richiede dsearch\\nInstalla da github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "La ricerca file richiede dsearch\\nInstalla da github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "La ricerca file richiede dsearch\\nInstalla da github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "La ricerca file richiede dsearch\\nInstalla da github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "File"
|
"Files": "File"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "ファイル情報"
|
"File Information": "ファイル情報"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": ""
|
"Files": ""
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Bestandsinformatie"
|
"File Information": "Bestandsinformatie"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "Bestandszoeken vereist dsearch\nInstalleer via github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Bestandszoeken vereist dsearch\nInstalleer via github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "Bestandszoeken vereist dsearch\\nInstalleer via github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "Bestandszoeken vereist dsearch\\nInstalleer via github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Bestanden"
|
"Files": "Bestanden"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Informacje"
|
"File Information": "Informacje"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Akta"
|
"Files": "Akta"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Informação do Arquivo"
|
"File Information": "Informação do Arquivo"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": "Pesquisa de arquivo requer dsearch\nInstalar de github.com/morelazers/dsearch"
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": "Pesquisa de arquivo requer dsearch\nInstalar de github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "A pesquisa de arquivo requer dsearch\\nInstale em github.com/morelazers/dsearch"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "A pesquisa de arquivo requer dsearch\\nInstale em github.com/AvengeMedia/danksearch"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Arquivos"
|
"Files": "Arquivos"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "Dosya Bilgisi"
|
"File Information": "Dosya Bilgisi"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "Dosyalar"
|
"Files": "Dosyalar"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "文件信息"
|
"File Information": "文件信息"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "文件搜索需要dsearch\\n请从github.com/morelazers/dsearch进行安装"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "文件搜索需要dsearch\\n请从github.com/AvengeMedia/danksearch进行安装"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "文件"
|
"Files": "文件"
|
||||||
|
|||||||
@@ -2023,11 +2023,11 @@
|
|||||||
"File Information": {
|
"File Information": {
|
||||||
"File Information": "檔案資訊"
|
"File Information": "檔案資訊"
|
||||||
},
|
},
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\nInstall from github.com/morelazers/dsearch": ""
|
"File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch": ""
|
||||||
},
|
},
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": {
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": {
|
||||||
"File search requires dsearch\\nInstall from github.com/morelazers/dsearch": "檔案搜尋需要 dsearch\\n請從 github.com/morelazers/dsearch 安裝"
|
"File search requires dsearch\\nInstall from github.com/AvengeMedia/danksearch": "檔案搜尋需要 dsearch\\n請從 github.com/AvengeMedia/danksearch 安裝"
|
||||||
},
|
},
|
||||||
"Files": {
|
"Files": {
|
||||||
"Files": "檔案"
|
"Files": "檔案"
|
||||||
|
|||||||
@@ -2484,6 +2484,23 @@
|
|||||||
"theme"
|
"theme"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "matugenTemplateZed",
|
||||||
|
"label": "Zed",
|
||||||
|
"tabIndex": 10,
|
||||||
|
"category": "Theme & Colors",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"colors",
|
||||||
|
"look",
|
||||||
|
"matugen",
|
||||||
|
"scheme",
|
||||||
|
"style",
|
||||||
|
"template",
|
||||||
|
"theme",
|
||||||
|
"zed"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "matugenTemplateFirefox",
|
"section": "matugenTemplateFirefox",
|
||||||
"label": "Firefox",
|
"label": "Firefox",
|
||||||
|
|||||||
@@ -5194,7 +5194,7 @@
|
|||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"term": "File search requires dsearch\nInstall from github.com/morelazers/dsearch",
|
"term": "File search requires dsearch\nInstall from github.com/AvengeMedia/danksearch",
|
||||||
"translation": "",
|
"translation": "",
|
||||||
"context": "",
|
"context": "",
|
||||||
"reference": "",
|
"reference": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user