1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-03 11:02:08 -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
18 changed files with 418 additions and 337 deletions

View File

@@ -430,7 +430,7 @@ func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Packa
}
// 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{
Phase: PhaseSystemPackages,

View File

@@ -33,6 +33,7 @@ const (
TemplateKindTerminal
TemplateKindGTK
TemplateKindVSCode
TemplateKindEmacs
)
type TemplateDef struct {
@@ -65,7 +66,7 @@ var templateRegistry = []TemplateDef{
{ID: "dgop", Commands: []string{"dgop"}, ConfigFile: "dgop.toml"},
{ID: "kcolorscheme", ConfigFile: "kcolorscheme.toml", RunUnconditionally: true},
{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 {
@@ -78,7 +79,8 @@ func (c *ColorMode) GTKTheme() string {
}
var (
matugenVersionOnce sync.Once
matugenVersionMu sync.Mutex
matugenVersionOK bool
matugenSupportsCOE bool
matugenIsV4 bool
)
@@ -334,6 +336,10 @@ output_path = '%s'
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/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)
case TemplateKindEmacs:
if utils.EmacsConfigDir() != "" {
appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile)
}
default:
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, "'DATA_DIR/", "'"+utils.XDGDataHome()+"/")
result = strings.ReplaceAll(result, "'CACHE_DIR/", "'"+utils.XDGCacheHome()+"/")
if emacsDir := utils.EmacsConfigDir(); emacsDir != "" {
result = strings.ReplaceAll(result, "'EMACS_DIR/", "'"+emacsDir+"/")
}
return result
}
@@ -511,79 +520,160 @@ func extractTOMLSection(content, startMarker, endMarker string) string {
return content[startIdx : startIdx+endIdx]
}
func checkMatugenVersion() {
matugenVersionOnce.Do(func() {
cmd := exec.Command("matugen", "--version")
output, err := cmd.Output()
if err != nil {
return
}
versionStr := strings.TrimSpace(string(output))
versionStr = strings.TrimPrefix(versionStr, "matugen ")
parts := strings.Split(versionStr, ".")
if len(parts) < 2 {
return
}
major, err := strconv.Atoi(parts[0])
if err != nil {
return
}
minor, err := strconv.Atoi(parts[1])
if err != nil {
return
}
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
matugenIsV4 = major >= 4
if matugenSupportsCOE {
log.Infof("Matugen %s supports --continue-on-error", versionStr)
}
if matugenIsV4 {
log.Infof("Matugen %s: using v4 flags", versionStr)
}
})
type matugenFlags struct {
supportsCOE bool
isV4 bool
}
func runMatugen(args []string) error {
checkMatugenVersion()
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")
output, err := cmd.Output()
if err != nil {
return matugenFlags{}, fmt.Errorf("failed to get matugen version: %w", err)
}
versionStr := strings.TrimSpace(string(output))
versionStr = strings.TrimPrefix(versionStr, "matugen ")
parts := strings.Split(versionStr, ".")
if len(parts) < 2 {
return matugenFlags{}, fmt.Errorf("unexpected matugen version format: %q", versionStr)
}
major, err := strconv.Atoi(parts[0])
if err != nil {
return matugenFlags{}, fmt.Errorf("failed to parse matugen major version %q: %w", parts[0], err)
}
minor, err := strconv.Atoi(parts[1])
if err != nil {
return matugenFlags{}, fmt.Errorf("failed to parse matugen minor version %q: %w", parts[1], err)
}
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
matugenIsV4 = major >= 4
matugenVersionOK = true
if matugenSupportsCOE {
args = append([]string{"--continue-on-error"}, args...)
log.Infof("Matugen %s supports --continue-on-error", versionStr)
}
if matugenIsV4 {
log.Infof("Matugen %s: using v4 flags", versionStr)
}
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
}
func buildMatugenArgs(baseArgs []string, flags matugenFlags) []string {
args := make([]string, 0, len(baseArgs)+4)
if flags.supportsCOE {
args = append(args, "--continue-on-error")
}
args = append(args, baseArgs...)
if flags.isV4 {
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.Stdout = os.Stdout
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) {
checkMatugenVersion()
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()
flags, err := detectMatugenVersion()
if err != nil {
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
}
@@ -819,6 +909,8 @@ func CheckTemplates(checker utils.AppChecker) []TemplateCheck {
detected = true
case tmpl.Kind == TemplateKindVSCode:
detected = checkVSCodeExtension(homeDir)
case tmpl.Kind == TemplateKindEmacs:
detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) && utils.EmacsConfigDir() != ""
default:
detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks)
}

View File

@@ -38,6 +38,22 @@ func XDGConfigHome() string {
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) {
expanded := os.ExpandEnv(path)
expanded = filepath.Clean(expanded)

View File

@@ -1 +1 @@
The Wolverine
Saffron Bloom

View File

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

View File

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

View File

@@ -22,6 +22,8 @@ PanelWindow {
property bool _isDestroying: false
property bool _finalized: false
property real _lastReportedAlignedHeight: -1
property real _storedTopMargin: 0
property real _storedBottomMargin: 0
readonly property string clearText: I18n.tr("Dismiss")
property bool descriptionExpanded: false
readonly property bool hasExpandableBody: (notificationData?.htmlBody || "").replace(/<[^>]*>/g, "").trim().length > 0
@@ -146,6 +148,8 @@ PanelWindow {
}
Component.onCompleted: {
_lastReportedAlignedHeight = Theme.px(implicitHeight, dpr);
_storedTopMargin = getTopMargin();
_storedBottomMargin = getBottomMargin();
if (SettingsData.notificationPopupPrivacyMode)
descriptionExpanded = false;
if (hasValidData) {
@@ -179,14 +183,30 @@ PanelWindow {
property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter
property bool isCenterPosition: isTopCenter || isBottomCenter
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left
anchors.bottom: isBottomCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right
anchors.top: true
anchors.bottom: true
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
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 {
top: getTopMargin()
bottom: getBottomMargin()
top: _storedTopMargin
bottom: _storedBottomMargin
left: getLeftMargin()
right: getRightMargin()
}
@@ -263,7 +283,14 @@ PanelWindow {
id: content
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
height: alignedHeight
visible: !win._finalized
@@ -311,7 +338,7 @@ PanelWindow {
id: bgShadowLayer
anchors.fill: parent
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.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically

View File

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

View File

@@ -8,13 +8,20 @@ DankOSD {
readonly property bool useVertical: isVerticalLayout
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
property bool _suppressNewPlayer: false
property int _displayVolume: 0
function _syncVolume() {
if (!player)
return;
_displayVolume = Math.min(100, Math.round(player.volume * 100));
}
onPlayerChanged: {
_suppressNewPlayer = true;
_suppressTimer.restart();
_syncVolume();
}
Timer {
@@ -37,25 +44,25 @@ DankOSD {
}
function toggleMute() {
if (player) {
player.volume = player.volume > 0 ? 0 : 1;
}
if (!player)
return;
player.volume = player.volume > 0 ? 0 : 1;
}
function setVolume(volumePercent) {
if (player) {
player.volume = volumePercent / 100;
resetHideTimer();
}
if (!player)
return;
player.volume = volumePercent / 100;
resetHideTimer();
}
Connections {
target: player
function onVolumeChanged() {
if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer) {
root._syncVolume();
if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer)
root.show();
}
}
}
@@ -96,9 +103,7 @@ DankOSD {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: toggleMute()
onContainsMouseChanged: {
setChildHovered(containsMouse || volumeSlider.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse)
}
}
@@ -115,29 +120,21 @@ DankOSD {
showValue: true
unit: "%"
thumbOutlineColor: Theme.surfaceContainer
valueOverride: currentVolume
valueOverride: root._displayVolume
alwaysShowValue: SettingsData.osdAlwaysShowValue
Component.onCompleted: {
value = currentVolume;
root._syncVolume();
value = root._displayVolume;
}
onSliderValueChanged: newValue => {
setVolume(newValue);
}
onSliderValueChanged: newValue => setVolume(newValue)
onContainsMouseChanged: {
setChildHovered(containsMouse || muteButton.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse)
Connections {
target: player
function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = currentVolume;
}
}
Binding on value {
value: root._displayVolume
when: !volumeSlider.pressed
}
}
}
@@ -172,9 +169,7 @@ DankOSD {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: toggleMute()
onContainsMouseChanged: {
setChildHovered(containsMouse || vertSliderArea.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse)
}
}
@@ -186,7 +181,7 @@ DankOSD {
y: gap * 2 + Theme.iconSize
property bool dragging: false
property int value: currentVolume
property int value: root._displayVolume
Rectangle {
id: vertTrack
@@ -231,28 +226,21 @@ DankOSD {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: {
setChildHovered(containsMouse || muteButtonVert.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse)
onPressed: mouse => {
vertSlider.dragging = true;
updateVolume(mouse);
}
onReleased: {
vertSlider.dragging = false;
}
onReleased: vertSlider.dragging = false
onPositionChanged: mouse => {
if (pressed) {
if (pressed)
updateVolume(mouse);
}
}
onClicked: mouse => {
updateVolume(mouse);
}
onClicked: mouse => updateVolume(mouse)
function updateVolume(mouse) {
const ratio = 1.0 - (mouse.y / height);
@@ -260,16 +248,6 @@ DankOSD {
setVolume(volume);
}
}
Connections {
target: player
function onVolumeChanged() {
if (!vertSlider.dragging) {
vertSlider.value = currentVolume;
}
}
}
}
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
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)
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
@@ -14,18 +21,17 @@ DankOSD {
enableMouseInteraction: true
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
target: AudioService.sink?.audio ?? null
function onVolumeChanged() {
if (SettingsData.osdVolumeEnabled) {
root._syncVolume();
if (SettingsData.osdVolumeEnabled)
root.show();
}
}
function onMutedChanged() {
if (SettingsData.osdVolumeEnabled) {
if (SettingsData.osdVolumeEnabled)
root.show();
}
}
}
@@ -33,9 +39,9 @@ DankOSD {
target: AudioService
function onSinkChanged() {
if (root.shouldBeVisible && SettingsData.osdVolumeEnabled) {
root._syncVolume();
if (root.shouldBeVisible && SettingsData.osdVolumeEnabled)
root.show();
}
}
}
@@ -64,7 +70,7 @@ DankOSD {
DankIcon {
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
color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText
}
@@ -75,60 +81,45 @@ DankOSD {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
AudioService.toggleMute();
}
onContainsMouseChanged: {
setChildHovered(containsMouse || volumeSlider.containsMouse);
}
onClicked: AudioService.toggleMute()
onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse)
}
}
DankSlider {
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
height: 40
x: parent.gap * 2 + Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
minimum: 0
maximum: AudioService.sinkMaxVolume
enabled: AudioService.sink && AudioService.sink.audio
enabled: AudioService.sink?.audio
showValue: true
unit: "%"
thumbOutlineColor: Theme.surfaceContainer
valueOverride: displayPercent
valueOverride: root._displayVolume
alwaysShowValue: SettingsData.osdAlwaysShowValue
Component.onCompleted: {
if (AudioService.sink && AudioService.sink.audio) {
value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
root._syncVolume();
value = root._displayVolume;
}
onSliderValueChanged: newValue => {
if (AudioService.sink && AudioService.sink.audio) {
SessionData.suppressOSDTemporarily();
AudioService.sink.audio.volume = newValue / 100;
resetHideTimer();
}
if (!AudioService.sink?.audio)
return;
SessionData.suppressOSDTemporarily();
AudioService.sink.audio.volume = newValue / 100;
resetHideTimer();
}
onContainsMouseChanged: {
setChildHovered(containsMouse || muteButton.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse)
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
}
}
Binding on value {
value: root._displayVolume
when: !volumeSlider.pressed
}
}
}
@@ -151,7 +142,7 @@ DankOSD {
DankIcon {
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
color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText
}
@@ -162,12 +153,8 @@ DankOSD {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
AudioService.toggleMute();
}
onContainsMouseChanged: {
setChildHovered(containsMouse || vertSliderArea.containsMouse);
}
onClicked: AudioService.toggleMute()
onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse)
}
}
@@ -179,7 +166,7 @@ DankOSD {
y: gap * 2 + Theme.iconSize
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 {
id: vertTrack
@@ -220,50 +207,35 @@ DankOSD {
id: vertSliderArea
anchors.fill: parent
anchors.margins: -12
enabled: AudioService.sink && AudioService.sink.audio
enabled: AudioService.sink?.audio
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: {
setChildHovered(containsMouse || muteButtonVert.containsMouse);
}
onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse)
onPressed: mouse => {
vertSlider.dragging = true;
updateVolume(mouse);
}
onReleased: {
vertSlider.dragging = false;
}
onReleased: vertSlider.dragging = false
onPositionChanged: mouse => {
if (pressed) {
if (pressed)
updateVolume(mouse);
}
}
onClicked: mouse => {
updateVolume(mouse);
}
onClicked: mouse => updateVolume(mouse)
function updateVolume(mouse) {
if (AudioService.sink && AudioService.sink.audio) {
const maxVol = AudioService.sinkMaxVolume;
const ratio = 1.0 - (mouse.y / height);
const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol)));
SessionData.suppressOSDTemporarily();
AudioService.sink.audio.volume = volume / 100;
resetHideTimer();
}
}
}
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));
if (!AudioService.sink?.audio)
return;
const maxVol = AudioService.sinkMaxVolume;
const ratio = 1.0 - (mouse.y / height);
const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol)));
SessionData.suppressOSDTemporarily();
AudioService.sink.audio.volume = volume / 100;
resetHideTimer();
}
}
}
@@ -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
function loadValue() {
const settings = findSettings()
const settings = findSettings();
if (settings && settings.pluginService) {
const loadedValue = settings.loadValue(settingKey, defaultValue)
value = loadedValue
textField.text = loadedValue
isInitialized = true
const loadedValue = settings.loadValue(settingKey, defaultValue);
if (textField.activeFocus && isInitialized)
return;
value = loadedValue;
textField.text = loadedValue;
isInitialized = true;
}
}
Component.onCompleted: {
Qt.callLater(loadValue)
Qt.callLater(loadValue);
}
onValueChanged: {
if (!isInitialized) return
const settings = findSettings()
if (settings) {
settings.saveValue(settingKey, value)
}
function commit() {
if (!isInitialized)
return;
if (textField.text === value)
return;
value = textField.text;
const settings = findSettings();
if (settings)
settings.saveValue(settingKey, value);
}
function findSettings() {
let item = parent
let item = parent;
while (item) {
if (item.saveValue !== undefined && item.loadValue !== undefined) {
return item
return item;
}
item = item.parent
item = item.parent;
}
return null
return null;
}
StyledText {
@@ -70,16 +75,10 @@ Column {
id: textField
width: parent.width
placeholderText: root.placeholder
onTextEdited: {
root.value = text
}
onEditingFinished: {
root.value = text
}
onEditingFinished: root.commit()
onActiveFocusChanged: {
if (!activeFocus) {
root.value = text
}
if (!activeFocus)
root.commit();
}
}
}

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ Singleton {
id: root
readonly property string currentVersion: "1.4"
readonly property bool changelogEnabled: false
readonly property bool changelogEnabled: true
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion

View File

@@ -1 +1 @@
v1.5-beta
v1.4.1

View File

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

View File

@@ -469,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 {
id: contentWrapper
anchors.centerIn: parent
@@ -480,31 +518,10 @@ Item {
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)
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.enabled: contentWrapper.opacity < 1
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.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 {
NumberAnimation {
duration: animationDuration

View File

@@ -1,3 +1,3 @@
[templates.dmsemacs]
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'