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

Compare commits

...

12 Commits

Author SHA1 Message Date
bbedward
242ead722a screenshot: adjust cursor CLI option to be more explicit 2026-02-17 22:28:19 -05:00
bbedward
8a6d9696a8 settings: workaround crash 2026-02-17 22:20:01 -05:00
purian23
896b7ea242 notifications: Tweak animation scale & settings 2026-02-17 22:05:19 -05:00
bbedward
0c7f4c7828 settings: guard internal writes from watcher 2026-02-17 22:03:36 -05:00
bbedward
3d35af2a87 cc: fix plugin reloading in bar position changes 2026-02-17 17:24:22 -05:00
bbedward
fed3c36f84 popout: anchor height changing popout surfaces to top and bottom 2026-02-17 17:18:07 -05:00
bbedward
414d81aa40 workspaces: fix named workspace icons 2026-02-17 16:02:13 -05:00
bbedward
d548803769 dankinstall: no_anim on dms layers 2026-02-17 15:32:08 -05:00
bbedward
1180258394 system updater: fix hide no update option 2026-02-17 13:53:17 -05:00
bbedward
48a566a24b launcher: fix kb navigation not always showing last delegate in view 2026-02-17 13:07:43 -05:00
bbedward
3bc5d1df81 doctor: add qt6-imageformats check 2026-02-17 12:58:09 -05:00
bbedward
c7222e2e86 bump version, codename, disable changelog 2026-02-17 12:02:36 -05:00
27 changed files with 283 additions and 220 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")
keyPlugins := []struct{ file, format string }{
{"kimg_avif.so", "AVIF"},
{"kimg_heif.so", "HEIF"},
{"kimg_jxl.so", "JXL"},
{"kimg_exr.so", "EXR"},
}
var found []string
for _, p := range keyPlugins {
if _, err := os.Stat(filepath.Join(imageFormatsDir, p.file)); err == nil {
found = append(found, p.format)
} }
} }
if len(found) == 0 { imageFormatsDir := filepath.Join(pluginDir, "imageformats")
return checkResult{catOptionalFeatures, "kimageformats", statusWarn, "Not installed", desc, url}
type pluginCheck struct {
name string
desc string
plugins []struct{ file, format string }
} }
details := "" checks := []pluginCheck{
if doctorVerbose { {
details = fmt.Sprintf("Formats: %s (%s)", strings.Join(found, ", "), imageFormatsDir) 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_heif.so", "HEIF"},
{"kimg_jxl.so", "JXL"},
{"kimg_exr.so", "EXR"},
},
},
} }
return checkResult{catOptionalFeatures, "kimageformats", statusOK, fmt.Sprintf("Installed (%d formats)", len(found)), details, url} var results []checkResult
for _, c := range checks {
var found []string
for _, p := range c.plugins {
if _, err := os.Stat(filepath.Join(imageFormatsDir, p.file)); err == nil {
found = append(found, p.format)
}
}
var result checkResult
switch {
case len(found) == 0:
result = checkResult{catOptionalFeatures, c.name, statusWarn, "Not installed", c.desc, url}
default:
details := ""
if doctorVerbose {
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 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

@@ -13,16 +13,16 @@ import (
) )
var ( var (
ssOutputName string ssOutputName string
ssIncludeCursor bool ssCursor string
ssFormat string ssFormat string
ssQuality int ssQuality int
ssOutputDir string ssOutputDir string
ssFilename string ssFilename string
ssNoClipboard bool ssNoClipboard bool
ssNoFile bool ssNoFile bool
ssNoNotify bool ssNoNotify bool
ssStdout bool ssStdout bool
) )
var screenshotCmd = &cobra.Command{ var screenshotCmd = &cobra.Command{
@@ -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

@@ -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"`
@@ -42,29 +49,29 @@ 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
Filename string Filename string
Clipboard bool Clipboard bool
SaveFile bool SaveFile bool
Notify bool Notify bool
Stdout bool Stdout bool
} }
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: "",
Filename: "", Filename: "",
Clipboard: true, Clipboard: true,
SaveFile: true, SaveFile: true,
Notify: true, Notify: true,
} }
} }

View File

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

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;
var rowY = _cumulativeHeights[rowIndex]; mainListView.positionViewAtIndex(rowIndex, ListView.Contain);
var rowHeight = row.height;
var scrollY = mainListView.contentY - mainListView.originY;
var viewHeight = mainListView.height;
var headerH = stickyHeader.height;
if (rowY < scrollY + headerH) { if (stickyHeader.visible && rowIndex < _cumulativeHeights.length) {
mainListView.contentY = Math.max(mainListView.originY, rowY - headerH + mainListView.originY); var rowY = _cumulativeHeights[rowIndex];
return; var scrollY = mainListView.contentY - mainListView.originY;
} if (rowY < scrollY + stickyHeader.height) {
if (rowY + rowHeight > scrollY + viewHeight) { mainListView.contentY = Math.max(mainListView.originY, rowY - stickyHeader.height + mainListView.originY);
mainListView.contentY = rowY + rowHeight - viewHeight + mainListView.originY; }
} }
} }

View File

@@ -945,22 +945,31 @@ Column {
} }
} }
Component.onCompleted: { function tryCreatePluginInstance() {
Qt.callLater(() => { const pluginComponent = PluginService.pluginWidgetComponents[pluginId];
const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; if (!pluginComponent)
if (pluginComponent) { return false;
const instance = pluginComponent.createObject(null, { try {
"pluginId": pluginId, const instance = pluginComponent.createObject(null, {
"pluginService": PluginService, "pluginId": pluginId,
"visible": false, "pluginService": PluginService,
"width": 0, "visible": false,
"height": 0 "width": 0,
}); "height": 0
if (instance) { });
pluginInstance = instance; if (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

@@ -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

@@ -814,7 +814,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 +824,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

@@ -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

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

View File

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

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