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

Compare commits

...

11 Commits

Author SHA1 Message Date
bbedward
03a8e1e0d5 clipboard: fix memory leak from unbounded offer maps and unguarded file reads 2026-02-20 11:42:14 -05:00
bbedward
4d4d3c20a1 keybinds/niri: fix quote preservation 2026-02-20 11:42:14 -05:00
bbedward
cef16d6bc9 dankdash: fix widgets across different bar section fixes #1764s 2026-02-20 11:42:14 -05:00
bbedward
aafaad1791 core/screenshot: light cleanups 2026-02-20 11:42:14 -05:00
Patrick Fischer
7906fdc2b0 screensaver: emit ActiveChanged on lock/unlock (#1761) 2026-02-20 11:42:14 -05:00
Triệu Kha
397650ca52 clipboard: improve image thumbnail (#1759)
- thumbnail image is now bigger
- circular mask has been replaced with rounded rectangular mask
2026-02-20 11:42:14 -05:00
purian23
826207006a template: Default install method 2026-02-20 11:42:14 -05:00
purian23
58c2fcd31c issues: Template fix 2026-02-20 11:42:14 -05:00
purian23
b2a2b425ec templates: Fix GitHub issue labels 2026-02-20 11:42:14 -05:00
shorinkiwata
942c9c9609 feat(distros): allow CatOS to run DMS installer (#1768)
- This PR adds support for **CatOS**
- CatOS is fully compatible with Arch Linux
2026-02-20 11:42:14 -05:00
purian23
46d6e1cff3 templates: Update DMS issue formats 2026-02-20 11:42:14 -05:00
20 changed files with 474 additions and 122 deletions

View File

@@ -8,31 +8,31 @@ body:
value: |
## DankMaterialShell Bug Report
Limit your report to one issue per submission unless closely related
- type: checkboxes
- type: dropdown
id: compositor
attributes:
label: Compositor
options:
- label: Niri
- label: Hyprland
- label: MangoWC (dwl)
- label: Sway
- Niri
- Hyprland
- MangoWC (dwl)
- Sway
validations:
required: true
- type: checkboxes
- type: dropdown
id: distribution
attributes:
label: Distribution
options:
- label: Arch Linux
- label: CachyOS
- label: Fedora
- label: NixOS
- label: Debian
- label: Ubuntu
- label: Gentoo
- label: OpenSUSE
- label: Other (specify below)
- Arch Linux
- CachyOS
- Fedora
- NixOS
- Debian
- Ubuntu
- Gentoo
- OpenSUSE
- Other (specify below)
validations:
required: true
- type: input
@@ -42,12 +42,45 @@ body:
placeholder: e.g., PikaOS, Void Linux, etc.
validations:
required: false
- type: dropdown
id: installation_method
attributes:
label: Select your Installation Method
options:
- DankInstaller
- Distro Packaging
- Source
validations:
required: true
- type: dropdown
id: original_installation_method_different
attributes:
label: Was your original Installation method different?
options:
- "Yes"
- No (specify below)
default: 0
validations:
required: false
- type: input
id: original_installation_method_specify
attributes:
label: If no, specify
placeholder: e.g., Distro Packaging, then Source
validations:
required: false
- type: textarea
id: dms_doctor
attributes:
label: dms doctor -vC
description: Output of `dms doctor -vC` command
description: Output of `dms doctor -vC` command — paste between the lines below to keep it collapsed in the issue
placeholder: Paste the output of `dms doctor -vC` here
value: |
<details>
<summary>Click to expand</summary>
</details>
validations:
required: true
- type: textarea
@@ -69,7 +102,7 @@ body:
- type: textarea
id: steps_to_reproduce
attributes:
label: Steps to Reproduce & Installation Method
label: Steps to Reproduce
description: Please provide detailed steps to reproduce the issue
placeholder: |
1. ...

View File

@@ -23,18 +23,25 @@ body:
placeholder: Why is this feature important?
validations:
required: false
- type: checkboxes
- type: dropdown
id: compositor
attributes:
label: Compositor(s)
description: Is this feature specific to one or more compositors?
options:
- label: All compositors
- label: Niri
- label: Hyprland
- label: MangoWC (dwl)
- label: Sway
- label: Other (specify below)
- All compositors
- Niri
- Hyprland
- MangoWC (dwl)
- Sway
- Other (specify below)
validations:
required: true
- type: input
id: compositor_other
attributes:
label: If Other, please specify
placeholder: e.g., Wayfire, Mutter, etc.
validations:
required: false
- type: textarea

View File

@@ -7,32 +7,87 @@ body:
attributes:
value: |
## DankMaterialShell Support Request
- type: checkboxes
- type: dropdown
id: compositor
attributes:
label: Compositor
options:
- label: Niri
- label: Hyprland
- label: MangoWC (dwl)
- label: Sway
- label: Other (specify below)
- Niri
- Hyprland
- MangoWC (dwl)
- Sway
- Other (specify below)
validations:
required: true
- type: input
id: compositor_other
attributes:
label: If Other, please specify
placeholder: e.g., Wayfire, Mutter, etc.
validations:
required: false
- type: input
- type: dropdown
id: distribution
attributes:
label: Distribution
description: Which Linux distribution are you using? (e.g., Arch, Fedora, Debian, etc.)
placeholder: Your Linux distribution
options:
- Arch Linux
- CachyOS
- Fedora
- NixOS
- Debian
- Ubuntu
- Gentoo
- OpenSUSE
- Other (specify below)
validations:
required: true
- type: input
id: distribution_other
attributes:
label: If Other, please specify
placeholder: e.g., PikaOS, Void Linux, etc.
validations:
required: false
- type: dropdown
id: installation_method
attributes:
label: Select your Installation Method
options:
- DankInstaller
- Distro Packaging
- Source
validations:
required: true
- type: dropdown
id: original_installation_method_different
attributes:
label: Was your original Installation method different?
options:
- "Yes"
- No (specify below)
default: 0
validations:
required: false
- type: input
id: original_installation_method_specify
attributes:
label: If no, specify
placeholder: e.g., Distro Packaging, then Source
validations:
required: false
- type: textarea
id: dms_doctor
attributes:
label: dms doctor -vC
description: Output of `dms doctor -vC` command
description: Output of `dms doctor -vC` command — paste between the lines below to keep it collapsed in the issue
placeholder: Paste the output of `dms doctor -vC` here
value: |
<details>
<summary>Click to expand</summary>
</details>
validations:
required: false
- type: textarea

View File

@@ -26,6 +26,9 @@ func init() {
Register("cachyos", "#08A283", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
return NewArchDistribution(config, logChan)
})
Register("catos", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
return NewArchDistribution(config, logChan)
})
Register("endeavouros", "#7F3FBF", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
return NewArchDistribution(config, logChan)
})

View File

@@ -341,6 +341,8 @@ func (n *NiriProvider) buildActionFromNode(bindNode *document.Node) string {
val := arg.ValueString()
if val == "" {
parts = append(parts, `""`)
} else if strings.ContainsAny(val, " \t") {
parts = append(parts, `"`+strings.ReplaceAll(val, `"`, `\"`)+`"`)
} else {
parts = append(parts, val)
}

View File

@@ -232,8 +232,15 @@ func (m *Manager) setupDataDeviceSync() {
return
}
prevOffer := m.currentOffer
m.currentOffer = offer
if prevOffer != nil && prevOffer != offer {
m.offerMutex.Lock()
delete(m.offerMimeTypes, prevOffer)
m.offerMutex.Unlock()
}
m.offerMutex.RLock()
mimes := m.offerMimeTypes[offer]
m.offerMutex.RUnlock()
@@ -587,20 +594,26 @@ func (m *Manager) uriListPreview(data []byte) (string, bool) {
uris = strings.Split(text, "\n")
}
if len(uris) > 1 {
return fmt.Sprintf("[[ %d files ]]", len(uris)), false
}
if len(uris) == 1 && strings.HasPrefix(uris[0], "file://") {
filePath := strings.TrimPrefix(uris[0], "file://")
if info, err := os.Stat(filePath); err == nil && !info.IsDir() {
info, err := os.Stat(filePath)
if err != nil || info.IsDir() {
return m.textPreview(data), false
}
cfg := m.getConfig()
if info.Size() <= cfg.MaxEntrySize {
if imgData, err := os.ReadFile(filePath); err == nil {
if config, imgFmt, err := image.DecodeConfig(bytes.NewReader(imgData)); err == nil {
return fmt.Sprintf("[[ file %s %s %dx%d ]]", filepath.Base(filePath), imgFmt, config.Width, config.Height), true
}
}
return fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), false
}
}
if len(uris) > 1 {
return fmt.Sprintf("[[ %d files ]]", len(uris)), false
return fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)), false
}
return m.textPreview(data), false
@@ -623,6 +636,11 @@ func (m *Manager) tryReadImageFromURI(data []byte) ([]byte, string, bool) {
return nil, "", false
}
cfg := m.getConfig()
if info.Size() > cfg.MaxEntrySize {
return nil, "", false
}
imgData, err := os.ReadFile(filePath)
if err != nil {
return nil, "", false

View File

@@ -16,4 +16,8 @@ const (
dbusScreensaverPath = "/ScreenSaver"
dbusScreensaverPath2 = "/org/freedesktop/ScreenSaver"
dbusScreensaverInterface = "org.freedesktop.ScreenSaver"
dbusGnomeScreensaverName = "org.gnome.ScreenSaver"
dbusGnomeScreensaverPath = "/org/gnome/ScreenSaver"
dbusGnomeScreensaverInterface = "org.gnome.ScreenSaver"
)

View File

@@ -191,6 +191,12 @@ func (m *Manager) Close() {
return true
})
m.screensaverSubscribers.Range(func(key string, ch chan ScreensaverState) bool {
close(ch)
m.screensaverSubscribers.Delete(key)
return true
})
if m.systemConn != nil {
m.systemConn.Close()
}

