1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-02 02:22:06 -04:00

Compare commits

...

22 Commits

Author SHA1 Message Date
bbedward
db4de55338 popout: decouple shadow from content layer 2026-02-18 10:46:01 -05:00
bbedward
37ecbbbbde popout: disable layer after animation 2026-02-18 10:34:21 -05:00
purian23
d6a6d2a438 notifications: Maintain shadow during expansion 2026-02-18 10:34:21 -05:00
purian23
bf1c6eec74 notifications: Update initial popup height surfaces 2026-02-18 10:34:21 -05:00
bbedward
0ddae80584 running apps: fix scroll events being propagated fixes #1724 2026-02-18 10:34:21 -05:00
bbedward
5c96c03bfa matugen: make v4 detection more resilient 2026-02-18 09:57:35 -05:00
bbedward
dfe36e47d8 process list: fix scaling with fonts fixes #1721 2026-02-18 09:57:35 -05:00
purian23
63e1b75e57 dankinstall: Fix Debian ARM64 detection 2026-02-18 09:57:35 -05:00
bbedward
29efdd8598 matugen: detect emacs directory fixes #1720 2026-02-18 09:57:35 -05:00
bbedward
34d03cf11b osd: optimize bindings 2026-02-18 09:57:35 -05:00
bbedward
c339389d44 screenshot: adjust cursor CLI option to be more explicit 2026-02-17 22:28:46 -05:00
bbedward
af5f6eb656 settings: workaround crash 2026-02-17 22:20:19 -05:00
purian23
a6d28e2553 notifications: Tweak animation scale & settings 2026-02-17 22:07:36 -05:00
bbedward
6213267908 settings: guard internal writes from watcher 2026-02-17 22:03:57 -05:00
bbedward
d084114149 cc: fix plugin reloading in bar position changes 2026-02-17 17:25:19 -05:00
bbedward
f6d99eca0d popout: anchor height changing popout surfaces to top and bottom 2026-02-17 17:25:19 -05:00
bbedward
722eb3289e workspaces: fix named workspace icons 2026-02-17 17:25:19 -05:00
bbedward
b7f2bdcb2d dankinstall: no_anim on dms layers 2026-02-17 17:25:19 -05:00
bbedward
11c20db6e6 1.4.1 2026-02-17 14:08:15 -05:00
bbedward
8a4e3f8bb1 system updater: fix hide no update option 2026-02-17 14:08:04 -05:00
bbedward
bc8fe97c13 launcher: fix kb navigation not always showing last delegate in view 2026-02-17 14:08:04 -05:00
bbedward
47262155aa doctor: add qt6-imageformats check 2026-02-17 14:08:04 -05:00
38 changed files with 696 additions and 552 deletions

View File

@@ -45,9 +45,9 @@ body:
- type: textarea - type: textarea
id: dms_doctor id: dms_doctor
attributes: attributes:
label: dms doctor -v label: dms doctor -vC
description: Output of `dms doctor -v` command description: Output of `dms doctor -vC` command
placeholder: Paste the output of `dms doctor -v` here placeholder: Paste the output of `dms doctor -vC` here
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -30,9 +30,9 @@ body:
- type: textarea - type: textarea
id: dms_doctor id: dms_doctor
attributes: attributes:
label: dms doctor -v label: dms doctor -vC
description: Output of `dms doctor -v` command description: Output of `dms doctor -vC` command
placeholder: Paste the output of `dms doctor -v` here placeholder: Paste the output of `dms doctor -vC` here
validations: validations:
required: false required: false
- type: textarea - type: textarea

View File

