diff --git a/core/cmd/dms/commands_greeter.go b/core/cmd/dms/commands_greeter.go index b4dd872a..a96ddef3 100644 --- a/core/cmd/dms/commands_greeter.go +++ b/core/cmd/dms/commands_greeter.go @@ -119,7 +119,7 @@ func installGreeter() error { } fmt.Println("\nSynchronizing DMS configurations...") - if err := greeter.SyncDMSConfigs(dmsPath, logFunc, ""); err != nil { + if err := greeter.SyncDMSConfigs(dmsPath, selectedCompositor, logFunc, ""); err != nil { return err } @@ -147,6 +147,23 @@ func syncGreeter() error { } fmt.Printf("✓ Found DMS at: %s\n", dmsPath) + if !isGreeterEnabled() { + fmt.Println("\n⚠ DMS greeter is not enabled in greetd config.") + fmt.Print("Would you like to enable it now? (Y/n): ") + + var response string + fmt.Scanln(&response) + response = strings.ToLower(strings.TrimSpace(response)) + + if response != "n" && response != "no" { + if err := enableGreeter(); err != nil { + return err + } + } else { + return fmt.Errorf("greeter must be enabled before syncing") + } + } + cacheDir := "/var/cache/dms-greeter" if _, err := os.Stat(cacheDir); os.IsNotExist(err) { return fmt.Errorf("greeter cache directory not found at %s\nPlease install the greeter first", cacheDir) @@ -188,13 +205,34 @@ func syncGreeter() error { } } + compositor := detectConfiguredCompositor() + if compositor == "" { + compositors := greeter.DetectCompositors() + switch len(compositors) { + case 0: + return fmt.Errorf("no supported compositors found") + case 1: + compositor = compositors[0] + fmt.Printf("✓ Using compositor: %s\n", compositor) + default: + var err error + compositor, err = promptCompositorChoice(compositors) + if err != nil { + return err + } + fmt.Printf("✓ Selected compositor: %s\n", compositor) + } + } else { + fmt.Printf("✓ Detected compositor from config: %s\n", compositor) + } + fmt.Println("\nSetting up permissions and ACLs...") if err := greeter.SetupDMSGroup(logFunc, ""); err != nil { return err } fmt.Println("\nSynchronizing DMS configurations...") - if err := greeter.SyncDMSConfigs(dmsPath, logFunc, ""); err != nil { + if err := greeter.SyncDMSConfigs(dmsPath, compositor, logFunc, ""); err != nil { return err } @@ -552,6 +590,39 @@ func enableGreeter() error { return nil } +func isGreeterEnabled() bool { + data, err := os.ReadFile("/etc/greetd/config.toml") + if err != nil { + return false + } + return strings.Contains(string(data), "dms-greeter") +} + +func detectConfiguredCompositor() string { + data, err := os.ReadFile("/etc/greetd/config.toml") + if err != nil { + return "" + } + + for _, line := range strings.Split(string(data), "\n") { + trimmed := strings.TrimSpace(line) + if !strings.HasPrefix(trimmed, "command") || !strings.Contains(trimmed, "dms-greeter") { + continue + } + + switch { + case strings.Contains(trimmed, "--command niri"): + return "niri" + case strings.Contains(trimmed, "--command hyprland"): + return "hyprland" + case strings.Contains(trimmed, "--command sway"): + return "sway" + } + } + + return "" +} + func promptCompositorChoice(compositors []string) (string, error) { fmt.Println("\nMultiple compositors detected:") for i, comp := range compositors { diff --git a/core/internal/config/embedded/niri-greeter.kdl b/core/internal/config/embedded/niri-greeter.kdl new file mode 100644 index 00000000..5653a16e --- /dev/null +++ b/core/internal/config/embedded/niri-greeter.kdl @@ -0,0 +1,17 @@ +hotkey-overlay { + skip-at-startup +} + +environment { + DMS_RUN_GREETER "1" +} + +gestures { + hot-corners { + off + } +} + +layout { + background-color "#000000" +} diff --git a/core/internal/config/niri.go b/core/internal/config/niri.go index e68f77e0..01801ca0 100644 --- a/core/internal/config/niri.go +++ b/core/internal/config/niri.go @@ -16,3 +16,6 @@ var NiriAlttabConfig string //go:embed embedded/niri-binds.kdl var NiriBindsConfig string + +//go:embed embedded/niri-greeter.kdl +var NiriGreeterConfig string diff --git a/core/internal/greeter/installer.go b/core/internal/greeter/installer.go index 0bcd26bf..13b05472 100644 --- a/core/internal/greeter/installer.go +++ b/core/internal/greeter/installer.go @@ -325,7 +325,7 @@ func SetupDMSGroup(logFunc func(string), sudoPassword string) error { return nil } -func SyncDMSConfigs(dmsPath string, logFunc func(string), sudoPassword string) error { +func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string) error { homeDir, err := os.UserHomeDir() if err != nil { return fmt.Errorf("failed to get user home directory: %w", err) @@ -381,6 +381,10 @@ func SyncDMSConfigs(dmsPath string, logFunc func(string), sudoPassword string) e logFunc(fmt.Sprintf("✓ Synced %s", link.desc)) } + if strings.ToLower(compositor) != "niri" { + return nil + } + if err := syncNiriGreeterConfig(logFunc, sudoPassword); err != nil { logFunc(fmt.Sprintf("⚠ Warning: Failed to sync niri greeter config: %v", err)) } @@ -464,7 +468,7 @@ func syncNiriGreeterConfig(logFunc func(string), sudoPassword string) error { return fmt.Errorf("failed to install greetd niri dms config: %w", err) } - mainContent := fmt.Sprintf("hotkey-overlay {\n skip-at-startup\n}\n\ninclude \"%s\"\n", dmsPath) + mainContent := fmt.Sprintf("%s\ninclude \"%s\"\n", config.NiriGreeterConfig, dmsPath) mainTemp, err := os.CreateTemp("", "dms-greeter-niri-main-*.kdl") if err != nil { return fmt.Errorf("failed to create temp file: %w", err) @@ -526,9 +530,8 @@ func ensureGreetdNiriConfig(logFunc func(string), sudoPassword string, niriConfi if !strings.Contains(command, "--command niri") { continue } - if strings.Contains(command, " -C ") || strings.Contains(command, " --config ") || strings.Contains(command, "--config") { - return nil - } + // Strip existing -C or --config and their arguments + command = stripConfigFlag(command) newCommand := fmt.Sprintf("%s -C %s", command, niriConfigPath) idx := strings.Index(line, "command") @@ -808,6 +811,37 @@ user = "greeter" return nil } +func stripConfigFlag(command string) string { + for _, flag := range []string{" -C ", " --config "} { + idx := strings.Index(command, flag) + if idx == -1 { + continue + } + + before := command[:idx] + after := command[idx+len(flag):] + + switch { + case strings.HasPrefix(after, `"`): + if end := strings.Index(after[1:], `"`); end != -1 { + after = after[end+2:] + } else { + after = "" + } + default: + if space := strings.Index(after, " "); space != -1 { + after = after[space:] + } else { + after = "" + } + } + + command = strings.TrimSpace(before + after) + } + + return command +} + func runSudoCmd(sudoPassword string, command string, args ...string) error { var cmd *exec.Cmd