View File

@@ -1,6 +1,7 @@
package freedesktop
import (
"fmt"
"path/filepath"
"strings"
"sync/atomic"
@@ -15,45 +16,9 @@ type screensaverHandler struct {
manager *Manager
}
func (m *Manager) initializeScreensaver() error {
if m.sessionConn == nil {
m.stateMutex.Lock()
m.state.Screensaver.Available = false
m.stateMutex.Unlock()
return nil
}
reply, err := m.sessionConn.RequestName(dbusScreensaverName, dbus.NameFlagDoNotQueue)
if err != nil {
log.Warnf("Failed to request screensaver name: %v", err)
m.stateMutex.Lock()
m.state.Screensaver.Available = false
m.stateMutex.Unlock()
return nil
}
if reply != dbus.RequestNameReplyPrimaryOwner {
log.Warnf("Screensaver name already owned by another process")
m.stateMutex.Lock()
m.state.Screensaver.Available = false
m.stateMutex.Unlock()
return nil
}
handler := &screensaverHandler{manager: m}
if err := m.sessionConn.Export(handler, dbusScreensaverPath, dbusScreensaverInterface); err != nil {
log.Warnf("Failed to export screensaver on %s: %v", dbusScreensaverPath, err)
return nil
}
if err := m.sessionConn.Export(handler, dbusScreensaverPath2, dbusScreensaverInterface); err != nil {
log.Warnf("Failed to export screensaver on %s: %v", dbusScreensaverPath2, err)
return nil
}
screensaverIface := introspect.Interface{
Name: dbusScreensaverInterface,
func screensaverIntrospectIface(ifaceName string) introspect.Interface {
return introspect.Interface{
Name: ifaceName,
Methods: []introspect.Method{
{
Name: "Inhibit",
@@ -69,40 +34,106 @@ func (m *Manager) initializeScreensaver() error {
{Name: "cookie", Type: "u", Direction: "in"},
},
},
{
Name: "GetActive",
Args: []introspect.Arg{
{Name: "active", Type: "b", Direction: "out"},
},
},
{
Name: "SetActive",
Args: []introspect.Arg{
{Name: "active", Type: "b", Direction: "in"},
},
},
{
Name: "Lock",
},
},
Signals: []introspect.Signal{
{
Name: "ActiveChanged",
Args: []introspect.Arg{
{Name: "new_value", Type: "b"},
},
},
},
}
}
func (m *Manager) initializeScreensaver() error {
if m.sessionConn == nil {
m.stateMutex.Lock()
m.state.Screensaver.Available = false
m.stateMutex.Unlock()
return nil
}
introNode := &introspect.Node{
Name: dbusScreensaverPath,
Interfaces: []introspect.Interface{
introspect.IntrospectData,
screensaverIface,
},
}
if err := m.sessionConn.Export(introspect.NewIntrospectable(introNode), dbusScreensaverPath, "org.freedesktop.DBus.Introspectable"); err != nil {
log.Warnf("Failed to export introspectable on %s: %v", dbusScreensaverPath, err)
}
handler := &screensaverHandler{manager: m}
introNode2 := &introspect.Node{
Name: dbusScreensaverPath2,
Interfaces: []introspect.Interface{
introspect.IntrospectData,
screensaverIface,
},
}
if err := m.sessionConn.Export(introspect.NewIntrospectable(introNode2), dbusScreensaverPath2, "org.freedesktop.DBus.Introspectable"); err != nil {
log.Warnf("Failed to export introspectable on %s: %v", dbusScreensaverPath2, err)
m.screensaverFreedesktopClaimed = m.claimScreensaverName(handler,
dbusScreensaverName, dbusScreensaverInterface, dbusScreensaverPath, dbusScreensaverPath2)
m.screensaverGnomeClaimed = m.claimScreensaverName(handler,
dbusGnomeScreensaverName, dbusGnomeScreensaverInterface, dbusGnomeScreensaverPath)
if !m.screensaverFreedesktopClaimed && !m.screensaverGnomeClaimed {
log.Warn("No screensaver interface could be claimed")
m.stateMutex.Lock()
m.state.Screensaver.Available = false
m.stateMutex.Unlock()
return nil
}
go m.watchPeerDisconnects()
m.stateMutex.Lock()
m.state.Screensaver.Available = true
m.state.Screensaver.Active = false
m.state.Screensaver.Inhibited = false
m.state.Screensaver.Inhibitors = []ScreensaverInhibitor{}
m.stateMutex.Unlock()
log.Info("Screensaver inhibit listener initialized")
log.Info("Screensaver listener initialized")
return nil
}
func (m *Manager) claimScreensaverName(handler *screensaverHandler, name, iface string, paths ...dbus.ObjectPath) bool {
reply, err := m.sessionConn.RequestName(name, dbus.NameFlagDoNotQueue)
if err != nil {
log.Warnf("Failed to request screensaver name %s: %v", name, err)
return false
}
if reply != dbus.RequestNameReplyPrimaryOwner {
log.Warnf("Screensaver name %s already owned by another process", name)
return false
}
if err := m.exportScreensaverOnPaths(handler, iface, paths...); err != nil {
log.Warnf("Failed to export screensaver on %s: %v", name, err)
return false
}
log.Infof("Claimed %s on session bus", name)
return true
}
// exportScreensaverOnPaths exports the handler and introspection on the given
// paths under the specified interface name.
func (m *Manager) exportScreensaverOnPaths(handler *screensaverHandler, ifaceName string, paths ...dbus.ObjectPath) error {
iface := screensaverIntrospectIface(ifaceName)
for _, path := range paths {
if err := m.sessionConn.Export(handler, path, ifaceName); err != nil {
return fmt.Errorf("export handler on %s: %w", path, err)
}
node := &introspect.Node{
Name: string(path),
Interfaces: []introspect.Interface{
introspect.IntrospectData,
iface,
},
}
if err := m.sessionConn.Export(introspect.NewIntrospectable(node), path, "org.freedesktop.DBus.Introspectable"); err != nil {
log.Warnf("Failed to export introspectable on %s: %v", path, err)
}
}
return nil
}
@@ -268,3 +299,51 @@ func (m *Manager) NotifyScreensaverSubscribers() {
return true
})
}
func (h *screensaverHandler) GetActive() (bool, *dbus.Error) {
h.manager.stateMutex.RLock()
active := h.manager.state.Screensaver.Active
h.manager.stateMutex.RUnlock()
return active, nil
}
func (h *screensaverHandler) SetActive(active bool) *dbus.Error {
h.manager.SetScreenLockActive(active)
return nil
}
func (h *screensaverHandler) Lock() *dbus.Error {
h.manager.SetScreenLockActive(true)
return nil
}
func (m *Manager) SetScreenLockActive(active bool) {
m.stateMutex.Lock()
changed := m.state.Screensaver.Active != active
m.state.Screensaver.Active = active
m.stateMutex.Unlock()
if !changed {
return
}
log.Infof("Screen lock active changed: %v", active)
defer m.NotifyScreensaverSubscribers()
if m.sessionConn == nil {
return
}
if m.screensaverFreedesktopClaimed {
if err := m.sessionConn.Emit(dbusScreensaverPath, dbusScreensaverInterface+".ActiveChanged", active); err != nil {
log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusScreensaverPath, err)
}
if err := m.sessionConn.Emit(dbusScreensaverPath2, dbusScreensaverInterface+".ActiveChanged", active); err != nil {
log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusScreensaverPath2, err)
}
}
if m.screensaverGnomeClaimed {
if err := m.sessionConn.Emit(dbusGnomeScreensaverPath, dbusGnomeScreensaverInterface+".ActiveChanged", active); err != nil {
log.Warnf("Failed to emit ActiveChanged on %s: %v", dbusGnomeScreensaverPath, err)
}
}
}