@@ -649,40 +649,73 @@ func checkI2CAvailability() checkResult {
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"} return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
} }
func checkKImageFormats() checkResult { func checkImageFormatPlugins() []checkResult {
url := doctorDocsURL + "#optional-features" url := doctorDocsURL + "#optional-features"
desc := "Extra image format support (AVIF, HEIF, JXL)"
pluginDir := findQtPluginDir() pluginDir := findQtPluginDir()
if pluginDir == "" { if pluginDir == "" {
return checkResult{catOptionalFeatures, "kimageformats", statusInfo, "Cannot detect (qtpaths not found)", desc, url} return []checkResult{
{catOptionalFeatures, "qt6-imageformats", statusInfo, "Cannot detect (plugin dir not found)", "WebP, TIFF, JP2 support", url},
{catOptionalFeatures, "kimageformats", statusInfo, "Cannot detect (plugin dir not found)", "AVIF, HEIF, JXL support", url},
}
} }
imageFormatsDir := filepath.Join(pluginDir, "imageformats") imageFormatsDir := filepath.Join(pluginDir, "imageformats")
keyPlugins := []struct{ file, format string }{
type pluginCheck struct {
name string
desc string
plugins []struct{ file, format string }
}
checks := []pluginCheck{
{
name: "qt6-imageformats",
desc: "WebP, TIFF, GIF, JP2 support",
plugins: []struct{ file, format string }{
{"libqwebp.so", "WebP"},
{"libqtiff.so", "TIFF"},
{"libqgif.so", "GIF"},
{"libqjp2.so", "JP2"},
{"libqicns.so", "ICNS"},
},
},
{
name: "kimageformats",
desc: "AVIF, HEIF, JXL support",
plugins: []struct{ file, format string }{
{"kimg_avif.so", "AVIF"}, {"kimg_avif.so", "AVIF"},
{"kimg_heif.so", "HEIF"}, {"kimg_heif.so", "HEIF"},
{"kimg_jxl.so", "JXL"}, {"kimg_jxl.so", "JXL"},
{"kimg_exr.so", "EXR"}, {"kimg_exr.so", "EXR"},
},
},
} }
var results []checkResult
for _, c := range checks {
var found []string var found []string
for _, p := range keyPlugins { for _, p := range c.plugins {
if _, err := os.Stat(filepath.Join(imageFormatsDir, p.file)); err == nil { if _, err := os.Stat(filepath.Join(imageFormatsDir, p.file)); err == nil {
found = append(found, p.format) found = append(found, p.format)
} }
} }
if len(found) == 0 { var result checkResult
return checkResult{catOptionalFeatures, "kimageformats", statusWarn, "Not installed", desc, url} switch {
} case len(found) == 0:
result = checkResult{catOptionalFeatures, c.name, statusWarn, "Not installed", c.desc, url}
default:
details := "" details := ""
if doctorVerbose { if doctorVerbose {
details = fmt.Sprintf("Formats: %s (%s)", strings.Join(found, ", "), imageFormatsDir) details = fmt.Sprintf("Formats: %s (%s)", strings.Join(found, ", "), imageFormatsDir)
} }
result = checkResult{catOptionalFeatures, c.name, statusOK, fmt.Sprintf("Installed (%d formats)", len(found)), details, url}
}
results = append(results, result)
}
return checkResult{catOptionalFeatures, "kimageformats", statusOK, fmt.Sprintf("Installed (%d formats)", len(found)), details, url} return results
} }
func findQtPluginDir() string { func findQtPluginDir() string {
@@ -773,7 +806,7 @@ func checkOptionalDependencies() []checkResult {
results = append(results, checkResult{catOptionalFeatures, "cups-pk-helper", cupsPkStatus, cupsPkMsg, "Printer management", optionalFeaturesURL}) results = append(results, checkResult{catOptionalFeatures, "cups-pk-helper", cupsPkStatus, cupsPkMsg, "Printer management", optionalFeaturesURL})
results = append(results, checkI2CAvailability()) results = append(results, checkI2CAvailability())
results = append(results, checkKImageFormats()) results = append(results, checkImageFormatPlugins()...)
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"} terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 { if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {

View File

@@ -14,7 +14,7 @@ import (
var ( var (
ssOutputName string ssOutputName string
ssIncludeCursor bool ssCursor string
ssFormat string ssFormat string
ssQuality int ssQuality int
ssOutputDir string ssOutputDir string
@@ -52,7 +52,7 @@ Examples:
dms screenshot last # Last region (pre-selected) dms screenshot last # Last region (pre-selected)
dms screenshot --no-clipboard # Save file only dms screenshot --no-clipboard # Save file only
dms screenshot --no-file # Clipboard only dms screenshot --no-file # Clipboard only
dms screenshot --cursor # Include cursor dms screenshot --cursor=on # Include cursor
dms screenshot -f jpg -q 85 # JPEG with quality 85`, dms screenshot -f jpg -q 85 # JPEG with quality 85`,
} }
@@ -111,7 +111,7 @@ var notifyActionCmd = &cobra.Command{
func init() { func init() {
screenshotCmd.PersistentFlags().StringVarP(&ssOutputName, "output", "o", "", "Output name for 'output' mode") screenshotCmd.PersistentFlags().StringVarP(&ssOutputName, "output", "o", "", "Output name for 'output' mode")
screenshotCmd.PersistentFlags().BoolVar(&ssIncludeCursor, "cursor", false, "Include cursor in screenshot") screenshotCmd.PersistentFlags().StringVar(&ssCursor, "cursor", "off", "Include cursor in screenshot (on/off)")
screenshotCmd.PersistentFlags().StringVarP(&ssFormat, "format", "f", "png", "Output format (png, jpg, ppm)") screenshotCmd.PersistentFlags().StringVarP(&ssFormat, "format", "f", "png", "Output format (png, jpg, ppm)")
screenshotCmd.PersistentFlags().IntVarP(&ssQuality, "quality", "q", 90, "JPEG quality (1-100)") screenshotCmd.PersistentFlags().IntVarP(&ssQuality, "quality", "q", 90, "JPEG quality (1-100)")
screenshotCmd.PersistentFlags().StringVarP(&ssOutputDir, "dir", "d", "", "Output directory") screenshotCmd.PersistentFlags().StringVarP(&ssOutputDir, "dir", "d", "", "Output directory")
@@ -136,7 +136,9 @@ func getScreenshotConfig(mode screenshot.Mode) screenshot.Config {
config := screenshot.DefaultConfig() config := screenshot.DefaultConfig()
config.Mode = mode config.Mode = mode
config.OutputName = ssOutputName config.OutputName = ssOutputName
config.IncludeCursor = ssIncludeCursor if strings.EqualFold(ssCursor, "on") {
config.Cursor = screenshot.CursorOn
}
config.Clipboard = !ssNoClipboard config.Clipboard = !ssNoClipboard
config.SaveFile = !ssNoFile config.SaveFile = !ssNoFile
config.Notify = !ssNoNotify config.Notify = !ssNoNotify

View File

@@ -111,6 +111,7 @@ windowrule = float on, match:class ^(zoom)$
# windowrule = float on, match:class ^(org.quickshell)$ # windowrule = float on, match:class ^(org.quickshell)$
layerrule = no_anim on, match:namespace ^(quickshell)$ layerrule = no_anim on, match:namespace ^(quickshell)$
layerrule = no_anim on, match:namespace ^dms:.*
source = ./dms/colors.conf source = ./dms/colors.conf
source = ./dms/outputs.conf source = ./dms/outputs.conf

View File

@@ -430,7 +430,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, runtime.GOARCH, baseURL)
progressChan <- InstallProgressMsg{ progressChan <- InstallProgressMsg{
Phase: PhaseSystemPackages, Phase: PhaseSystemPackages,

View File

@@ -33,6 +33,7 @@ const (
TemplateKindTerminal TemplateKindTerminal
TemplateKindGTK TemplateKindGTK
TemplateKindVSCode TemplateKindVSCode
TemplateKindEmacs
) )
type TemplateDef struct { type TemplateDef struct {
@@ -65,7 +66,7 @@ var templateRegistry = []TemplateDef{
{ID: "dgop", Commands: []string{"dgop"}, ConfigFile: "dgop.toml"}, {ID: "dgop", Commands: []string{"dgop"}, ConfigFile: "dgop.toml"},
{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"}, {ID: "emacs", Commands: []string{"emacs"}, ConfigFile: "emacs.toml", Kind: TemplateKindEmacs},
} }
func (c *ColorMode) GTKTheme() string { func (c *ColorMode) GTKTheme() string {
@@ -78,7 +79,8 @@ func (c *ColorMode) GTKTheme() string {
} }
var ( var (
matugenVersionOnce sync.Once matugenVersionMu sync.Mutex
matugenVersionOK bool
matugenSupportsCOE bool matugenSupportsCOE bool
matugenIsV4 bool matugenIsV4 bool
) )
@@ -334,6 +336,10 @@ output_path = '%s'
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions"), opts.ShellDir) appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions"), opts.ShellDir)
appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions"), opts.ShellDir) appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions"), opts.ShellDir)
appendVSCodeConfig(cfgFile, "vscode-insiders", filepath.Join(homeDir, ".vscode-insiders/extensions"), opts.ShellDir) appendVSCodeConfig(cfgFile, "vscode-insiders", filepath.Join(homeDir, ".vscode-insiders/extensions"), opts.ShellDir)
case TemplateKindEmacs:
if utils.EmacsConfigDir() != "" {
appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile)
}
default: default:
appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile)
} }
@@ -491,6 +497,9 @@ func substituteVars(content, shellDir string) string {
result = strings.ReplaceAll(result, "'CONFIG_DIR/", "'"+utils.XDGConfigHome()+"/") result = strings.ReplaceAll(result, "'CONFIG_DIR/", "'"+utils.XDGConfigHome()+"/")
result = strings.ReplaceAll(result, "'DATA_DIR/", "'"+utils.XDGDataHome()+"/") result = strings.ReplaceAll(result, "'DATA_DIR/", "'"+utils.XDGDataHome()+"/")
result = strings.ReplaceAll(result, "'CACHE_DIR/", "'"+utils.XDGCacheHome()+"/") result = strings.ReplaceAll(result, "'CACHE_DIR/", "'"+utils.XDGCacheHome()+"/")
if emacsDir := utils.EmacsConfigDir(); emacsDir != "" {
result = strings.ReplaceAll(result, "'EMACS_DIR/", "'"+emacsDir+"/")
}
return result return result
} }
@@ -511,12 +520,40 @@ func extractTOMLSection(content, startMarker, endMarker string) string {
return content[startIdx : startIdx+endIdx] return content[startIdx : startIdx+endIdx]
} }
func checkMatugenVersion() { type matugenFlags struct {
matugenVersionOnce.Do(func() { supportsCOE bool
isV4 bool
}
func detectMatugenVersion() (matugenFlags, error) {
matugenVersionMu.Lock()
defer matugenVersionMu.Unlock()
if matugenVersionOK {
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
}
return detectMatugenVersionLocked()
}
func redetectMatugenVersion(old matugenFlags) (matugenFlags, bool) {
matugenVersionMu.Lock()
defer matugenVersionMu.Unlock()
matugenVersionOK = false
flags, err := detectMatugenVersionLocked()
if err != nil {
return old, false
}
changed := flags.supportsCOE != old.supportsCOE || flags.isV4 != old.isV4
return flags, changed
}
func detectMatugenVersionLocked() (matugenFlags, error) {
cmd := exec.Command("matugen", "--version") cmd := exec.Command("matugen", "--version")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
return return matugenFlags{}, fmt.Errorf("failed to get matugen version: %w", err)
} }
versionStr := strings.TrimSpace(string(output)) versionStr := strings.TrimSpace(string(output))
@@ -524,66 +561,119 @@ func checkMatugenVersion() {
parts := strings.Split(versionStr, ".") parts := strings.Split(versionStr, ".")
if len(parts) < 2 { if len(parts) < 2 {
return return matugenFlags{}, fmt.Errorf("unexpected matugen version format: %q", versionStr)
} }
major, err := strconv.Atoi(parts[0]) major, err := strconv.Atoi(parts[0])
if err != nil { if err != nil {
return return matugenFlags{}, fmt.Errorf("failed to parse matugen major version %q: %w", parts[0], err)
} }
minor, err := strconv.Atoi(parts[1]) minor, err := strconv.Atoi(parts[1])
if err != nil { if err != nil {
return return matugenFlags{}, fmt.Errorf("failed to parse matugen minor version %q: %w", parts[1], err)
} }
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1) matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
matugenIsV4 = major >= 4 matugenIsV4 = major >= 4
matugenVersionOK = true
if matugenSupportsCOE { if matugenSupportsCOE {
log.Infof("Matugen %s supports --continue-on-error", versionStr) log.Infof("Matugen %s supports --continue-on-error", versionStr)
} }
if matugenIsV4 { if matugenIsV4 {
log.Infof("Matugen %s: using v4 flags", versionStr) log.Infof("Matugen %s: using v4 flags", versionStr)
} }
}) return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
} }
func runMatugen(args []string) error { func buildMatugenArgs(baseArgs []string, flags matugenFlags) []string {
checkMatugenVersion() args := make([]string, 0, len(baseArgs)+4)
if flags.supportsCOE {
if matugenSupportsCOE { args = append(args, "--continue-on-error")
args = append([]string{"--continue-on-error"}, args...)
} }
if matugenIsV4 { args = append(args, baseArgs...)
if flags.isV4 {
args = append(args, "--source-color-index", "0") args = append(args, "--source-color-index", "0")
} }
return args
}
func runMatugen(baseArgs []string) error {
flags, err := detectMatugenVersion()
if err != nil {
return err
}
args := buildMatugenArgs(baseArgs, flags)
cmd := exec.Command("matugen", args...) cmd := exec.Command("matugen", args...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() runErr := cmd.Run()
if runErr == nil {
return nil
}
log.Warnf("Matugen failed (v4=%v): %v", flags.isV4, runErr)
newFlags, changed := redetectMatugenVersion(flags)
if !changed {
return runErr
}
log.Warnf("Matugen version changed (v4: %v -> %v), retrying", flags.isV4, newFlags.isV4)
args = buildMatugenArgs(baseArgs, newFlags)
retryCmd := exec.Command("matugen", args...)
retryCmd.Stdout = os.Stdout
retryCmd.Stderr = os.Stderr
return retryCmd.Run()
} }
func runMatugenDryRun(opts *Options) (string, error) { func runMatugenDryRun(opts *Options) (string, error) {
checkMatugenVersion() flags, err := detectMatugenVersion()
var args []string
switch opts.Kind {
case "hex":
args = []string{"color", "hex", opts.Value}
default:
args = []string{opts.Kind, opts.Value}
}
args = append(args, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run")
if matugenIsV4 {
args = append(args, "--source-color-index", "0", "--old-json-output")
}
cmd := exec.Command("matugen", args...)
output, err := cmd.Output()
if err != nil { if err != nil {
return "", err return "", err
} }
output, dryErr := execDryRun(opts, flags)
if dryErr == nil {
return output, nil
}
log.Warnf("Matugen dry-run failed (v4=%v): %v", flags.isV4, dryErr)
newFlags, changed := redetectMatugenVersion(flags)
if !changed {
return "", dryErr
}
log.Warnf("Matugen version changed (v4: %v -> %v), retrying dry-run", flags.isV4, newFlags.isV4)
return execDryRun(opts, newFlags)
}
func execDryRun(opts *Options, flags matugenFlags) (string, error) {
var baseArgs []string
switch opts.Kind {
case "hex":
baseArgs = []string{"color", "hex", opts.Value}
default:
baseArgs = []string{opts.Kind, opts.Value}
}
baseArgs = append(baseArgs, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run")
if flags.isV4 {
baseArgs = append(baseArgs, "--source-color-index", "0", "--old-json-output")
}
cmd := exec.Command("matugen", baseArgs...)
var stderr strings.Builder
cmd.Stderr = &stderr
output, err := cmd.Output()
if err != nil {
if stderr.Len() > 0 {
return "", fmt.Errorf("matugen %v failed (v4=%v): %s", baseArgs, flags.isV4, strings.TrimSpace(stderr.String()))
}
return "", fmt.Errorf("matugen %v failed (v4=%v): %w", baseArgs, flags.isV4, err)
}
return strings.ReplaceAll(string(output), "\n", ""), nil return strings.ReplaceAll(string(output), "\n", ""), nil
} }
@@ -819,6 +909,8 @@ func CheckTemplates(checker utils.AppChecker) []TemplateCheck {
detected = true detected = true
case tmpl.Kind == TemplateKindVSCode: case tmpl.Kind == TemplateKindVSCode:
detected = checkVSCodeExtension(homeDir) detected = checkVSCodeExtension(homeDir)
case tmpl.Kind == TemplateKindEmacs:
detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) && utils.EmacsConfigDir() != ""
default: default:
detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks)
} }

