summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
committerNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
commita2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 (patch)
tree1a8769217f84bfe9d6216fafaadaf8cdd876d457 /raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go
parent34b9c34f982b2596cfa9e368a2d7f74e9a17477c (diff)
downloadRaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.tar.gz
RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go739
1 files changed, 0 insertions, 739 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go
deleted file mode 100644
index 7ce2003..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/cmd/dms/shell.go
+++ /dev/null
@@ -1,739 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "os/signal"
- "path/filepath"
- "slices"
- "strconv"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server"
-)
-
-type ipcTargets map[string]map[string][]string
-
-// getProcessExitCode returns the exit code from a ProcessState.
-// For normal exits, returns the exit code directly.
-// For signal termination, returns 128 + signal number (Unix convention).
-func getProcessExitCode(state *os.ProcessState) int {
- if state == nil {
- return 1
- }
- if code := state.ExitCode(); code != -1 {
- return code
- }
- // Process was killed by signal - extract signal number
- if status, ok := state.Sys().(syscall.WaitStatus); ok {
- if status.Signaled() {
- return 128 + int(status.Signal())
- }
- }
- return 1
-}
-
-var isSessionManaged bool
-
-func execDetachedRestart(targetPID int) {
- selfPath, err := os.Executable()
- if err != nil {
- return
- }
-
- cmd := exec.Command(selfPath, "restart-detached", strconv.Itoa(targetPID))
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Setsid: true,
- }
- cmd.Start()
-}
-
-func runDetachedRestart(targetPIDStr string) {
- targetPID, err := strconv.Atoi(targetPIDStr)
- if err != nil {
- return
- }
-
- time.Sleep(200 * time.Millisecond)
-
- proc, err := os.FindProcess(targetPID)
- if err == nil {
- proc.Signal(syscall.SIGTERM)
- }
-
- time.Sleep(500 * time.Millisecond)
-
- killShell()
- runShellDaemon(false)
-}
-
-func getRuntimeDir() string {
- if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" {
- return runtime
- }
- return os.TempDir()
-}
-
-func hasSystemdRun() bool {
- _, err := exec.LookPath("systemd-run")
- return err == nil
-}
-
-func getPIDFilePath() string {
- return filepath.Join(getRuntimeDir(), fmt.Sprintf("danklinux-%d.pid", os.Getpid()))
-}
-
-func writePIDFile(childPID int) error {
- pidFile := getPIDFilePath()
- return os.WriteFile(pidFile, []byte(strconv.Itoa(childPID)), 0o644)
-}
-
-func removePIDFile() {
- pidFile := getPIDFilePath()
- os.Remove(pidFile)
-}
-
-func getAllDMSPIDs() []int {
- dir := getRuntimeDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return nil
- }
-
- var pids []int
-
- for _, entry := range entries {
- if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".pid") {
- continue
- }
-
- pidFile := filepath.Join(dir, entry.Name())
- data, err := os.ReadFile(pidFile)
- if err != nil {
- continue
- }
-
- childPID, err := strconv.Atoi(strings.TrimSpace(string(data)))
- if err != nil {
- os.Remove(pidFile)
- continue
- }
-
- proc, err := os.FindProcess(childPID)
- if err != nil {
- os.Remove(pidFile)
- continue
- }
-
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- os.Remove(pidFile)
- continue
- }
-
- pids = append(pids, childPID)
-
- parentPIDStr := strings.TrimPrefix(entry.Name(), "danklinux-")
- parentPIDStr = strings.TrimSuffix(parentPIDStr, ".pid")
- if parentPID, err := strconv.Atoi(parentPIDStr); err == nil {
- if parentProc, err := os.FindProcess(parentPID); err == nil {
- if err := parentProc.Signal(syscall.Signal(0)); err == nil {
- pids = append(pids, parentPID)
- }
- }
- }
- }
-
- return pids
-}
-
-func runShellInteractive(session bool) {
- isSessionManaged = session
- go printASCII()
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- socketPath := server.GetSocketPath()
-
- configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
- if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil {
- log.Warnf("Failed to write config state file: %v", err)
- }
- defer os.Remove(configStateFile)
-
- errChan := make(chan error, 2)
-
- go func() {
- defer func() {
- if r := recover(); r != nil {
- errChan <- fmt.Errorf("server panic: %v", r)
- }
- }()
- server.CLIVersion = Version
- if err := server.Start(false); err != nil {
- errChan <- fmt.Errorf("server error: %w", err)
- }
- }()
-
- log.Infof("Spawning quickshell with -p %s", configPath)
-
- cmd := exec.CommandContext(ctx, "qs", "-p", configPath)
- cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath)
- if os.Getenv("QT_LOGGING_RULES") == "" {
- if qtRules := log.GetQtLoggingRules(); qtRules != "" {
- cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules)
- }
- }
-
- // ! TODO - remove when QS 0.3 is up and we can use the pragma
- cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms")
-
- if isSessionManaged && hasSystemdRun() {
- cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope")
- }
-
- homeDir, err := os.UserHomeDir()
- if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" {
- if !strings.HasPrefix(configPath, homeDir) {
- cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1")
- }
- }
-
- if os.Getenv("QT_QPA_PLATFORMTHEME") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME=gtk3")
- }
- if os.Getenv("QT_QPA_PLATFORMTHEME_QT6") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME_QT6=gtk3")
- }
- if os.Getenv("QT_QPA_PLATFORM") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
- }
-
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting quickshell: %v", err)
- }
-
- // Write PID file for the quickshell child process
- if err := writePIDFile(cmd.Process.Pid); err != nil {
- log.Warnf("Failed to write PID file: %v", err)
- }
- defer removePIDFile()
-
- defer func() {
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- }()
-
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
-
- go func() {
- if err := cmd.Wait(); err != nil {
- errChan <- fmt.Errorf("quickshell exited: %w", err)
- } else {
- errChan <- fmt.Errorf("quickshell exited")
- }
- }()
-
- for {
- select {
- case sig := <-sigChan:
- if sig == syscall.SIGUSR1 {
- if isSessionManaged {
- log.Infof("Received SIGUSR1, exiting for systemd restart...")
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- os.Exit(1)
- }
- log.Infof("Received SIGUSR1, spawning detached restart process...")
- execDetachedRestart(os.Getpid())
- return
- }
-
- // Check if qs already crashed before we got SIGTERM (systemd sends SIGTERM when D-Bus name is released)
- select {
- case <-errChan:
- cancel()
- os.Remove(socketPath)
- os.Exit(getProcessExitCode(cmd.ProcessState))
- case <-time.After(500 * time.Millisecond):
- }
-
- log.Infof("\nReceived signal %v, shutting down...", sig)
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- return
-
- case err := <-errChan:
- log.Error(err)
- cancel()
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- os.Remove(socketPath)
- os.Exit(getProcessExitCode(cmd.ProcessState))
- }
- }
-}
-
-func restartShell() {
- pids := getAllDMSPIDs()
-
- if len(pids) == 0 {
- log.Info("No running DMS shell instances found. Starting daemon...")
- runShellDaemon(false)
- return
- }
-
- currentPid := os.Getpid()
- uniquePids := make(map[int]bool)
-
- for _, pid := range pids {
- if pid != currentPid {
- uniquePids[pid] = true
- }
- }
-
- for pid := range uniquePids {
- proc, err := os.FindProcess(pid)
- if err != nil {
- log.Errorf("Error finding process %d: %v", pid, err)
- continue
- }
-
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- continue
- }
-
- if err := proc.Signal(syscall.SIGUSR1); err != nil {
- log.Errorf("Error sending SIGUSR1 to process %d: %v", pid, err)
- } else {
- log.Infof("Sent SIGUSR1 to DMS process with PID %d", pid)
- }
- }
-}
-
-func killShell() {
- pids := getAllDMSPIDs()
-
- if len(pids) == 0 {
- log.Info("No running DMS shell instances found.")
- return
- }
-
- currentPid := os.Getpid()
- uniquePids := make(map[int]bool)
-
- for _, pid := range pids {
- if pid != currentPid {
- uniquePids[pid] = true
- }
- }
-
- for pid := range uniquePids {
- proc, err := os.FindProcess(pid)
- if err != nil {
- log.Errorf("Error finding process %d: %v", pid, err)
- continue
- }
-
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- continue
- }
-
- if err := proc.Kill(); err != nil {
- log.Errorf("Error killing process %d: %v", pid, err)
- } else {
- log.Infof("Killed DMS process with PID %d", pid)
- }
- }
-
- dir := getRuntimeDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return
- }
-
- for _, entry := range entries {
- if strings.HasPrefix(entry.Name(), "danklinux-") && strings.HasSuffix(entry.Name(), ".pid") {
- pidFile := filepath.Join(dir, entry.Name())
- os.Remove(pidFile)
- }
- }
-}
-
-func runShellDaemon(session bool) {
- isSessionManaged = session
- isDaemonChild := slices.Contains(os.Args, "--daemon-child")
-
- if !isDaemonChild {
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- cmd := exec.Command(os.Args[0], "run", "-d", "--daemon-child")
- cmd.Env = os.Environ()
-
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Setsid: true,
- }
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting daemon: %v", err)
- }
-
- log.Infof("DMS shell daemon started (PID: %d)", cmd.Process.Pid)
- return
- }
-
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- socketPath := server.GetSocketPath()
-
- configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
- if err := os.WriteFile(configStateFile, []byte(configPath), 0o644); err != nil {
- log.Warnf("Failed to write config state file: %v", err)
- }
- defer os.Remove(configStateFile)
-
- errChan := make(chan error, 2)
-
- go func() {
- defer func() {
- if r := recover(); r != nil {
- errChan <- fmt.Errorf("server panic: %v", r)
- }
- }()
- server.CLIVersion = Version
- if err := server.Start(false); err != nil {
- errChan <- fmt.Errorf("server error: %w", err)
- }
- }()
-
- log.Infof("Spawning quickshell with -p %s", configPath)
-
- cmd := exec.CommandContext(ctx, "qs", "-p", configPath)
- cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath)
- if os.Getenv("QT_LOGGING_RULES") == "" {
- if qtRules := log.GetQtLoggingRules(); qtRules != "" {
- cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules)
- }
- }
-
- // ! TODO - remove when QS 0.3 is up and we can use the pragma
- cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms")
-
- if isSessionManaged && hasSystemdRun() {
- cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope")
- }
-
- homeDir, err := os.UserHomeDir()
- if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" {
- if !strings.HasPrefix(configPath, homeDir) {
- cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1")
- }
- }
-
- if os.Getenv("QT_QPA_PLATFORMTHEME") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME=gtk3")
- }
- if os.Getenv("QT_QPA_PLATFORMTHEME_QT6") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORMTHEME_QT6=gtk3")
- }
- if os.Getenv("QT_QPA_PLATFORM") == "" {
- cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
- }
-
- devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
- if err != nil {
- log.Fatalf("Error opening /dev/null: %v", err)
- }
- defer devNull.Close()
-
- cmd.Stdin = devNull
- cmd.Stdout = devNull
- cmd.Stderr = devNull
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting daemon: %v", err)
- }
-
- // Write PID file for the quickshell child process
- if err := writePIDFile(cmd.Process.Pid); err != nil {
- log.Warnf("Failed to write PID file: %v", err)
- }
- defer removePIDFile()
-
- defer func() {
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- }()
-
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
-
- go func() {
- if err := cmd.Wait(); err != nil {
- errChan <- fmt.Errorf("quickshell exited: %w", err)
- } else {
- errChan <- fmt.Errorf("quickshell exited")
- }
- }()
-
- for {
- select {
- case sig := <-sigChan:
- if sig == syscall.SIGUSR1 {
- if isSessionManaged {
- log.Infof("Received SIGUSR1, exiting for systemd restart...")
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- os.Exit(1)
- }
- log.Infof("Received SIGUSR1, spawning detached restart process...")
- execDetachedRestart(os.Getpid())
- return
- }
-
- // Check if qs already crashed before we got SIGTERM (systemd sends SIGTERM when D-Bus name is released)
- select {
- case <-errChan:
- cancel()
- os.Remove(socketPath)
- os.Exit(getProcessExitCode(cmd.ProcessState))
- case <-time.After(500 * time.Millisecond):
- }
-
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- return
-
- case <-errChan:
- cancel()
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- os.Remove(socketPath)
- os.Exit(getProcessExitCode(cmd.ProcessState))
- }
- }
-}
-
-var qsHasAnyDisplay = sync.OnceValue(func() bool {
- out, err := exec.Command("qs", "ipc", "--help").Output()
- if err != nil {
- return false
- }
- return strings.Contains(string(out), "--any-display")
-})
-
-func parseTargetsFromIPCShowOutput(output string) ipcTargets {
- targets := make(ipcTargets)
- var currentTarget string
- for line := range strings.SplitSeq(output, "\n") {
- if after, ok := strings.CutPrefix(line, "target "); ok {
- currentTarget = strings.TrimSpace(after)
- targets[currentTarget] = make(map[string][]string)
- }
- if strings.HasPrefix(line, " function") && currentTarget != "" {
- argsList := []string{}
- currentFunc := strings.TrimPrefix(line, " function ")
- funcDef := strings.SplitN(currentFunc, "(", 2)
- argList := strings.SplitN(funcDef[1], ")", 2)[0]
- args := strings.Split(argList, ",")
- if len(args) > 0 && strings.TrimSpace(args[0]) != "" {
- argsList = append(argsList, funcDef[0])
- for _, arg := range args {
- argName := strings.SplitN(strings.TrimSpace(arg), ":", 2)[0]
- argsList = append(argsList, argName)
- }
- targets[currentTarget][funcDef[0]] = argsList
- } else {
- targets[currentTarget][funcDef[0]] = make([]string, 0)
- }
- }
- }
- return targets
-}
-
-func getShellIPCCompletions(args []string, _ string) []string {
- cmdArgs := []string{"ipc"}
- if qsHasAnyDisplay() {
- cmdArgs = append(cmdArgs, "--any-display")
- }
- cmdArgs = append(cmdArgs, "-p", configPath, "show")
- cmd := exec.Command("qs", cmdArgs...)
- var targets ipcTargets
-
- if output, err := cmd.Output(); err == nil {
- 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
- }
- if len(args) == 1 {
- if targetFuncs, ok := targets[args[0]]; ok {
- funcNames := make([]string, 0)
- for k := range targetFuncs {
- funcNames = append(funcNames, k)
- }
- return funcNames
- }
- return nil
- }
- if len(args) <= len(targets[args[0]]) {
- funcArgs := targets[args[0]][args[1]]
- if len(funcArgs) >= len(args) {
- return []string{fmt.Sprintf("[%s]", funcArgs[len(args)-1])}
- }
- }
-
- return nil
-}
-
-func getFirstDMSPID() (int, bool) {
- dir := getRuntimeDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return 0, false
- }
-
- for _, entry := range entries {
- if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".pid") {
- continue
- }
-
- data, err := os.ReadFile(filepath.Join(dir, entry.Name()))
- if err != nil {
- continue
- }
-
- pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
- if err != nil {
- continue
- }
-
- proc, err := os.FindProcess(pid)
- if err != nil {
- continue
- }
-
- if proc.Signal(syscall.Signal(0)) != nil {
- continue
- }
-
- return pid, true
- }
-
- return 0, false
-}
-
-func runShellIPCCommand(args []string) {
- if len(args) == 0 {
- printIPCHelp()
- return
- }
-
- if args[0] != "call" {
- args = append([]string{"call"}, args...)
- }
-
- cmdArgs := []string{"ipc"}
-
- switch pid, ok := getFirstDMSPID(); {
- case ok:
- cmdArgs = append(cmdArgs, "--pid", strconv.Itoa(pid))
- default:
- if err := findConfig(nil, nil); err != nil {
- log.Fatalf("Error finding config: %v", err)
- }
- // ! TODO - remove check when QS 0.3 is released
- if qsHasAnyDisplay() {
- cmdArgs = append(cmdArgs, "--any-display")
- }
- cmdArgs = append(cmdArgs, "-p", configPath)
- }
-
- cmdArgs = append(cmdArgs, args...)
- cmd := exec.Command("qs", cmdArgs...)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if err := cmd.Run(); err != nil {
- log.Fatalf("Error running IPC command: %v", err)
- }
-}
-
-func printIPCHelp() {
- fmt.Println("Usage: dms ipc <target> <function> [args...]")
- fmt.Println()
-
- cmdArgs := []string{"ipc"}
- if qsHasAnyDisplay() {
- cmdArgs = append(cmdArgs, "--any-display")
- }
- cmdArgs = append(cmdArgs, "-p", configPath, "show")
- cmd := exec.Command("qs", cmdArgs...)
-
- output, err := cmd.Output()
- if err != nil {
- fmt.Println("Could not retrieve available IPC targets (is DMS running?)")
- return
- }
-
- targets := parseTargetsFromIPCShowOutput(string(output))
- if len(targets) == 0 {
- fmt.Println("No IPC targets available")
- return
- }
-
- fmt.Println("Targets:")
-
- targetNames := make([]string, 0, len(targets))
- for name := range targets {
- targetNames = append(targetNames, name)
- }
- slices.Sort(targetNames)
-
- for _, targetName := range targetNames {
- funcs := targets[targetName]
- funcNames := make([]string, 0, len(funcs))
- for fn := range funcs {
- funcNames = append(funcNames, fn)
- }
- slices.Sort(funcNames)
- fmt.Printf(" %-16s %s\n", targetName, strings.Join(funcNames, ", "))
- }
-}