View File

@@ -0,0 +1,102 @@
package freedesktop
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestSetScreenLockActive_ChangesState(t *testing.T) {
manager := &Manager{
state: &FreedeskState{
Screensaver: ScreensaverState{Available: true},
},
stateMutex: sync.RWMutex{},
}
assert.False(t, manager.GetScreensaverState().Active)
manager.SetScreenLockActive(true)
assert.True(t, manager.GetScreensaverState().Active)
manager.SetScreenLockActive(false)
assert.False(t, manager.GetScreensaverState().Active)
}
func TestSetScreenLockActive_NoChangeNoDuplicate(t *testing.T) {
ch := make(chan ScreensaverState, 64)
manager := &Manager{
state: &FreedeskState{
Screensaver: ScreensaverState{Available: true, Active: false},
},
stateMutex: sync.RWMutex{},
}
manager.screensaverSubscribers.Store("test", ch)
defer manager.screensaverSubscribers.Delete("test")
// Setting to same value should not notify
manager.SetScreenLockActive(false)
select {
case <-ch:
t.Fatal("should not have received notification for no-change")
case <-time.After(50 * time.Millisecond):
// Expected: no notification
}
}
func TestSetScreenLockActive_NotifiesSubscribers(t *testing.T) {
ch := make(chan ScreensaverState, 64)
manager := &Manager{
state: &FreedeskState{
Screensaver: ScreensaverState{Available: true, Active: false},
},
stateMutex: sync.RWMutex{},
}
manager.screensaverSubscribers.Store("test", ch)
defer manager.screensaverSubscribers.Delete("test")
manager.SetScreenLockActive(true)
select {
case state := <-ch:
assert.True(t, state.Active)
case <-time.After(time.Second):
t.Fatal("timeout waiting for subscriber notification")
}
}
func TestSetScreenLockActive_NilSessionConn(t *testing.T) {
manager := &Manager{
state: &FreedeskState{
Screensaver: ScreensaverState{Available: true},
},
stateMutex: sync.RWMutex{},
}
assert.NotPanics(t, func() {
manager.SetScreenLockActive(true)
})
assert.True(t, manager.GetScreensaverState().Active)
}
func TestGetActive_ReturnsCurrentState(t *testing.T) {
manager := &Manager{
state: &FreedeskState{
Screensaver: ScreensaverState{Available: true, Active: true},
},
stateMutex: sync.RWMutex{},
}
handler := &screensaverHandler{manager: manager}
active, dbusErr := handler.GetActive()
assert.Nil(t, dbusErr)
assert.True(t, active)
}
func TestScreensaverState_ActiveDefaultsFalse(t *testing.T) {
state := ScreensaverState{}
assert.False(t, state.Active)
}