View File

@@ -108,7 +108,7 @@ func NewRegionSelector(s *Screenshoter) *RegionSelector {
screenshoter: s, screenshoter: s,
outputs: make(map[uint32]*WaylandOutput), outputs: make(map[uint32]*WaylandOutput),
preCapture: make(map[*WaylandOutput]*PreCapture), preCapture: make(map[*WaylandOutput]*PreCapture),
showCapturedCursor: true, showCapturedCursor: s.config.Cursor == CursorOn,
} }
} }

View File

@@ -453,10 +453,7 @@ func (s *Screenshoter) blitBuffer(dst, src *ShmBuffer, dstX, dstY int, yInverted
} }
func (s *Screenshoter) captureWholeOutput(output *WaylandOutput) (*CaptureResult, error) { func (s *Screenshoter) captureWholeOutput(output *WaylandOutput) (*CaptureResult, error) {
cursor := int32(0) cursor := int32(s.config.Cursor)
if s.config.IncludeCursor {
cursor = 1
}
frame, err := s.screencopy.CaptureOutput(cursor, output.wlOutput) frame, err := s.screencopy.CaptureOutput(cursor, output.wlOutput)
if err != nil { if err != nil {
@@ -624,10 +621,7 @@ func (s *Screenshoter) captureRegionOnOutput(output *WaylandOutput, region Regio
} }
} }
cursor := int32(0) cursor := int32(s.config.Cursor)
if s.config.IncludeCursor {
cursor = 1
}
frame, err := s.screencopy.CaptureOutputRegion(cursor, output.wlOutput, localX, localY, w, h) frame, err := s.screencopy.CaptureOutputRegion(cursor, output.wlOutput, localX, localY, w, h)
if err != nil { if err != nil {

View File

@@ -19,6 +19,13 @@ const (
FormatPPM FormatPPM
) )
type CursorMode int
const (
CursorOff CursorMode = iota
CursorOn
)
type Region struct { type Region struct {
X int32 `json:"x"` X int32 `json:"x"`
Y int32 `json:"y"` Y int32 `json:"y"`
@@ -44,7 +51,7 @@ type Output struct {
type Config struct { type Config struct {
Mode Mode Mode Mode
OutputName string OutputName string
IncludeCursor bool Cursor CursorMode
Format Format Format Format
Quality int Quality int
OutputDir string OutputDir string
@@ -58,7 +65,7 @@ type Config struct {
func DefaultConfig() Config { func DefaultConfig() Config {
return Config{ return Config{
Mode: ModeRegion, Mode: ModeRegion,
IncludeCursor: false, Cursor: CursorOff,
Format: FormatPNG, Format: FormatPNG,
Quality: 90, Quality: 90,
OutputDir: "", OutputDir: "",

View File

@@ -38,6 +38,22 @@ func XDGConfigHome() string {
return filepath.Join(home, ".config") return filepath.Join(home, ".config")
} }
func EmacsConfigDir() string {
home, _ := os.UserHomeDir()
emacsD := filepath.Join(home, ".emacs.d")
if info, err := os.Stat(emacsD); err == nil && info.IsDir() {
return emacsD
}
xdgEmacs := filepath.Join(XDGConfigHome(), "emacs")
if info, err := os.Stat(xdgEmacs); err == nil && info.IsDir() {
return xdgEmacs
}
return ""
}
func ExpandPath(path string) (string, error) { func ExpandPath(path string) (string, error) {
expanded := os.ExpandEnv(path) expanded := os.ExpandEnv(path)
expanded = filepath.Clean(expanded) expanded = filepath.Clean(expanded)

View File

@@ -60,6 +60,7 @@ Singleton {
property bool _hasLoaded: false property bool _hasLoaded: false
property bool _isReadOnly: false property bool _isReadOnly: false
property bool _hasUnsavedChanges: false property bool _hasUnsavedChanges: false
property bool _selfWrite: false
property var _loadedSettingsSnapshot: null property var _loadedSettingsSnapshot: null
property var pluginSettings: ({}) property var pluginSettings: ({})
property var builtInPluginSettings: ({}) property var builtInPluginSettings: ({})
@@ -1243,6 +1244,7 @@ Singleton {
function saveSettings() { function saveSettings() {
if (_loading || _parseError || !_hasLoaded) if (_loading || _parseError || !_hasLoaded)
return; return;
_selfWrite = true;
settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2)); settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2));
if (_isReadOnly) if (_isReadOnly)
_checkSettingsWritable(); _checkSettingsWritable();
@@ -2589,7 +2591,13 @@ Singleton {
blockWrites: true blockWrites: true
atomicWrites: true atomicWrites: true
watchChanges: true watchChanges: true
onFileChanged: settingsFileReloadDebounce.restart() onFileChanged: {
if (_selfWrite) {
_selfWrite = false;
return;
}
settingsFileReloadDebounce.restart();
}
onLoaded: { onLoaded: {
if (isGreeterMode) if (isGreeterMode)
return; return;

View File

@@ -81,6 +81,12 @@ function calculateNextIndex(flatModel, selectedFlatIndex, sectionId, viewMode, g
return bounds.start + newPosInSection; return bounds.start + newPosInSection;
} }
var currentRow = Math.floor(posInSection / cols);
var lastRow = Math.floor((bounds.count - 1) / cols);
if (currentRow < lastRow) {
return bounds.start + bounds.count - 1;
}
var nextSection = findNextNonHeaderIndex(flatModel, bounds.end + 1); var nextSection = findNextNonHeaderIndex(flatModel, bounds.end + 1);
return nextSection !== -1 ? nextSection : selectedFlatIndex; return nextSection !== -1 ? nextSection : selectedFlatIndex;
} }

View File

@@ -130,24 +130,17 @@ Item {
if (!entry || entry.isHeader) if (!entry || entry.isHeader)
return; return;
var rowIndex = _flatIndexToRowMap[index]; var rowIndex = _flatIndexToRowMap[index];
if (rowIndex === undefined || rowIndex >= _cumulativeHeights.length) if (rowIndex === undefined)
return;
var row = _visualRows[rowIndex];
if (!row)
return; return;
mainListView.positionViewAtIndex(rowIndex, ListView.Contain);
if (stickyHeader.visible && rowIndex < _cumulativeHeights.length) {
var rowY = _cumulativeHeights[rowIndex]; var rowY = _cumulativeHeights[rowIndex];
var rowHeight = row.height;
var scrollY = mainListView.contentY - mainListView.originY; var scrollY = mainListView.contentY - mainListView.originY;
var viewHeight = mainListView.height; if (rowY < scrollY + stickyHeader.height) {
var headerH = stickyHeader.height; mainListView.contentY = Math.max(mainListView.originY, rowY - stickyHeader.height + mainListView.originY);
if (rowY < scrollY + headerH) {
mainListView.contentY = Math.max(mainListView.originY, rowY - headerH + mainListView.originY);
return;
} }
if (rowY + rowHeight > scrollY + viewHeight) {
mainListView.contentY = rowY + rowHeight - viewHeight + mainListView.originY;
} }
} }

View File

@@ -83,9 +83,9 @@ FloatingWindow {
objectName: "processListModal" objectName: "processListModal"
title: I18n.tr("System Monitor", "sysmon window title") title: I18n.tr("System Monitor", "sysmon window title")
minimumSize: Qt.size(750, 550) minimumSize: Qt.size(Math.min(Math.round(Theme.fontSizeMedium * 48), Screen.width), Math.min(Math.round(Theme.fontSizeMedium * 34), Screen.height))
implicitWidth: 1000 implicitWidth: Math.round(Theme.fontSizeMedium * 71)
implicitHeight: 720 implicitHeight: Math.round(Theme.fontSizeMedium * 51)
color: Theme.surfaceContainer color: Theme.surfaceContainer
visible: false visible: false
@@ -236,7 +236,7 @@ FloatingWindow {
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 48 Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 3.4)
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@@ -293,10 +293,10 @@ FloatingWindow {
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 52 Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 3.7)
Layout.leftMargin: Theme.spacingL Layout.leftMargin: Theme.spacingL
Layout.rightMargin: Theme.spacingL Layout.rightMargin: Theme.spacingL
spacing: Theme.spacingL spacing: Theme.spacingM
Row { Row {
spacing: 2 spacing: 2
@@ -322,14 +322,15 @@ FloatingWindow {
] ]
Rectangle { Rectangle {
width: 120 width: tabRowContent.implicitWidth + Theme.spacingM * 2
height: 44 height: Math.round(Theme.fontSizeMedium * 3.1)
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: currentTab === index ? Theme.primaryPressed : (tabMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent") color: currentTab === index ? Theme.primaryPressed : (tabMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent")
border.color: currentTab === index ? Theme.primary : "transparent" border.color: currentTab === index ? Theme.primary : "transparent"
border.width: currentTab === index ? 1 : 0 border.width: currentTab === index ? 1 : 0
Row { Row {
id: tabRowContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
@@ -373,11 +374,13 @@ FloatingWindow {
DankButtonGroup { DankButtonGroup {
id: processFilterGroup id: processFilterGroup
Layout.minimumWidth: implicitWidth + 8
model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")] model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")]
currentIndex: 0 currentIndex: 0
checkEnabled: false checkEnabled: false
buttonHeight: 36 buttonHeight: Math.round(Theme.fontSizeSmall * 2.6)
minButtonWidth: 0
buttonPadding: Theme.spacingS
textSize: Theme.fontSizeSmall
visible: currentTab === 0 visible: currentTab === 0
onSelectionChanged: (index, selected) => { onSelectionChanged: (index, selected) => {
if (!selected) if (!selected)
@@ -400,9 +403,9 @@ FloatingWindow {
DankTextField { DankTextField {
id: searchField id: searchField
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumWidth: 250 Layout.maximumWidth: Math.round(Theme.fontSizeMedium * 18)
Layout.minimumWidth: 120 Layout.minimumWidth: Theme.fontSizeMedium * 4
Layout.preferredHeight: 40 Layout.preferredHeight: Math.round(Theme.fontSizeMedium * 2.8)
placeholderText: I18n.tr("Search processes...", "process search placeholder") placeholderText: I18n.tr("Search processes...", "process search placeholder")
leftIconName: "search" leftIconName: "search"
showClearButton: true showClearButton: true
@@ -470,7 +473,7 @@ FloatingWindow {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 32 Layout.preferredHeight: Math.round(Theme.fontSizeSmall * 2.7)
Layout.leftMargin: Theme.spacingL Layout.leftMargin: Theme.spacingL
Layout.rightMargin: Theme.spacingL Layout.rightMargin: Theme.spacingL
Layout.bottomMargin: Theme.spacingM Layout.bottomMargin: Theme.spacingM

View File

@@ -945,10 +945,11 @@ Column {
} }
} }
Component.onCompleted: { function tryCreatePluginInstance() {
Qt.callLater(() => {
const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; const pluginComponent = PluginService.pluginWidgetComponents[pluginId];
if (pluginComponent) { if (!pluginComponent)
return false;
try {
const instance = pluginComponent.createObject(null, { const instance = pluginComponent.createObject(null, {
"pluginId": pluginId, "pluginId": pluginId,
"pluginService": PluginService, "pluginService": PluginService,
@@ -958,9 +959,17 @@ Column {
}); });
if (instance) { if (instance) {
pluginInstance = instance; pluginInstance = instance;
return true;
} }
} catch (e) {
console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading");
PluginService.reloadPlugin(pluginId);
} }
}); return false;
}
Component.onCompleted: {
Qt.callLater(() => tryCreatePluginInstance());
} }
Connections { Connections {
@@ -970,6 +979,11 @@ Column {
pluginInstance.loadPluginData(); pluginInstance.loadPluginData();
} }
} }
function onPluginLoaded(loadedPluginId) {
if (loadedPluginId !== pluginId || pluginInstance)
return;
Qt.callLater(() => tryCreatePluginInstance());
}
} }
Component.onDestruction: { Component.onDestruction: {

View File

@@ -13,8 +13,8 @@ Row {
property Item popoutContent: null property Item popoutContent: null
signal addWidget(string widgetId) signal addWidget(string widgetId)
signal resetToDefault() signal resetToDefault
signal clearAll() signal clearAll
height: 48 height: 48
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -28,7 +28,7 @@ Row {
y: parent ? Math.round((parent.height - height) / 2) : 0 y: parent ? Math.round((parent.height - height) / 2) : 0
width: 400 width: 400
height: 300 height: 300
modal: true modal: false
focus: true focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
@@ -133,7 +133,7 @@ Row {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.addWidget(modelData.id) root.addWidget(modelData.id);
} }
} }
} }

View File

@@ -12,6 +12,7 @@ DankPopout {
id: root id: root
layerNamespace: "dms:control-center" layerNamespace: "dms:control-center"
fullHeightSurface: true
property string expandedSection: "" property string expandedSection: ""
property var triggerScreen: null property var triggerScreen: null

View File

@@ -216,14 +216,18 @@ QtObject {
} }
const pluginComponent = PluginService.pluginWidgetComponents[plugin.id]; const pluginComponent = PluginService.pluginWidgetComponents[plugin.id];
if (!pluginComponent || typeof pluginComponent.createObject !== 'function') { if (!pluginComponent)
continue; continue;
}
const tempInstance = pluginComponent.createObject(null); let tempInstance;
if (!tempInstance) { try {
tempInstance = pluginComponent.createObject(null);
} catch (e) {
PluginService.reloadPlugin(plugin.id);
continue; continue;
} }
if (!tempInstance)
continue;
const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0; const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0;
tempInstance.destroy(); tempInstance.destroy();

View File

@@ -155,6 +155,7 @@ BasePill {
property real touchpadThreshold: 500 property real touchpadThreshold: 500
onWheel: function (wheelEvent) { onWheel: function (wheelEvent) {
wheelEvent.accepted = true;
const deltaY = wheelEvent.angleDelta.y; const deltaY = wheelEvent.angleDelta.y;
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0;

View File

@@ -10,6 +10,45 @@ BasePill {
property bool isActive: false property bool isActive: false
readonly property bool hasUpdates: SystemUpdateService.updateCount > 0 readonly property bool hasUpdates: SystemUpdateService.updateCount > 0
readonly property bool isChecking: SystemUpdateService.isChecking readonly property bool isChecking: SystemUpdateService.isChecking
readonly property bool shouldHide: SettingsData.updaterHideWidget && !hasUpdates && !isChecking && !SystemUpdateService.hasError
opacity: shouldHide ? 0 : 1
states: [
State {
name: "hidden_horizontal"
when: root.shouldHide && !isVerticalOrientation
PropertyChanges {
target: root
width: 0
}
},
State {
name: "hidden_vertical"
when: root.shouldHide && isVerticalOrientation
PropertyChanges {
target: root
height: 0
}
}
]
transitions: [
Transition {
NumberAnimation {
properties: "width,height"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Ref { Ref {
service: SystemUpdateService service: SystemUpdateService

View File

@@ -924,8 +924,13 @@ Item {
return loadedIsUrgent; return loadedIsUrgent;
return false; return false;
} }
property var loadedIconData: null readonly property var loadedIconData: {
property bool loadedHasIcon: false if (isPlaceholder) return null;
const name = modelData?.name;
if (!name) return null;
return SettingsData.getWorkspaceNameIcon(name);
}
readonly property bool loadedHasIcon: loadedIconData !== null
property var loadedIcons: [] property var loadedIcons: []
readonly property int stableIconCount: { readonly property int stableIconCount: {
@@ -986,8 +991,8 @@ Item {
readonly property real baseHeight: root.isVertical ? (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) readonly property real baseHeight: root.isVertical ? (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5)
readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== "" readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== ""
readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && (CompositorService.isNiri || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && (CompositorService.isNiri || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
readonly property real contentImplicitWidth: (hasWorkspaceName || loadedHasIcon) ? (appIconsLoader.item?.contentWidth ?? 0) : 0 readonly property real contentImplicitWidth: hasWorkspaceName ? (appIconsLoader.item?.contentWidth ?? 0) : 0
readonly property real contentImplicitHeight: (workspaceNamesEnabled || loadedHasIcon) ? (appIconsLoader.item?.contentHeight ?? 0) : 0 readonly property real contentImplicitHeight: workspaceNamesEnabled ? (appIconsLoader.item?.contentHeight ?? 0) : 0
readonly property real iconsExtraWidth: { readonly property real iconsExtraWidth: {
if (!root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) { if (!root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) {
@@ -1222,8 +1227,6 @@ Item {
onTriggered: { onTriggered: {
if (isPlaceholder) { if (isPlaceholder) {
delegateRoot.loadedWorkspaceData = null; delegateRoot.loadedWorkspaceData = null;
delegateRoot.loadedIconData = null;
delegateRoot.loadedHasIcon = false;
delegateRoot.loadedIcons = []; delegateRoot.loadedIcons = [];
delegateRoot.loadedIsUrgent = false; delegateRoot.loadedIsUrgent = false;
return; return;
@@ -1249,13 +1252,6 @@ Item {
delegateRoot.loadedIsUrgent = wsData?.urgent ?? false; delegateRoot.loadedIsUrgent = wsData?.urgent ?? false;
} }
var icData = null;
if (wsData?.name) {
icData = SettingsData.getWorkspaceNameIcon(wsData.name);
}
delegateRoot.loadedIconData = icData;
delegateRoot.loadedHasIcon = icData !== null;
if (SettingsData.showWorkspaceApps) { if (SettingsData.showWorkspaceApps) {
if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData); delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData);
@@ -1420,7 +1416,7 @@ Item {
Item { Item {
visible: loadedHasIcon && loadedIconData?.type === "icon" visible: loadedHasIcon && loadedIconData?.type === "icon"
width: wsIcon.width + (isActive && loadedIcons.length > 0 ? 4 : 0) width: wsIcon.width
height: root.appIconSize height: root.appIconSize
DankIcon { DankIcon {
@@ -1435,7 +1431,7 @@ Item {
Item { Item {
visible: loadedHasIcon && loadedIconData?.type === "text" visible: loadedHasIcon && loadedIconData?.type === "text"
width: wsText.implicitWidth + (isActive && loadedIcons.length > 0 ? 4 : 0) width: wsText.implicitWidth
height: root.appIconSize height: root.appIconSize
StyledText { StyledText {
@@ -1449,14 +1445,14 @@ Item {
} }
Item { Item {
visible: (SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName)
width: wsIndexText.implicitWidth + (isActive && loadedIcons.length > 0 ? 4 : 0) width: wsIndexText.implicitWidth
height: root.appIconSize height: root.appIconSize
StyledText { StyledText {
id: wsIndexText id: wsIndexText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.getWorkspaceIndex(modelData, index) text: loadedHasIcon ? (modelData?.name ?? "") : root.getWorkspaceIndex(modelData, index)
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale) font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
@@ -1574,9 +1570,9 @@ Item {
} }
StyledText { StyledText {
visible: (SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName)
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: root.getWorkspaceIndex(modelData, index) text: loadedHasIcon ? (root.isVertical ? (modelData?.name ?? "").charAt(0) : (modelData?.name ?? "")) : root.getWorkspaceIndex(modelData, index)
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale) font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
@@ -1670,55 +1666,6 @@ Item {
} }
} }
// Loader for Custom Name Icon
Loader {
id: customIconLoader
anchors.fill: parent
active: !isPlaceholder && loadedHasIcon && loadedIconData.type === "icon" && !SettingsData.showWorkspaceApps
sourceComponent: Item {
DankIcon {
anchors.centerIn: parent
name: loadedIconData ? loadedIconData.value : "" // NULL CHECK
size: Theme.fontSizeSmall
color: isActive ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : Theme.surfaceTextMedium
weight: isActive && !isPlaceholder ? 500 : 400
}
}
}
// Loader for Custom Name Text
Loader {
id: customTextLoader
anchors.fill: parent
active: !isPlaceholder && loadedHasIcon && loadedIconData.type === "text" && !SettingsData.showWorkspaceApps
sourceComponent: Item {
StyledText {
anchors.centerIn: parent
text: loadedIconData ? loadedIconData.value : "" // NULL CHECK
color: isActive ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : Theme.surfaceTextMedium
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
}
}
}
// Loader for Workspace Index
Loader {
id: indexLoader
anchors.fill: parent
active: (SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon && !SettingsData.showWorkspaceApps
sourceComponent: Item {
StyledText {
anchors.centerIn: parent
text: {
return root.getWorkspaceIndex(modelData, index);
}
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
}
}
}
} }
Component.onCompleted: updateAllData() Component.onCompleted: updateAllData()

View File

@@ -278,7 +278,7 @@ Item {
Behavior on x { Behavior on x {
enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.notificationExitDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
@@ -286,7 +286,7 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: delegateRoot.__delegateInitialized enabled: delegateRoot.__delegateInitialized
NumberAnimation { NumberAnimation {
duration: delegateRoot.__delegateInitialized ? Theme.shortDuration : 0 duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0
} }
} }
} }

View File

@@ -257,7 +257,7 @@ DankListView {
target: delegateRoot target: delegateRoot
property: "swipeOffset" property: "swipeOffset"
to: 0 to: 0
duration: Theme.shortDuration duration: Theme.notificationExitDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
onStopped: NotificationService.dismissGroup(delegateRoot.modelData?.key || "") onStopped: NotificationService.dismissGroup(delegateRoot.modelData?.key || "")
} }

View File

@@ -764,7 +764,7 @@ Rectangle {
target: expandedDelegateWrapper target: expandedDelegateWrapper
property: "swipeOffset" property: "swipeOffset"
to: expandedDelegateWrapper.swipeOffset > 0 ? expandedDelegateWrapper.width : -expandedDelegateWrapper.width to: expandedDelegateWrapper.swipeOffset > 0 ? expandedDelegateWrapper.width : -expandedDelegateWrapper.width
duration: Theme.shortDuration duration: Theme.notificationExitDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
onStopped: NotificationService.dismissNotification(modelData) onStopped: NotificationService.dismissNotification(modelData)
} }

View File

@@ -7,6 +7,7 @@ DankPopout {
id: root id: root
layerNamespace: "dms:notification-center-popout" layerNamespace: "dms:notification-center-popout"
fullHeightSurface: true
property bool notificationHistoryVisible: false property bool notificationHistoryVisible: false
property var triggerScreen: null property var triggerScreen: null
@@ -34,9 +35,9 @@ DankPopout {
popupWidth: triggerScreen ? Math.min(500, Math.max(380, triggerScreen.width - 48)) : 400 popupWidth: triggerScreen ? Math.min(500, Math.max(380, triggerScreen.width - 48)) : 400
popupHeight: stablePopupHeight popupHeight: stablePopupHeight
positioning: "" positioning: ""
animationScaleCollapsed: 1.0 animationScaleCollapsed: 0.94
animationOffset: 0 animationOffset: 0
suspendShadowWhileResizing: true suspendShadowWhileResizing: false
screen: triggerScreen screen: triggerScreen
shouldBeVisible: notificationHistoryVisible shouldBeVisible: notificationHistoryVisible

View File

@@ -22,6 +22,8 @@ PanelWindow {
property bool _isDestroying: false property bool _isDestroying: false
property bool _finalized: false property bool _finalized: false
property real _lastReportedAlignedHeight: -1 property real _lastReportedAlignedHeight: -1
property real _storedTopMargin: 0
property real _storedBottomMargin: 0
readonly property string clearText: I18n.tr("Dismiss") readonly property string clearText: I18n.tr("Dismiss")
property bool descriptionExpanded: false property bool descriptionExpanded: false
readonly property bool hasExpandableBody: (notificationData?.htmlBody || "").replace(/<[^>]*>/g, "").trim().length > 0 readonly property bool hasExpandableBody: (notificationData?.htmlBody || "").replace(/<[^>]*>/g, "").trim().length > 0
@@ -146,6 +148,8 @@ PanelWindow {
} }
Component.onCompleted: { Component.onCompleted: {
_lastReportedAlignedHeight = Theme.px(implicitHeight, dpr); _lastReportedAlignedHeight = Theme.px(implicitHeight, dpr);
_storedTopMargin = getTopMargin();
_storedBottomMargin = getBottomMargin();
if (SettingsData.notificationPopupPrivacyMode) if (SettingsData.notificationPopupPrivacyMode)
descriptionExpanded = false; descriptionExpanded = false;
if (hasValidData) { if (hasValidData) {
@@ -179,14 +183,30 @@ PanelWindow {
property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter
property bool isCenterPosition: isTopCenter || isBottomCenter property bool isCenterPosition: isTopCenter || isBottomCenter
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left anchors.top: true
anchors.bottom: isBottomCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right anchors.bottom: true
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right
mask: contentInputMask
Region {
id: contentInputMask
item: contentMaskRect
}
Item {
id: contentMaskRect
visible: false
x: content.x
y: content.y
width: alignedWidth
height: alignedHeight
}
margins { margins {
top: getTopMargin() top: _storedTopMargin
bottom: getBottomMargin() bottom: _storedBottomMargin
left: getLeftMargin() left: getLeftMargin()
right: getRightMargin() right: getRightMargin()
} }
@@ -263,7 +283,14 @@ PanelWindow {
id: content id: content
x: Theme.snap((win.width - alignedWidth) / 2, dpr) x: Theme.snap((win.width - alignedWidth) / 2, dpr)
y: Theme.snap((win.height - alignedHeight) / 2, dpr) y: {
const isTop = isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left;
if (isTop) {
return Theme.snap(screenY, dpr);
} else {
return Theme.snap(win.height - alignedHeight - screenY, dpr);
}
}
width: alignedWidth width: alignedWidth
height: alignedHeight height: alignedHeight
visible: !win._finalized visible: !win._finalized
@@ -311,7 +338,7 @@ PanelWindow {
id: bgShadowLayer id: bgShadowLayer
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.snap(4, win.dpr) anchors.margins: Theme.snap(4, win.dpr)
layer.enabled: !win._isDestroying && win.screenValid && !implicitHeightAnim.running layer.enabled: !win._isDestroying && win.screenValid
layer.smooth: false layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr)) layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically layer.textureMirroring: ShaderEffectSource.MirrorVertically
@@ -814,7 +841,7 @@ PanelWindow {
Behavior on swipeOffset { Behavior on swipeOffset {
enabled: !content.swipeActive && !content.swipeDismissing enabled: !content.swipeActive && !content.swipeDismissing
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.notificationExitDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
@@ -824,7 +851,7 @@ PanelWindow {
target: content target: content
property: "swipeOffset" property: "swipeOffset"
to: isTopCenter ? -content.height : isBottomCenter ? content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width) to: isTopCenter ? -content.height : isBottomCenter ? content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width)
duration: Theme.shortDuration duration: Theme.notificationExitDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
onStopped: { onStopped: {
NotificationService.dismissNotification(notificationData); NotificationService.dismissNotification(notificationData);

View File

@@ -7,9 +7,10 @@ DankOSD {
id: root id: root
readonly property bool useVertical: isVerticalLayout readonly property bool useVertical: isVerticalLayout
property int targetBrightness: { property int _displayBrightness: 0
DisplayService.brightnessVersion;
return DisplayService.brightnessLevel; function _syncBrightness() {
_displayBrightness = DisplayService.brightnessLevel;
} }
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
@@ -20,11 +21,11 @@ DankOSD {
Connections { Connections {
target: DisplayService target: DisplayService
function onBrightnessChanged(showOsd) { function onBrightnessChanged(showOsd) {
if (showOsd && SettingsData.osdBrightnessEnabled) { root._syncBrightness();
if (showOsd && SettingsData.osdBrightnessEnabled)
root.show(); root.show();
} }
} }
}
content: Loader { content: Loader {
anchors.fill: parent anchors.fill: parent
@@ -53,14 +54,12 @@ DankOSD {
anchors.centerIn: parent anchors.centerIn: parent
name: { name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc")
return "brightness_medium"; return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) { if (deviceInfo.name.includes("kbd"))
return "keyboard"; return "keyboard";
} else {
return "lightbulb"; return "lightbulb";
} }
}
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
} }
@@ -77,20 +76,16 @@ DankOSD {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) if (!deviceInfo)
return 1; return 1;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); if (SessionData.getBrightnessExponential(deviceInfo.id))
if (isExponential) {
return 1; return 1;
}
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0;
} }
maximum: { maximum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) if (!deviceInfo)
return 100; return 100;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); if (SessionData.getBrightnessExponential(deviceInfo.id))
if (isExponential) {
return 100; return 100;
}
return deviceInfo.displayMax || 100; return deviceInfo.displayMax || 100;
} }
enabled: DisplayService.brightnessAvailable enabled: DisplayService.brightnessAvailable
@@ -99,28 +94,24 @@ DankOSD {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) if (!deviceInfo)
return "%"; return "%";
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); if (SessionData.getBrightnessExponential(deviceInfo.id))
if (isExponential) {
return "%"; return "%";
}
return deviceInfo.class === "ddc" ? "" : "%"; return deviceInfo.class === "ddc" ? "" : "%";
} }
thumbOutlineColor: Theme.surfaceContainer thumbOutlineColor: Theme.surfaceContainer
alwaysShowValue: SettingsData.osdAlwaysShowValue alwaysShowValue: SettingsData.osdAlwaysShowValue
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => {
if (DisplayService.brightnessAvailable) { if (!DisplayService.brightnessAvailable)
return;
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true); DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
resetHideTimer(); resetHideTimer();
} }
}
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse)
setChildHovered(containsMouse);
}
Binding on value { Binding on value {
value: root.targetBrightness value: root._displayBrightness
when: !brightnessSlider.isDragging when: !brightnessSlider.isDragging
} }
} }
@@ -146,14 +137,12 @@ DankOSD {
anchors.centerIn: parent anchors.centerIn: parent
name: { name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc")
return "brightness_medium"; return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) { if (deviceInfo.name.includes("kbd"))
return "keyboard"; return "keyboard";
} else {
return "lightbulb"; return "lightbulb";
} }
}
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
} }
@@ -170,7 +159,7 @@ DankOSD {
property int value: 50 property int value: 50
Binding on value { Binding on value {
value: root.targetBrightness value: root._displayBrightness
when: !vertSlider.dragging when: !vertSlider.dragging
} }
@@ -178,8 +167,7 @@ DankOSD {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) if (!deviceInfo)
return 1; return 1;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); if (SessionData.getBrightnessExponential(deviceInfo.id))
if (isExponential)
return 1; return 1;
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0;
} }
@@ -188,8 +176,7 @@ DankOSD {
const deviceInfo = DisplayService.getCurrentDeviceInfo(); const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) if (!deviceInfo)
return 100; return 100;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); if (SessionData.getBrightnessExponential(deviceInfo.id))
if (isExponential)
return 100; return 100;
return deviceInfo.displayMax || 100; return deviceInfo.displayMax || 100;
} }
@@ -240,33 +227,25 @@ DankOSD {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse)
setChildHovered(containsMouse);
}
onPressed: mouse => { onPressed: mouse => {
vertSlider.dragging = true; vertSlider.dragging = true;
updateBrightness(mouse); updateBrightness(mouse);
} }
onReleased: { onReleased: vertSlider.dragging = false
vertSlider.dragging = false;
}
onPositionChanged: mouse => { onPositionChanged: mouse => {
if (pressed) { if (pressed)
updateBrightness(mouse); updateBrightness(mouse);
} }
}
onClicked: mouse => { onClicked: mouse => updateBrightness(mouse)
updateBrightness(mouse);
}
function updateBrightness(mouse) { function updateBrightness(mouse) {
if (!DisplayService.brightnessAvailable) { if (!DisplayService.brightnessAvailable)
return; return;
}
const ratio = 1.0 - (mouse.y / height); const ratio = 1.0 - (mouse.y / height);
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum)); const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum));
vertSlider.value = newValue; vertSlider.value = newValue;

View File

@@ -8,13 +8,20 @@ DankOSD {
readonly property bool useVertical: isVerticalLayout readonly property bool useVertical: isVerticalLayout
readonly property var player: MprisController.activePlayer readonly property var player: MprisController.activePlayer
readonly property int currentVolume: player ? Math.min(100, Math.round(player.volume * 100)) : 0
readonly property bool volumeSupported: player?.volumeSupported ?? false readonly property bool volumeSupported: player?.volumeSupported ?? false
property bool _suppressNewPlayer: false property bool _suppressNewPlayer: false
property int _displayVolume: 0
function _syncVolume() {
if (!player)
return;
_displayVolume = Math.min(100, Math.round(player.volume * 100));
}
onPlayerChanged: { onPlayerChanged: {
_suppressNewPlayer = true; _suppressNewPlayer = true;
_suppressTimer.restart(); _suppressTimer.restart();
_syncVolume();
} }
Timer { Timer {
@@ -37,27 +44,27 @@ DankOSD {
} }
function toggleMute() { function toggleMute() {
if (player) { if (!player)
return;
player.volume = player.volume > 0 ? 0 : 1; player.volume = player.volume > 0 ? 0 : 1;
} }
}
function setVolume(volumePercent) { function setVolume(volumePercent) {
if (player) { if (!player)
return;
player.volume = volumePercent / 100; player.volume = volumePercent / 100;
resetHideTimer(); resetHideTimer();
} }
}
Connections { Connections {
target: player target: player
function onVolumeChanged() { function onVolumeChanged() {
if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer) { root._syncVolume();
if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer)
root.show(); root.show();
} }
} }
}
content: Loader { content: Loader {
anchors.fill: parent anchors.fill: parent
@@ -96,9 +103,7 @@ DankOSD {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: toggleMute() onClicked: toggleMute()
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse)
setChildHovered(containsMouse || volumeSlider.containsMouse);
}
} }
} }
@@ -115,29 +120,21 @@ DankOSD {
showValue: true showValue: true
unit: "%" unit: "%"
thumbOutlineColor: Theme.surfaceContainer thumbOutlineColor: Theme.surfaceContainer
valueOverride: currentVolume valueOverride: root._displayVolume
alwaysShowValue: SettingsData.osdAlwaysShowValue alwaysShowValue: SettingsData.osdAlwaysShowValue
Component.onCompleted: { Component.onCompleted: {
value = currentVolume; root._syncVolume();
value = root._displayVolume;
} }
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => setVolume(newValue)
setVolume(newValue);
}
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse)
setChildHovered(containsMouse || muteButton.containsMouse);
}
Connections { Binding on value {
target: player value: root._displayVolume
when: !volumeSlider.pressed
function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = currentVolume;
}
}
} }
} }
} }
@@ -172,9 +169,7 @@ DankOSD {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: toggleMute() onClicked: toggleMute()
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse)
setChildHovered(containsMouse || vertSliderArea.containsMouse);
}
} }
} }
@@ -186,7 +181,7 @@ DankOSD {
y: gap * 2 + Theme.iconSize y: gap * 2 + Theme.iconSize
property bool dragging: false property bool dragging: false
property int value: currentVolume property int value: root._displayVolume
Rectangle { Rectangle {
id: vertTrack id: vertTrack
@@ -231,28 +226,21 @@ DankOSD {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse)
setChildHovered(containsMouse || muteButtonVert.containsMouse);
}
onPressed: mouse => { onPressed: mouse => {
vertSlider.dragging = true; vertSlider.dragging = true;
updateVolume(mouse); updateVolume(mouse);
} }
onReleased: { onReleased: vertSlider.dragging = false
vertSlider.dragging = false;
}
onPositionChanged: mouse => { onPositionChanged: mouse => {
if (pressed) { if (pressed)
updateVolume(mouse); updateVolume(mouse);
} }
}
onClicked: mouse => { onClicked: mouse => updateVolume(mouse)
updateVolume(mouse);
}
function updateVolume(mouse) { function updateVolume(mouse) {
const ratio = 1.0 - (mouse.y / height); const ratio = 1.0 - (mouse.y / height);
@@ -260,16 +248,6 @@ DankOSD {
setVolume(volume); setVolume(volume);
} }
} }
Connections {
target: player
function onVolumeChanged() {
if (!vertSlider.dragging) {
vertSlider.value = currentVolume;
}
}
}
} }
StyledText { StyledText {
@@ -283,15 +261,4 @@ DankOSD {
} }
} }
} }
onOsdShown: {
if (player && contentLoader.item && contentLoader.item.item) {
if (!useVertical) {
const slider = contentLoader.item.item.children[0].children[1];
if (slider && slider.value !== undefined) {
slider.value = currentVolume;
}
}
}
}
} }

View File

@@ -7,6 +7,13 @@ DankOSD {
id: root id: root
readonly property bool useVertical: isVerticalLayout readonly property bool useVertical: isVerticalLayout
property int _displayVolume: 0
function _syncVolume() {
if (!AudioService.sink?.audio)
return;
_displayVolume = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2) osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
@@ -14,30 +21,29 @@ DankOSD {
enableMouseInteraction: true enableMouseInteraction: true
Connections { Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null target: AudioService.sink?.audio ?? null
function onVolumeChanged() { function onVolumeChanged() {
if (SettingsData.osdVolumeEnabled) { root._syncVolume();
if (SettingsData.osdVolumeEnabled)
root.show(); root.show();
} }
}
function onMutedChanged() { function onMutedChanged() {
if (SettingsData.osdVolumeEnabled) { if (SettingsData.osdVolumeEnabled)
root.show(); root.show();
} }
} }
}
Connections { Connections {
target: AudioService target: AudioService
function onSinkChanged() { function onSinkChanged() {
if (root.shouldBeVisible && SettingsData.osdVolumeEnabled) { root._syncVolume();
if (root.shouldBeVisible && SettingsData.osdVolumeEnabled)
root.show(); root.show();
} }
} }
}
content: Loader { content: Loader {
anchors.fill: parent anchors.fill: parent
@@ -64,7 +70,7 @@ DankOSD {
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ? "volume_off" : "volume_up" name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up"
size: Theme.iconSize size: Theme.iconSize
color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText
} }
@@ -75,60 +81,45 @@ DankOSD {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: AudioService.toggleMute()
AudioService.toggleMute(); onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse)
}
onContainsMouseChanged: {
setChildHovered(containsMouse || volumeSlider.containsMouse);
}
} }
} }
DankSlider { DankSlider {
id: volumeSlider id: volumeSlider
readonly property real actualVolumePercent: AudioService.sink && AudioService.sink.audio ? Math.round(AudioService.sink.audio.volume * 100) : 0
readonly property real displayPercent: actualVolumePercent
width: parent.width - Theme.iconSize - parent.gap * 3 width: parent.width - Theme.iconSize - parent.gap * 3
height: 40 height: 40
x: parent.gap * 2 + Theme.iconSize x: parent.gap * 2 + Theme.iconSize
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
minimum: 0 minimum: 0
maximum: AudioService.sinkMaxVolume maximum: AudioService.sinkMaxVolume
enabled: AudioService.sink && AudioService.sink.audio enabled: AudioService.sink?.audio
showValue: true showValue: true
unit: "%" unit: "%"
thumbOutlineColor: Theme.surfaceContainer thumbOutlineColor: Theme.surfaceContainer
valueOverride: displayPercent valueOverride: root._displayVolume
alwaysShowValue: SettingsData.osdAlwaysShowValue alwaysShowValue: SettingsData.osdAlwaysShowValue
Component.onCompleted: { Component.onCompleted: {
if (AudioService.sink && AudioService.sink.audio) { root._syncVolume();
value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); value = root._displayVolume;
}
} }
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => {
if (AudioService.sink && AudioService.sink.audio) { if (!AudioService.sink?.audio)
return;
SessionData.suppressOSDTemporarily(); SessionData.suppressOSDTemporarily();
AudioService.sink.audio.volume = newValue / 100; AudioService.sink.audio.volume = newValue / 100;
resetHideTimer(); resetHideTimer();
} }
}
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse)
setChildHovered(containsMouse || muteButton.containsMouse);
}
Connections { Binding on value {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null value: root._displayVolume
when: !volumeSlider.pressed
function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
}
} }
} }
} }
@@ -151,7 +142,7 @@ DankOSD {
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ? "volume_off" : "volume_up" name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up"
size: Theme.iconSize size: Theme.iconSize
color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText
} }
@@ -162,12 +153,8 @@ DankOSD {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: AudioService.toggleMute()
AudioService.toggleMute(); onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse)
}
onContainsMouseChanged: {
setChildHovered(containsMouse || vertSliderArea.containsMouse);
}
} }
} }
@@ -179,7 +166,7 @@ DankOSD {
y: gap * 2 + Theme.iconSize y: gap * 2 + Theme.iconSize
property bool dragging: false property bool dragging: false
property int value: AudioService.sink && AudioService.sink.audio ? Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)) : 0 property int value: root._displayVolume
Rectangle { Rectangle {
id: vertTrack id: vertTrack
@@ -220,35 +207,29 @@ DankOSD {
id: vertSliderArea id: vertSliderArea
anchors.fill: parent anchors.fill: parent
anchors.margins: -12 anchors.margins: -12
enabled: AudioService.sink && AudioService.sink.audio enabled: AudioService.sink?.audio
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: { onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse)
setChildHovered(containsMouse || muteButtonVert.containsMouse);
}
onPressed: mouse => { onPressed: mouse => {
vertSlider.dragging = true; vertSlider.dragging = true;
updateVolume(mouse); updateVolume(mouse);
} }
onReleased: { onReleased: vertSlider.dragging = false
vertSlider.dragging = false;
}
onPositionChanged: mouse => { onPositionChanged: mouse => {
if (pressed) { if (pressed)
updateVolume(mouse); updateVolume(mouse);
} }
}
onClicked: mouse => { onClicked: mouse => updateVolume(mouse)
updateVolume(mouse);
}
function updateVolume(mouse) { function updateVolume(mouse) {
if (AudioService.sink && AudioService.sink.audio) { if (!AudioService.sink?.audio)
return;
const maxVol = AudioService.sinkMaxVolume; const maxVol = AudioService.sinkMaxVolume;
const ratio = 1.0 - (mouse.y / height); const ratio = 1.0 - (mouse.y / height);
const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol))); const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol)));
@@ -259,15 +240,6 @@ DankOSD {
} }
} }
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
vertSlider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
}
}
StyledText { StyledText {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -279,15 +251,4 @@ DankOSD {
} }
} }
} }
onOsdShown: {
if (AudioService.sink && AudioService.sink.audio && contentLoader.item && contentLoader.item.item) {
if (!useVertical) {
const slider = contentLoader.item.item.children[0].children[1];
if (slider && slider.value !== undefined) {
slider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
}
}
}
} }

