1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Marcus Ramberg
0df47d2ce3 core: add dynamic completion for more commands (#889) 2025-12-02 18:35:51 -05:00
purian23
e24b548b54 fix: dms-cli & about versioning in all builds 2025-12-02 18:12:13 -05:00
Lucas
75af444cee niri: add option to disable overview launcher (#887) 2025-12-02 18:04:04 -05:00
bbedward
02dd19962f matugen: backup and add to vscode extensions json when present 2025-12-02 17:32:48 -05:00
purian23
f552b8ef7b Update Debian version format 2025-12-02 16:51:58 -05:00
Marcus Ramberg
9162e31489 core: add dynamic completion for ipc command (#885) 2025-12-02 15:51:26 -05:00
bbedward
01b28e3ee8 spotlight: optimize to keep loaded 2025-12-02 15:01:23 -05:00
bbedward
f5aa855125 network: eth device speed is not exposed 2025-12-02 14:45:28 -05:00
Guilherme Pagano
db3610fcdb feat: add support for geometric centering (#856)
Introduces a configurable centering mode.
- Adds 'geometric' option.
- Retains 'index' as the default value to preserve existing behavior.
2025-12-02 14:43:51 -05:00
bbedward
2e3f330058 theme: uncomment niri alt-tab colors 2025-12-02 14:41:09 -05:00
Marcus Ramberg
1617a7f2c1 dankbar: allow disabling title scrolling in the music display (#882) 2025-12-02 13:39:19 -05:00
25 changed files with 517 additions and 66 deletions

View File

@@ -171,7 +171,52 @@ jobs:
DATE_STR=$(date "+%a %b %d %Y") DATE_STR=$(date "+%a %b %d %Y")
CHANGELOG_ENTRY="* $DATE_STR Avenge Media <AvengeMedia.US@gmail.com> - ${NEW_VERSION}-1\n- Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)" CHANGELOG_ENTRY="* $DATE_STR Avenge Media <AvengeMedia.US@gmail.com> - ${NEW_VERSION}-1\n- Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)"
sed -i "/%changelog/a\\$CHANGELOG_ENTRY" distro/opensuse/dms-git.spec sed -i "/%changelog/a\\$CHANGELOG_ENTRY" distro/opensuse/dms-git.spec
- name: Update Debian dms-git changelog version
if: contains(steps.packages.outputs.packages, 'dms-git') || steps.packages.outputs.packages == 'all'
run: |
# Get commit info for dms-git versioning
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD)
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2")
# Debian version format: 0.6.2+git2256.9162e314
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
echo "📦 Updating Debian dms-git changelog to version: $NEW_VERSION"
CHANGELOG_DATE=$(date -R)
CHANGELOG_FILE="distro/debian/dms-git/debian/changelog"
# Get current version from changelog
CURRENT_VERSION=$(head -1 "$CHANGELOG_FILE" | sed 's/.*(\([^)]*\)).*/\1/')
echo "Current Debian version: $CURRENT_VERSION"
echo "New version: $NEW_VERSION"
# Only update if version changed
if [ "$CURRENT_VERSION" != "$NEW_VERSION" ]; then
# Create new changelog entry at top
TEMP_CHANGELOG=$(mktemp)
cat > "$TEMP_CHANGELOG" << EOF
dms-git ($NEW_VERSION) nightly; urgency=medium
* Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)
-- Avenge Media <AvengeMedia.US@gmail.com> $CHANGELOG_DATE
EOF
# Prepend to existing changelog
cat "$CHANGELOG_FILE" >> "$TEMP_CHANGELOG"
mv "$TEMP_CHANGELOG" "$CHANGELOG_FILE"
echo "✓ Updated Debian changelog: $CURRENT_VERSION → $NEW_VERSION"
else
echo "✓ Debian changelog already at version $NEW_VERSION"
fi
- name: Update dms stable version - name: Update dms stable version
if: steps.packages.outputs.version != '' if: steps.packages.outputs.version != ''
run: | run: |

View File

@@ -43,6 +43,7 @@ install-shell:
@mkdir -p $(SHELL_INSTALL_DIR) @mkdir -p $(SHELL_INSTALL_DIR)
@cp -r $(SHELL_DIR)/* $(SHELL_INSTALL_DIR)/ @cp -r $(SHELL_DIR)/* $(SHELL_INSTALL_DIR)/
@rm -rf $(SHELL_INSTALL_DIR)/.git* $(SHELL_INSTALL_DIR)/.github @rm -rf $(SHELL_INSTALL_DIR)/.git* $(SHELL_INSTALL_DIR)/.github
@$(MAKE) --no-print-directory -C $(CORE_DIR) print-version > $(SHELL_INSTALL_DIR)/VERSION
@echo "Shell files installed" @echo "Shell files installed"
install-completions: install-completions:
@@ -80,8 +81,7 @@ install: build install-bin install-shell install-completions install-systemd ins
@echo "" @echo ""
@echo "Installation complete!" @echo "Installation complete!"
@echo "" @echo ""
@echo "To enable and start DMS:" @echo "=== The DMS Team! ==="
@echo " systemctl --user enable --now dms"
# Uninstallation targets # Uninstallation targets
uninstall-bin: uninstall-bin:

View File

@@ -10,16 +10,19 @@ GO=go
GOFLAGS=-ldflags="-s -w" GOFLAGS=-ldflags="-s -w"
# Version and build info # Version and build info
VERSION=$(shell git describe --tags --always 2>/dev/null || echo "dev") BASE_VERSION=$(shell git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.0.0")
BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S') COMMIT_COUNT=$(shell git rev-list --count HEAD 2>/dev/null || echo "0")
COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") COMMIT_HASH=$(shell git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown")
VERSION?=$(BASE_VERSION)+git$(COMMIT_COUNT).$(COMMIT_HASH)
BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
COMMIT?=$(COMMIT_HASH)
BUILD_LDFLAGS=-ldflags='-s -w -X main.Version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.commit=$(COMMIT)' BUILD_LDFLAGS=-ldflags='-s -w -X main.Version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.commit=$(COMMIT)'
# Architecture to build for dist target (amd64, arm64, or all) # Architecture to build for dist target (amd64, arm64, or all)
ARCH ?= all ARCH ?= all
.PHONY: all build dankinstall dist clean install install-all install-dankinstall uninstall uninstall-all uninstall-dankinstall install-config uninstall-config test fmt vet deps help .PHONY: all build dankinstall dist clean install install-all install-dankinstall uninstall uninstall-all uninstall-dankinstall install-config uninstall-config test fmt vet deps print-version help
# Default target # Default target
all: build all: build
@@ -132,6 +135,9 @@ version: check-go
@echo "Build Time: $(BUILD_TIME)" @echo "Build Time: $(BUILD_TIME)"
@echo "Commit: $(COMMIT)" @echo "Commit: $(COMMIT)"
print-version:
@echo "$(VERSION)"
help: help:
@echo "Available targets:" @echo "Available targets:"
@echo " all - Build the main binary (dms) (default)" @echo " all - Build the main binary (dms) (default)"

View File

@@ -28,7 +28,14 @@ var brightnessSetCmd = &cobra.Command{
Short: "Set brightness for a device", Short: "Set brightness for a device",
Long: "Set brightness percentage (0-100) for a specific device", Long: "Set brightness percentage (0-100) for a specific device",
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
Run: runBrightnessSet, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
includeDDC, _ := cmd.Flags().GetBool("ddc")
return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp
},
Run: runBrightnessSet,
} }
var brightnessGetCmd = &cobra.Command{ var brightnessGetCmd = &cobra.Command{
@@ -36,7 +43,14 @@ var brightnessGetCmd = &cobra.Command{
Short: "Get brightness for a device", Short: "Get brightness for a device",
Long: "Get current brightness percentage for a specific device", Long: "Get current brightness percentage for a specific device",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: runBrightnessGet, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
includeDDC, _ := cmd.Flags().GetBool("ddc")
return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp
},
Run: runBrightnessGet,
} }
func init() { func init() {
@@ -105,9 +119,7 @@ Global Flags:
brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd) brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd)
} }
func runBrightnessList(cmd *cobra.Command, args []string) { func getAllBrightnessDevices(includeDDC bool) []brightness.Device {
includeDDC, _ := cmd.Flags().GetBool("ddc")
allDevices := []brightness.Device{} allDevices := []brightness.Device{}
sysfs, err := brightness.NewSysfsBackend() sysfs, err := brightness.NewSysfsBackend()
@@ -138,6 +150,13 @@ func runBrightnessList(cmd *cobra.Command, args []string) {
} }
} }
return allDevices
}
func runBrightnessList(cmd *cobra.Command, args []string) {
includeDDC, _ := cmd.Flags().GetBool("ddc")
allDevices := getAllBrightnessDevices(includeDDC)
if len(allDevices) == 0 { if len(allDevices) == 0 {
fmt.Println("No brightness devices found") fmt.Println("No brightness devices found")
return return
@@ -261,31 +280,20 @@ func runBrightnessSet(cmd *cobra.Command, args []string) {
log.Fatalf("Failed to set brightness for device: %s", deviceID) log.Fatalf("Failed to set brightness for device: %s", deviceID)
} }
func getBrightnessDevices(includeDDC bool) []string {
allDevices := getAllBrightnessDevices(includeDDC)
var deviceIDs []string
for _, device := range allDevices {
deviceIDs = append(deviceIDs, device.ID)
}
return deviceIDs
}
func runBrightnessGet(cmd *cobra.Command, args []string) { func runBrightnessGet(cmd *cobra.Command, args []string) {
deviceID := args[0] deviceID := args[0]
includeDDC, _ := cmd.Flags().GetBool("ddc") includeDDC, _ := cmd.Flags().GetBool("ddc")
allDevices := getAllBrightnessDevices(includeDDC)
allDevices := []brightness.Device{}
sysfs, err := brightness.NewSysfsBackend()
if err == nil {
devices, err := sysfs.GetDevices()
if err == nil {
allDevices = append(allDevices, devices...)
}
}
if includeDDC {
ddc, err := brightness.NewDDCBackend()
if err == nil {
defer ddc.Close()
time.Sleep(100 * time.Millisecond)
devices, err := ddc.GetDevices()
if err == nil {
allDevices = append(allDevices, devices...)
}
}
}
for _, device := range allDevices { for _, device := range allDevices {
if device.ID == deviceID { if device.ID == deviceID {

View File

@@ -66,6 +66,10 @@ var ipcCmd = &cobra.Command{
Short: "Send IPC commands to running DMS shell", Short: "Send IPC commands to running DMS shell",
Long: "Send IPC commands to running DMS shell (qs -c dms ipc <args>)", Long: "Send IPC commands to running DMS shell (qs -c dms ipc <args>)",
PreRunE: findConfig, PreRunE: findConfig,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
_ = findConfig(cmd, args)
return getShellIPCCompletions(args, toComplete), cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
runShellIPCCommand(args) runShellIPCCommand(args)
}, },
@@ -115,6 +119,12 @@ var pluginsInstallCmd = &cobra.Command{
Short: "Install a plugin by ID", Short: "Install a plugin by ID",
Long: "Install a DMS plugin from the registry using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.", Long: "Install a DMS plugin from the registry using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getAvailablePluginIDs(), cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if err := installPluginCLI(args[0]); err != nil { if err := installPluginCLI(args[0]); err != nil {
log.Fatalf("Error installing plugin: %v", err) log.Fatalf("Error installing plugin: %v", err)
@@ -127,6 +137,12 @@ var pluginsUninstallCmd = &cobra.Command{
Short: "Uninstall a plugin by ID", Short: "Uninstall a plugin by ID",
Long: "Uninstall a DMS plugin using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.", Long: "Uninstall a DMS plugin using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getInstalledPluginIDs(), cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if err := uninstallPluginCLI(args[0]); err != nil { if err := uninstallPluginCLI(args[0]); err != nil {
log.Fatalf("Error uninstalling plugin: %v", err) log.Fatalf("Error uninstalling plugin: %v", err)
@@ -299,6 +315,38 @@ func installPluginCLI(idOrName string) error {
return nil return nil
} }
func getAvailablePluginIDs() []string {
registry, err := plugins.NewRegistry()
if err != nil {
return nil
}
pluginList, err := registry.List()
if err != nil {
return nil
}
var ids []string
for _, p := range pluginList {
ids = append(ids, p.ID)
}
return ids
}
func getInstalledPluginIDs() []string {
manager, err := plugins.NewManager()
if err != nil {
return nil
}
installed, err := manager.ListInstalled()
if err != nil {
return nil
}
return installed
}
func uninstallPluginCLI(idOrName string) error { func uninstallPluginCLI(idOrName string) error {
manager, err := plugins.NewManager() manager, err := plugins.NewManager()
if err != nil { if err != nil {

View File

@@ -27,6 +27,9 @@ func init() {
dank16Cmd.Flags().Bool("wezterm", false, "Output in Wezterm terminal format") dank16Cmd.Flags().Bool("wezterm", false, "Output in Wezterm terminal format")
dank16Cmd.Flags().String("background", "", "Custom background color") dank16Cmd.Flags().String("background", "", "Custom background color")
dank16Cmd.Flags().String("contrast", "dps", "Contrast algorithm: dps (Delta Phi Star, default) or wcag") dank16Cmd.Flags().String("contrast", "dps", "Contrast algorithm: dps (Delta Phi Star, default) or wcag")
_ = dank16Cmd.RegisterFlagCompletionFunc("contrast", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"dps", "wcag"}, cobra.ShellCompDirectiveNoFileComp
})
} }
func runDank16(cmd *cobra.Command, args []string) { func runDank16(cmd *cobra.Command, args []string) {

View File

@@ -16,14 +16,26 @@ var dpmsOnCmd = &cobra.Command{
Use: "on [output]", Use: "on [output]",
Short: "Turn display(s) on", Short: "Turn display(s) on",
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: runDPMSOn, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getDPMSOutputs(), cobra.ShellCompDirectiveNoFileComp
},
Run: runDPMSOn,
} }
var dpmsOffCmd = &cobra.Command{ var dpmsOffCmd = &cobra.Command{
Use: "off [output]", Use: "off [output]",
Short: "Turn display(s) off", Short: "Turn display(s) off",
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: runDPMSOff, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getDPMSOutputs(), cobra.ShellCompDirectiveNoFileComp
},
Run: runDPMSOff,
} }
var dpmsListCmd = &cobra.Command{ var dpmsListCmd = &cobra.Command{
@@ -71,6 +83,15 @@ func runDPMSOff(cmd *cobra.Command, args []string) {
} }
} }
func getDPMSOutputs() []string {
client, err := newDPMSClient()
if err != nil {
return nil
}
defer client.Close()
return client.ListOutputs()
}
func runDPMSList(cmd *cobra.Command, args []string) { func runDPMSList(cmd *cobra.Command, args []string) {
client, err := newDPMSClient() client, err := newDPMSClient()
if err != nil { if err != nil {

View File

@@ -30,7 +30,14 @@ var keybindsShowCmd = &cobra.Command{
Short: "Show keybinds for a provider", Short: "Show keybinds for a provider",
Long: "Display keybinds/cheatsheet for the specified provider", Long: "Display keybinds/cheatsheet for the specified provider",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: runKeybindsShow, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
registry := keybinds.GetDefaultRegistry()
return registry.List(), cobra.ShellCompDirectiveNoFileComp
},
Run: runKeybindsShow,
} }
func init() { func init() {

View File

@@ -45,6 +45,9 @@ func init() {
openCmd.Flags().StringVar(&openMimeType, "mime", "", "MIME type for filtering applications") openCmd.Flags().StringVar(&openMimeType, "mime", "", "MIME type for filtering applications")
openCmd.Flags().StringSliceVar(&openCategories, "category", []string{}, "Application categories to filter (e.g., WebBrowser, Office, Graphics)") openCmd.Flags().StringSliceVar(&openCategories, "category", []string{}, "Application categories to filter (e.g., WebBrowser, Office, Graphics)")
openCmd.Flags().StringVar(&openRequestType, "type", "url", "Request type (url, file, or custom)") openCmd.Flags().StringVar(&openRequestType, "type", "url", "Request type (url, file, or custom)")
_ = openCmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"url", "file", "custom"}, cobra.ShellCompDirectiveNoFileComp
})
} }
// mimeTypeToCategories maps MIME types to desktop file categories // mimeTypeToCategories maps MIME types to desktop file categories

View File

@@ -16,6 +16,8 @@ import (
"github.com/AvengeMedia/DankMaterialShell/core/internal/server" "github.com/AvengeMedia/DankMaterialShell/core/internal/server"
) )
type ipcTargets map[string][]string
var isSessionManaged bool var isSessionManaged bool
func execDetachedRestart(targetPID int) { func execDetachedRestart(targetPID int) {
@@ -68,7 +70,7 @@ func getPIDFilePath() string {
func writePIDFile(childPID int) error { func writePIDFile(childPID int) error {
pidFile := getPIDFilePath() pidFile := getPIDFilePath()
return os.WriteFile(pidFile, []byte(strconv.Itoa(childPID)), 0644) return os.WriteFile(pidFile, []byte(strconv.Itoa(childPID)), 0o644)
} }
func removePIDFile() { func removePIDFile() {
@@ -144,7 +146,7 @@ func runShellInteractive(session bool) {
socketPath := server.GetSocketPath() socketPath := server.GetSocketPath()
configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path") configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
if err := os.WriteFile(configStateFile, []byte(configPath), 0644); err != nil { if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil {
log.Warnf("Failed to write config state file: %v", err) log.Warnf("Failed to write config state file: %v", err)
} }
defer os.Remove(configStateFile) defer os.Remove(configStateFile)
@@ -370,7 +372,7 @@ func runShellDaemon(session bool) {
socketPath := server.GetSocketPath() socketPath := server.GetSocketPath()
configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path") configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
if err := os.WriteFile(configStateFile, []byte(configPath), 0644); err != nil { if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil {
log.Warnf("Failed to write config state file: %v", err) log.Warnf("Failed to write config state file: %v", err)
} }
defer os.Remove(configStateFile) defer os.Remove(configStateFile)
@@ -473,6 +475,51 @@ func runShellDaemon(session bool) {
} }
} }
func parseTargetsFromIPCShowOutput(output string) ipcTargets {
targets := map[string][]string{}
var currentTarget string
for _, line := range strings.Split(output, "\n") {
if strings.HasPrefix(line, "target ") {
currentTarget = strings.TrimSpace(strings.TrimPrefix(line, "target "))
}
if strings.HasPrefix(line, " function") && currentTarget != "" {
currentFunc := strings.TrimPrefix(line, " function ")
currentFunc = strings.SplitN(currentFunc, "(", 2)[0]
targets[currentTarget] = append(targets[currentTarget], currentFunc)
}
}
return targets
}
func getShellIPCCompletions(args []string, toComplete string) []string {
cmdArgs := []string{"-p", configPath, "ipc", "show"}
cmd := exec.Command("qs", cmdArgs...)
var targets ipcTargets
if output, err := cmd.Output(); err == nil {
log.Debugf("IPC show output: %s", string(output))
targets = parseTargetsFromIPCShowOutput(string(output))
} else {
log.Debugf("Error getting IPC show output for completions: %v", err)
return nil
}
if len(args) > 0 && args[0] == "call" {
args = args[1:]
}
if len(args) == 0 {
targetNames := make([]string, 0)
targetNames = append(targetNames, "call")
for k := range targets {
targetNames = append(targetNames, k)
}
return targetNames
}
return targets[args[0]]
}
func runShellIPCCommand(args []string) { func runShellIPCCommand(args []string) {
if len(args) == 0 { if len(args) == 0 {
log.Error("IPC command requires arguments") log.Error("IPC command requires arguments")

View File

@@ -169,6 +169,7 @@ fi
CHANGELOG_VERSION="" CHANGELOG_VERSION=""
if [[ -d "distro/debian/$PACKAGE/debian" ]]; then if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
# Format: 0.6.2+git{COMMIT_COUNT}.{COMMIT_HASH} (e.g., 0.6.2+git2256.9162e314)
CHANGELOG_VERSION=$(grep -m1 "^$PACKAGE" "distro/debian/$PACKAGE/debian/changelog" 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "") CHANGELOG_VERSION=$(grep -m1 "^$PACKAGE" "distro/debian/$PACKAGE/debian/changelog" 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "")
if [[ -n "$CHANGELOG_VERSION" ]] && [[ "$CHANGELOG_VERSION" == *"-"* ]]; then if [[ -n "$CHANGELOG_VERSION" ]] && [[ "$CHANGELOG_VERSION" == *"-"* ]]; then
SOURCE_FORMAT_CHECK=$(cat "distro/debian/$PACKAGE/debian/source/format" 2>/dev/null || echo "3.0 (quilt)") SOURCE_FORMAT_CHECK=$(cat "distro/debian/$PACKAGE/debian/source/format" 2>/dev/null || echo "3.0 (quilt)")

View File

@@ -14,8 +14,31 @@ Singleton {
property var activeModal: null property var activeModal: null
property bool windowsVisible: false property bool windowsVisible: false
property var targetScreen: null property var targetScreen: null
property var persistentModal: null
readonly property bool hasActiveModal: activeModal !== null readonly property bool hasActiveModal: activeModal !== null
readonly property bool hasPersistentModal: persistentModal !== null
readonly property bool isPersistentModalActive: hasActiveModal && activeModal === persistentModal
readonly property bool shouldShowModal: hasActiveModal readonly property bool shouldShowModal: hasActiveModal
readonly property bool shouldKeepWindowsAlive: hasPersistentModal
onPersistentModalChanged: {
if (!persistentModal)
return;
cachedModal = persistentModal;
cachedModalWidth = Theme.px(persistentModal.modalWidth, dpr);
cachedModalHeight = Theme.px(persistentModal.modalHeight, dpr);
cachedModalX = calculateX(persistentModal);
cachedModalY = calculateY(persistentModal);
cachedAnimationDuration = persistentModal.animationDuration ?? Theme.shortDuration;
cachedEnterCurve = persistentModal.animationEnterCurve ?? Theme.expressiveCurves.expressiveFastSpatial;
cachedExitCurve = persistentModal.animationExitCurve ?? Theme.expressiveCurves.expressiveFastSpatial;
cachedScaleCollapsed = persistentModal.animationScaleCollapsed ?? 0.96;
if (persistentModal.directContent) {
persistentModal.directContent.parent = directContentWrapper;
persistentModal.directContent.anchors.fill = directContentWrapper;
}
}
readonly property var screen: backgroundWindow.screen readonly property var screen: backgroundWindow.screen
readonly property real dpr: screen ? CompositorService.getScreenScale(screen) : 1 readonly property real dpr: screen ? CompositorService.getScreenScale(screen) : 1
readonly property real shadowBuffer: 5 readonly property real shadowBuffer: 5
@@ -161,7 +184,7 @@ Singleton {
PanelWindow { PanelWindow {
id: backgroundWindow id: backgroundWindow
visible: root.windowsVisible visible: root.windowsVisible || root.shouldKeepWindowsAlive
screen: root.targetScreen screen: root.targetScreen
color: "transparent" color: "transparent"
@@ -223,7 +246,7 @@ Singleton {
PanelWindow { PanelWindow {
id: contentWindow id: contentWindow
visible: root.windowsVisible visible: root.windowsVisible || root.shouldKeepWindowsAlive
screen: root.targetScreen screen: root.targetScreen
color: "transparent" color: "transparent"

View File

@@ -168,12 +168,14 @@ Singleton {
property bool dwlShowAllTags: false property bool dwlShowAllTags: false
property var workspaceNameIcons: ({}) property var workspaceNameIcons: ({})
property bool waveProgressEnabled: true property bool waveProgressEnabled: true
property bool scrollTitleEnabled: true
property bool clockCompactMode: false property bool clockCompactMode: false
property bool focusedWindowCompactMode: false property bool focusedWindowCompactMode: false
property bool runningAppsCompactMode: true property bool runningAppsCompactMode: true
property bool keyboardLayoutNameCompactMode: false property bool keyboardLayoutNameCompactMode: false
property bool runningAppsCurrentWorkspace: false property bool runningAppsCurrentWorkspace: false
property bool runningAppsGroupByApp: false property bool runningAppsGroupByApp: false
property string centeringMode: "index"
property string clockDateFormat: "" property string clockDateFormat: ""
property string lockDateFormat: "" property string lockDateFormat: ""
property int mediaSize: 1 property int mediaSize: 1
@@ -185,6 +187,7 @@ Singleton {
property bool sortAppsAlphabetically: false property bool sortAppsAlphabetically: false
property int appLauncherGridColumns: 4 property int appLauncherGridColumns: 4
property bool spotlightCloseNiriOverview: true property bool spotlightCloseNiriOverview: true
property bool niriOverviewOverlayEnabled: true
property string weatherLocation: "New York, NY" property string weatherLocation: "New York, NY"
property string weatherCoordinates: "40.7128,-74.0060" property string weatherCoordinates: "40.7128,-74.0060"
@@ -226,6 +229,7 @@ Singleton {
onNotepadFontFamilyChanged: saveSettings() onNotepadFontFamilyChanged: saveSettings()
onNotepadFontSizeChanged: saveSettings() onNotepadFontSizeChanged: saveSettings()
onNotepadShowLineNumbersChanged: saveSettings() onNotepadShowLineNumbersChanged: saveSettings()
// onCenteringModeChanged: saveSettings()
onNotepadTransparencyOverrideChanged: { onNotepadTransparencyOverrideChanged: {
if (notepadTransparencyOverride > 0) { if (notepadTransparencyOverride > 0) {
notepadLastCustomTransparency = notepadTransparencyOverride; notepadLastCustomTransparency = notepadTransparencyOverride;

View File

@@ -83,12 +83,14 @@ var SPEC = {
dwlShowAllTags: { def: false }, dwlShowAllTags: { def: false },
workspaceNameIcons: { def: {} }, workspaceNameIcons: { def: {} },
waveProgressEnabled: { def: true }, waveProgressEnabled: { def: true },
scrollTitleEnabled: {def: true},
clockCompactMode: { def: false }, clockCompactMode: { def: false },
focusedWindowCompactMode: { def: false }, focusedWindowCompactMode: { def: false },
runningAppsCompactMode: { def: true }, runningAppsCompactMode: { def: true },
keyboardLayoutNameCompactMode: { def: false }, keyboardLayoutNameCompactMode: { def: false },
runningAppsCurrentWorkspace: { def: false }, runningAppsCurrentWorkspace: { def: false },
runningAppsGroupByApp: { def: false }, runningAppsGroupByApp: { def: false },
centeringMode: { def: "index" },
clockDateFormat: { def: "" }, clockDateFormat: { def: "" },
lockDateFormat: { def: "" }, lockDateFormat: { def: "" },
mediaSize: { def: 1 }, mediaSize: { def: 1 },
@@ -98,6 +100,7 @@ var SPEC = {
sortAppsAlphabetically: { def: false }, sortAppsAlphabetically: { def: false },
appLauncherGridColumns: { def: 4 }, appLauncherGridColumns: { def: 4 },
spotlightCloseNiriOverview: { def: true }, spotlightCloseNiriOverview: { def: true },
niriOverviewOverlayEnabled: { def: true },
weatherLocation: { def: "New York, NY" }, weatherLocation: { def: "New York, NY" },
weatherCoordinates: { def: "40.7128,-74.0060" }, weatherCoordinates: { def: "40.7128,-74.0060" },

View File

@@ -712,7 +712,7 @@ Item {
LazyLoader { LazyLoader {
id: niriOverviewOverlayLoader id: niriOverviewOverlayLoader
active: CompositorService.isNiri active: CompositorService.isNiri && SettingsData.niriOverviewOverlayEnabled
component: NiriOverviewOverlay { component: NiriOverviewOverlay {
id: niriOverviewOverlay id: niriOverviewOverlay
} }

View File

@@ -130,6 +130,10 @@ DankModal {
target: "spotlight" target: "spotlight"
} }
Component.onCompleted: {
DankModalWindow.persistentModal = spotlightModal;
}
SpotlightContent { SpotlightContent {
id: spotlightContentInstance id: spotlightContentInstance

View File

@@ -30,6 +30,64 @@ Item {
property real totalSize: 0 property real totalSize: 0
function updateLayout() { function updateLayout() {
if (SettingsData.centeringMode === "geometric") {
applyGeometricLayout();
} else {
// Default to index layout or if value is not 'geometric'
applyIndexLayout();
}
}
function applyGeometricLayout() {
if ((isVertical ? height : width) <= 0 || !visible) {
return;
}
centerWidgets = [];
totalWidgets = 0;
totalSize = 0;
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i);
if (item && item.active && item.item && getWidgetVisible(item.widgetId)) {
centerWidgets.push(item.item);
totalWidgets++;
totalSize += isVertical ? item.item.height : item.item.width;
}
}
if (totalWidgets === 0) {
return;
}
if (totalWidgets > 1) {
totalSize += spacing * (totalWidgets - 1);
}
positionWidgetsGeometric();
}
function positionWidgetsGeometric() {
const parentLength = isVertical ? height : width;
const parentCenter = parentLength / 2;
let currentPos = parentCenter - (totalSize / 2);
centerWidgets.forEach(widget => {
if (isVertical) {
widget.anchors.verticalCenter = undefined;
widget.y = currentPos;
} else {
widget.anchors.horizontalCenter = undefined;
widget.x = currentPos;
}
const widgetSize = isVertical ? widget.height : widget.width;
currentPos += widgetSize + spacing;
});
}
function applyIndexLayout() {
if ((isVertical ? height : width) <= 0 || !visible) { if ((isVertical ? height : width) <= 0 || !visible) {
return; return;
} }
@@ -85,10 +143,10 @@ Item {
totalSize += spacing * (totalWidgets - 1); totalSize += spacing * (totalWidgets - 1);
} }
positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget); positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
} }
function positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) { function positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) {
const parentCenter = (isVertical ? height : width) / 2; const parentCenter = (isVertical ? height : width) / 2;
const isOddConfigured = configuredWidgets % 2 === 1; const isOddConfigured = configuredWidgets % 2 === 1;
@@ -508,4 +566,11 @@ Item {
} }
} }
} }
Connections {
target: SettingsData
function onCenteringModeChanged() {
layoutTimer.restart();
}
}
} }

View File

@@ -232,7 +232,7 @@ BasePill {
StyledText { StyledText {
id: mediaText id: mediaText
property bool needsScrolling: implicitWidth > textContainer.width property bool needsScrolling: implicitWidth > textContainer.width && SettingsData.scrollTitleEnabled
property real scrollOffset: 0 property real scrollOffset: 0
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View File

@@ -162,7 +162,19 @@ Item {
} }
StyledText { StyledText {
text: SystemUpdateService.shellVersion ? `dms ${SystemUpdateService.shellVersion}` : "dms" text: {
if (!SystemUpdateService.shellVersion) return "dms";
// Git versioning to show ex: "dms v0.6.2-2223"
let version = SystemUpdateService.shellVersion;
let match = version.match(/^([\d.]+)\+git(\d+)\./);
if (match) {
return `dms v${match[1]}-${match[2]}`;
}
return `dms ${version}`;
}
font.pixelSize: Theme.fontSizeXLarge font.pixelSize: Theme.fontSizeXLarge
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText

View File

@@ -655,6 +655,69 @@ Item {
} }
} }
StyledRect {
width: parent.width
height: niriOverlayEnabledSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 0
visible: CompositorService.isNiri
Column {
id: niriOverlayEnabledSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "layers"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Enable Overview Overlay")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - parent.children[0].width - parent.children[1].width - niriOverlayToggle.width - Theme.spacingM * 3
height: 1
}
DankToggle {
id: niriOverlayToggle
width: 32
height: 18
checked: SettingsData.niriOverviewOverlayEnabled
anchors.verticalCenter: parent.verticalCenter
onToggled: checked => {
SettingsData.set("niriOverviewOverlayEnabled", checked);
}
}
}
StyledText {
width: parent.width
text: I18n.tr("When enabled, shows the launcher overlay when typing in Niri overview mode. Disable this if you prefer to not have the launcher when typing on Niri overview or want to use other launcher in the overview.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
}
}
StyledRect { StyledRect {
width: parent.width width: parent.width
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2 height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2

View File

@@ -407,20 +407,6 @@ Item {
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
visible: modelData.ip && modelData.ip.length > 0 visible: modelData.ip && modelData.ip.length > 0
} }
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: modelData.speed && modelData.speed > 0
}
StyledText {
text: modelData.speed ? modelData.speed + " Mbps" : ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: modelData.speed && modelData.speed > 0
}
} }
} }
} }

View File

@@ -203,6 +203,15 @@ Item {
return SettingsData.set("waveProgressEnabled", checked); return SettingsData.set("waveProgressEnabled", checked);
} }
} }
DankToggle {
width: parent.width
text: I18n.tr("Scroll song title")
description: I18n.tr("Scroll title if it doesn't fit in widget")
checked: SettingsData.scrollTitleEnabled
onToggled: checked => {
return SettingsData.set("scrollTitleEnabled", checked);
}
}
} }
} }

View File

@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts
import qs.Common import qs.Common
import qs.Widgets import qs.Widgets
import qs.Services import qs.Services
@@ -34,7 +35,7 @@ Column {
height: implicitHeight height: implicitHeight
spacing: Theme.spacingM spacing: Theme.spacingM
Row { RowLayout {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -42,7 +43,7 @@ Column {
name: root.titleIcon name: root.titleIcon
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter Layout.alignment: Qt.AlignVCenter
} }
StyledText { StyledText {
@@ -50,12 +51,54 @@ Column {
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter Layout.alignment: Qt.AlignVCenter
} }
Item { Item {
width: parent.width - 60
height: 1 height: 1
Layout.fillWidth: true
}
RowLayout {
spacing: Theme.spacingXS
Layout.alignment: Qt.AlignVCenter
visible: root.sectionId === "center"
DankActionButton {
id: indexCenterButton
buttonSize: 28
iconName: "format_list_numbered"
iconSize: 16
iconColor: SettingsData.centeringMode === "index" ? Theme.primary : Theme.outline
onClicked: {
console.log("Centering mode changed to: index");
SettingsData.set("centeringMode", "index");
}
onEntered: {
sharedTooltip.show("Index Centering", indexCenterButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
DankActionButton {
id: geometricCenterButton
buttonSize: 28
iconName: "center_focus_weak"
iconSize: 16
iconColor: SettingsData.centeringMode === "geometric" ? Theme.primary : Theme.outline
onClicked: {
console.log("Centering mode changed to: geometric");
SettingsData.set("centeringMode", "geometric");
}
onEntered: {
sharedTooltip.show("Geometric Centering", geometricCenterButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
} }
} }

View File

@@ -28,7 +28,7 @@ layout {
} }
} }
/-recent-windows { recent-windows {
highlight { highlight {
active-color "{{colors.primary_container.dark.hex}}" active-color "{{colors.primary_container.dark.hex}}"
urgent-color "{{colors.error.default.hex}}" urgent-color "{{colors.error.default.hex}}"

View File

@@ -175,6 +175,56 @@ setup_vscode_extension() {
mkdir -p "$theme_dir" mkdir -p "$theme_dir"
cp "$SHELL_DIR/matugen/templates/vscode-package.json" "$ext_dir/package.json" 2>/dev/null || true cp "$SHELL_DIR/matugen/templates/vscode-package.json" "$ext_dir/package.json" 2>/dev/null || true
cp "$SHELL_DIR/matugen/templates/vscode-vsixmanifest.xml" "$ext_dir/.vsixmanifest" 2>/dev/null || true cp "$SHELL_DIR/matugen/templates/vscode-vsixmanifest.xml" "$ext_dir/.vsixmanifest" 2>/dev/null || true
update_vscode_extensions_json "$config_dir/extensions" "$ext_dir"
}
update_vscode_extensions_json() {
local ext_list_dir="$1" ext_dir="$2"
local ext_json="$ext_list_dir/extensions.json"
[[ ! -f "$ext_json" ]] && return
grep -q "dynamic-base16-dankshell" "$ext_json" && return
cp "$ext_json" "$ext_json.bak"
local entry
entry=$(cat <<EOF
{
"identifier": {
"id": "local.dynamic-base16-dankshell",
"uuid": "00000000-0000-0000-0000-000000000000"
},
"version": "0.0.1",
"location": {
"\$mid": 1,
"path": "$ext_dir",
"scheme": "file"
},
"relativeLocation": "local.dynamic-base16-dankshell-0.0.1",
"metadata": {
"isApplicationScoped": false,
"isMachineScoped": false,
"isBuiltin": false,
"installedTimestamp": $(date +%s)000,
"pinned": false,
"source": "local",
"id": "00000000-0000-0000-0000-000000000000",
"publisherId": "local",
"publisherDisplayName": "Dank Linux",
"targetPlatform": "undefined",
"updated": true,
"private": false,
"isPreReleaseVersion": false,
"hasPreReleaseVersion": false,
"preRelease": false
}
}
EOF
)
local content
content=$(cat "$ext_json")
if [[ "$content" == "[]" ]]; then
echo "[$entry]" > "$ext_json"
else
echo "${content%]}, $entry]" > "$ext_json"
fi
} }
signal_terminals() { signal_terminals() {