View File

@@ -39,6 +39,7 @@ type ScreensaverInhibitor struct {
type ScreensaverState struct {
Available bool `json:"available"`
Active bool `json:"active"`
Inhibited bool `json:"inhibited"`
Inhibitors []ScreensaverInhibitor `json:"inhibitors"`
}
@@ -50,14 +51,16 @@ type FreedeskState struct {
}
type Manager struct {
state *FreedeskState
stateMutex sync.RWMutex
systemConn *dbus.Conn
sessionConn *dbus.Conn
accountsObj dbus.BusObject
settingsObj dbus.BusObject
currentUID uint64
subscribers syncmap.Map[string, chan FreedeskState]
screensaverSubscribers syncmap.Map[string, chan ScreensaverState]
screensaverCookieCounter uint32
state *FreedeskState
stateMutex sync.RWMutex
systemConn *dbus.Conn
sessionConn *dbus.Conn
accountsObj dbus.BusObject
settingsObj dbus.BusObject
currentUID uint64
subscribers syncmap.Map[string, chan FreedeskState]
screensaverSubscribers syncmap.Map[string, chan ScreensaverState]
screensaverCookieCounter uint32
screensaverFreedesktopClaimed bool
screensaverGnomeClaimed bool
}

View File

@@ -1516,7 +1516,11 @@ func Start(printDocs bool) error {
}
}()
loginctlReady := make(chan struct{})
freedesktopReady := make(chan struct{})
go func() {
defer close(loginctlReady)
if err := InitializeLoginctlManager(); err != nil {
log.Warnf("Loginctl manager unavailable: %v", err)
} else {
@@ -1525,6 +1529,7 @@ func Start(printDocs bool) error {
}()
go func() {
defer close(freedesktopReady)
if err := InitializeFreedeskManager(); err != nil {
log.Warnf("Freedesktop manager unavailable: %v", err)
} else if freedesktopManager != nil {
@@ -1533,6 +1538,31 @@ func Start(printDocs bool) error {
}
}()
// Bridge loginctl lock state to the freedesktop/gnome screensaver
// ActiveChanged signal so apps like Bitwarden can detect screen lock.
go func() {
<-loginctlReady
<-freedesktopReady
if loginctlManager == nil || freedesktopManager == nil {
return
}
ch := loginctlManager.Subscribe("dms-lock-bridge")
defer loginctlManager.Unsubscribe("dms-lock-bridge")
initial := loginctlManager.GetState()
lastLocked := initial.Locked
freedesktopManager.SetScreenLockActive(lastLocked)
for state := range ch {
if state.Locked != lastLocked {
lastLocked = state.Locked
freedesktopManager.SetScreenLockActive(lastLocked)
}
}
}()
if err := InitializeWaylandManager(); err != nil {
log.Warnf("Wayland manager unavailable: %v", err)
}

View File

@@ -162,7 +162,7 @@ func TestCleanupStaleSockets(t *testing.T) {
tempDir := t.TempDir()
t.Setenv("XDG_RUNTIME_DIR", tempDir)
staleSocket := filepath.Join(tempDir, "danklinux-999999.sock")
staleSocket := filepath.Join(tempDir, "danklinux-4194305.sock")
err := os.WriteFile(staleSocket, []byte{}, 0o600)
require.NoError(t, err)

View File

@@ -142,6 +142,8 @@ Singleton {
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
popout.currentTabIndex = tabIndex;
}
if (popout.updateSurfacePosition)
popout.updateSurfacePosition();
currentPopoutTriggers[screenName] = triggerId;
return;
}

View File

@@ -12,7 +12,7 @@ Singleton {
readonly property int popoutWidth: 550
readonly property int popoutHeight: 500
readonly property int itemHeight: 72
readonly property int thumbnailSize: 48
readonly property int thumbnailSize: 100
readonly property int retryInterval: 50
readonly property int viewportBuffer: 100
readonly property int extendedBuffer: 200

View File

@@ -84,7 +84,8 @@ Rectangle {
anchors.right: actionButtons.left
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
height: contentColumn.implicitHeight
// height: contentColumn.implicitHeight
height: ClipboardConstants.itemHeight
clip: true
ClipboardThumbnail {
@@ -92,7 +93,7 @@ Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: entryType === "image" ? ClipboardConstants.thumbnailSize : Theme.iconSize
height: entryType === "image" ? ClipboardConstants.thumbnailSize : Theme.iconSize
height: entryType === "image" ? ClipboardConstants.itemHeight - 4 : Theme.iconSize // 100 - 4 = 96, 96:72 = 4:3
entry: root.entry
entryType: root.entryType
modal: root.modal

View File

@@ -137,23 +137,23 @@ Item {
anchors.margins: 2
source: thumbnailImage
maskEnabled: true
maskSource: clipboardCircularMask
maskSource: clipboardRoundedRectangularMask
visible: entryType === "image" && thumbnailImage.status === Image.Ready && thumbnailImage.source != ""
maskThresholdMin: 0.5
maskSpreadAtMin: 1
}
Item {
id: clipboardCircularMask
width: ClipboardConstants.thumbnailSize - 4
height: ClipboardConstants.thumbnailSize - 4
id: clipboardRoundedRectangularMask
width: ClipboardConstants.thumbnailSize
height: ClipboardConstants.itemHeight - 4
layer.enabled: true
layer.smooth: true
visible: false
Rectangle {
anchors.fill: parent
radius: width / 2
radius: Theme.cornerRadius / 2 // Thumbnail corner radius is divided by 2 so it doesnt look weird on large corner radius (eg: 32px)
color: "black"
antialiasing: true
}

View File

@@ -811,7 +811,7 @@ Item {
} else {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
}
PopoutManager.requestPopout(dankDashPopoutLoader.item, 0, (effectiveBarConfig?.id ?? "default") + "-0");
PopoutManager.requestPopout(dankDashPopoutLoader.item, 0, (effectiveBarConfig?.id ?? "default") + "-" + section + "-0");
}
}
}
@@ -867,7 +867,7 @@ Item {
} else {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
}
PopoutManager.requestPopout(dankDashPopoutLoader.item, 1, (effectiveBarConfig?.id ?? "default") + "-1");
PopoutManager.requestPopout(dankDashPopoutLoader.item, 1, (effectiveBarConfig?.id ?? "default") + "-" + section + "-1");
}
}
}
@@ -926,7 +926,7 @@ Item {
} else {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
}
PopoutManager.requestPopout(dankDashPopoutLoader.item, 3, (effectiveBarConfig?.id ?? "default") + "-3");
PopoutManager.requestPopout(dankDashPopoutLoader.item, 3, (effectiveBarConfig?.id ?? "default") + "-" + section + "-3");
}
}
}

View File

@@ -80,7 +80,7 @@ PanelWindow {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
}
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-2");
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-" + section + "-2");
}
readonly property var dBarLayer: {

View File

@@ -109,6 +109,13 @@ Item {
readonly property bool useBackgroundWindow: !CompositorService.isHyprland || CompositorService.useHyprlandFocusGrab
function updateSurfacePosition() {
if (useBackgroundWindow && shouldBeVisible) {
_surfaceMarginLeft = alignedX - shadowBuffer;
_surfaceW = alignedWidth + shadowBuffer * 2;
}
}
function open() {
if (!screen)
return;