View File

@@ -18,36 +18,41 @@ Column {
property bool isInitialized: false property bool isInitialized: false
function loadValue() { function loadValue() {
const settings = findSettings() const settings = findSettings();
if (settings && settings.pluginService) { if (settings && settings.pluginService) {
const loadedValue = settings.loadValue(settingKey, defaultValue) const loadedValue = settings.loadValue(settingKey, defaultValue);
value = loadedValue if (textField.activeFocus && isInitialized)
textField.text = loadedValue return;
isInitialized = true value = loadedValue;
textField.text = loadedValue;
isInitialized = true;
} }
} }
Component.onCompleted: { Component.onCompleted: {
Qt.callLater(loadValue) Qt.callLater(loadValue);
} }
onValueChanged: { function commit() {
if (!isInitialized) return if (!isInitialized)
const settings = findSettings() return;
if (settings) { if (textField.text === value)
settings.saveValue(settingKey, value) return;
} value = textField.text;
const settings = findSettings();
if (settings)
settings.saveValue(settingKey, value);
} }
function findSettings() { function findSettings() {
let item = parent let item = parent;
while (item) { while (item) {
if (item.saveValue !== undefined && item.loadValue !== undefined) { if (item.saveValue !== undefined && item.loadValue !== undefined) {
return item return item;
} }
item = item.parent item = item.parent;
} }
return null return null;
} }
StyledText { StyledText {
@@ -70,16 +75,10 @@ Column {
id: textField id: textField
width: parent.width width: parent.width
placeholderText: root.placeholder placeholderText: root.placeholder
onTextEdited: { onEditingFinished: root.commit()
root.value = text
}
onEditingFinished: {
root.value = text
}
onActiveFocusChanged: { onActiveFocusChanged: {
if (!activeFocus) { if (!activeFocus)
root.value = text root.commit();
}
} }
} }
} }

View File

@@ -26,8 +26,8 @@ DankPopout {
open(); open();
} }
popupWidth: 650 popupWidth: Math.round(Theme.fontSizeMedium * 46)
popupHeight: 550 popupHeight: Math.round(Theme.fontSizeMedium * 39)
triggerWidth: 55 triggerWidth: 55
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen
@@ -151,11 +151,13 @@ DankPopout {
DankButtonGroup { DankButtonGroup {
id: processFilterGroup id: processFilterGroup
Layout.minimumWidth: implicitWidth + 8 Layout.minimumWidth: implicitWidth
model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")] model: [I18n.tr("All"), I18n.tr("User"), I18n.tr("System")]
currentIndex: 0 currentIndex: 0
checkEnabled: false checkEnabled: false
buttonHeight: Math.round(Theme.fontSizeMedium * 2.2) buttonHeight: Math.round(Theme.fontSizeSmall * 2.4)
minButtonWidth: 0
buttonPadding: Theme.spacingM
textSize: Theme.fontSizeSmall textSize: Theme.fontSizeSmall
onSelectionChanged: (index, selected) => { onSelectionChanged: (index, selected) => {
if (!selected) if (!selected)
@@ -177,7 +179,8 @@ DankPopout {
DankTextField { DankTextField {
id: searchField id: searchField
Layout.preferredWidth: Theme.fontSizeMedium * 14 Layout.fillWidth: true
Layout.minimumWidth: Theme.fontSizeMedium * 8
Layout.preferredHeight: Theme.fontSizeMedium * 2.5 Layout.preferredHeight: Theme.fontSizeMedium * 2.5
placeholderText: I18n.tr("Search...") placeholderText: I18n.tr("Search...")
leftIconName: "search" leftIconName: "search"

View File

@@ -375,8 +375,20 @@ FocusScope {
if (!plugin || !PluginService.isPluginLoaded(pluginId)) if (!plugin || !PluginService.isPluginLoaded(pluginId))
return; return;
var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
if (isLauncher) if (isLauncher) {
PluginService.reloadPlugin(pluginId); pluginReloadTimer.pendingPluginId = pluginId;
pluginReloadTimer.restart();
}
}
}
Timer {
id: pluginReloadTimer
property string pendingPluginId: ""
interval: 500
onTriggered: {
if (pendingPluginId)
PluginService.reloadPlugin(pendingPluginId);
} }
} }

View File

@@ -16,7 +16,7 @@ Item {
property var cachedCursorThemes: SettingsData.availableCursorThemes property var cachedCursorThemes: SettingsData.availableCursorThemes
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label) property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label)
property var installedRegistryThemes: [] property var installedRegistryThemes: []
property var templateDetection: ({}) property var templateDetection: []
property var cursorIncludeStatus: ({ property var cursorIncludeStatus: ({
"exists": false, "exists": false,
@@ -106,9 +106,10 @@ Item {
} }
function isTemplateDetected(templateId) { function isTemplateDetected(templateId) {
if (!templateDetection || Object.keys(templateDetection).length === 0) if (!templateDetection || templateDetection.length === 0)
return true; return true;
return templateDetection[templateId] !== false; var item = templateDetection.find(i => i.id === templateId);
return !item || item.detected !== false;
} }
function getTemplateDescription(templateId, baseDescription) { function getTemplateDescription(templateId, baseDescription) {
@@ -145,30 +146,17 @@ Item {
DMSService.listInstalledThemes(); DMSService.listInstalledThemes();
if (PopoutService.pendingThemeInstall) if (PopoutService.pendingThemeInstall)
Qt.callLater(() => showThemeBrowser()); Qt.callLater(() => showThemeBrowser());
templateCheckProcess.running = true; Proc.runCommand("template-check", ["dms", "matugen", "check"], (output, exitCode) => {
if (exitCode !== 0)
return;
try {
themeColorsTab.templateDetection = JSON.parse(output.trim());
} catch (e) {}
});
if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl) if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl)
checkCursorIncludeStatus(); checkCursorIncludeStatus();
} }
Process {
id: templateCheckProcess
command: ["dms", "matugen", "check"]
running: false
stdout: StdioCollector {
onStreamFinished: {
try {
const results = JSON.parse(text);
const detection = {};
for (const item of results) {
detection[item.id] = item.detected;
}
themeColorsTab.templateDetection = detection;
} catch (e) {}
}
}
}
Connections { Connections {
target: DMSService target: DMSService
function onInstalledThemesReceived(themes) { function onInstalledThemesReceived(themes) {

View File

@@ -1 +1 @@
v1.4.0 v1.4.1

View File

@@ -28,6 +28,10 @@ PanelWindow {
function show() { function show() {
if (SessionData.suppressOSD) if (SessionData.suppressOSD)
return; return;
if (shouldBeVisible) {
hideTimer.restart();
return;
}
OSDManager.showOSD(root); OSDManager.showOSD(root);
closeTimer.stop(); closeTimer.stop();
shouldBeVisible = true; shouldBeVisible = true;
@@ -257,7 +261,7 @@ PanelWindow {
property real shadowSpreadPx: 0 property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60 property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha * osdContainer.opacity)) readonly property real effectiveShadowAlpha: shouldBeVisible ? Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha)) : 0
Rectangle { Rectangle {
id: background id: background

View File

@@ -30,7 +30,10 @@ Item {
property var customKeyboardFocus: null property var customKeyboardFocus: null
property bool backgroundInteractive: true property bool backgroundInteractive: true
property bool contentHandlesKeys: false property bool contentHandlesKeys: false
property bool fullHeightSurface: false
property bool _resizeActive: false property bool _resizeActive: false
property real _surfaceMarginLeft: 0
property real _surfaceW: 0
property real storedBarThickness: Theme.barHeight - 4 property real storedBarThickness: Theme.barHeight - 4
property real storedBarSpacing: 4 property real storedBarSpacing: 4
@@ -125,6 +128,10 @@ Item {
_lastOpenedScreen = screen; _lastOpenedScreen = screen;
shouldBeVisible = true; shouldBeVisible = true;
if (useBackgroundWindow) {
_surfaceMarginLeft = alignedX - shadowBuffer;
_surfaceW = alignedWidth + shadowBuffer * 2;
}
Qt.callLater(() => { Qt.callLater(() => {
if (shouldBeVisible && screen) { if (shouldBeVisible && screen) {
if (useBackgroundWindow) if (useBackgroundWindow)
@@ -360,20 +367,38 @@ Item {
return WlrKeyboardFocus.Exclusive; return WlrKeyboardFocus.Exclusive;
} }
readonly property bool _fullHeight: useBackgroundWindow && root.fullHeightSurface
anchors { anchors {
left: true left: true
top: true top: true
right: !useBackgroundWindow right: !useBackgroundWindow
bottom: !useBackgroundWindow bottom: _fullHeight || !useBackgroundWindow
} }
WlrLayershell.margins { WlrLayershell.margins {
left: useBackgroundWindow ? (root.alignedX - shadowBuffer) : 0 left: useBackgroundWindow ? root._surfaceMarginLeft : 0
top: useBackgroundWindow ? (root.alignedY - shadowBuffer) : 0 top: (useBackgroundWindow && !_fullHeight) ? (root.alignedY - shadowBuffer) : 0
} }
implicitWidth: useBackgroundWindow ? (root.alignedWidth + (shadowBuffer * 2)) : 0 implicitWidth: useBackgroundWindow ? root._surfaceW : 0
implicitHeight: useBackgroundWindow ? (root.alignedHeight + (shadowBuffer * 2)) : 0 implicitHeight: (useBackgroundWindow && !_fullHeight) ? (root.alignedHeight + shadowBuffer * 2) : 0
mask: (useBackgroundWindow && _fullHeight) ? contentInputMask : null
Region {
id: contentInputMask
item: contentMaskRect
}
Item {
id: contentMaskRect
visible: false
x: contentContainer.x - root.shadowBuffer
y: contentContainer.y - root.shadowBuffer
width: root.alignedWidth + root.shadowBuffer * 2
height: root.alignedHeight + root.shadowBuffer * 2
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@@ -393,7 +418,7 @@ Item {
Item { Item {
id: contentContainer id: contentContainer
x: useBackgroundWindow ? shadowBuffer : root.alignedX x: useBackgroundWindow ? shadowBuffer : root.alignedX
y: useBackgroundWindow ? shadowBuffer : root.alignedY y: (useBackgroundWindow && !contentWindow._fullHeight) ? shadowBuffer : root.alignedY
width: root.alignedWidth width: root.alignedWidth
height: root.alignedHeight height: root.alignedHeight
@@ -444,6 +469,44 @@ Item {
} }
} }
Rectangle {
id: shadowSource
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: Theme.cornerRadius
color: "black"
visible: false
opacity: contentWrapper.opacity
scale: contentWrapper.scale
x: contentWrapper.x
y: contentWrapper.y
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
readonly property int blurMax: 64
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
layer.smooth: false
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, shadowSource.shadowBlurPx / shadowSource.blurMax))
shadowScale: 1 + (2 * shadowSource.shadowSpreadPx) / Math.max(1, Math.min(shadowSource.width, shadowSource.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, shadowSource.effectiveShadowAlpha);
}
}
}
Item { Item {
id: contentWrapper id: contentWrapper
anchors.centerIn: parent anchors.centerIn: parent
@@ -455,31 +518,10 @@ Item {
x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
property real shadowBlurPx: 10 layer.enabled: contentWrapper.opacity < 1
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
readonly property int blurMax: 64
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
layer.smooth: false layer.smooth: false
layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0) layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0)
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / contentWrapper.blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(contentWrapper.width, contentWrapper.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, contentWrapper.effectiveShadowAlpha);
}
}
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: animationDuration duration: animationDuration

View File

@@ -1,3 +1,3 @@
[templates.dmsemacs] [templates.dmsemacs]
input_path = 'SHELL_DIR/matugen/templates/dank-emacs.el' input_path = 'SHELL_DIR/matugen/templates/dank-emacs.el'
output_path = "~/.emacs.d/themes/dank-emacs-theme.el" output_path = 'EMACS_DIR/themes/dank-emacs-theme.el'