From a43965cf71a94f6a7ed4b5bf4ee052ea2a0038e0 Mon Sep 17 00:00:00 2001 From: aomizu Date: Sat, 31 May 2025 12:14:35 +0900 Subject: [PATCH] integrated launch terminal into launcher with option to show it --- pkg/launcher/launcher.go | 146 +++++++++++++++++++++++++++++++++++++-- pkg/ui/ui.go | 16 ++++- pkg/utils/prefs.go | 1 + 3 files changed, 156 insertions(+), 7 deletions(-) diff --git a/pkg/launcher/launcher.go b/pkg/launcher/launcher.go index b4a2357..4caf30c 100644 --- a/pkg/launcher/launcher.go +++ b/pkg/launcher/launcher.go @@ -1,9 +1,13 @@ package launcher import ( + "bufio" "fmt" "log" + "os" + "os/exec" "path/filepath" + "sync" "turtlesilicon/pkg/paths" // Corrected import path "turtlesilicon/pkg/utils" // Corrected import path @@ -15,6 +19,87 @@ import ( var EnableMetalHud = true // Default to enabled var CustomEnvVars = "" // Custom environment variables +// Terminal state management +var ( + currentGameProcess *exec.Cmd + isGameRunning bool + gameMutex sync.Mutex +) + +// runGameIntegrated runs the game with integrated terminal output +func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error { + gameMutex.Lock() + defer gameMutex.Unlock() + + if isGameRunning { + return fmt.Errorf("game is already running") + } + + isGameRunning = true + + // Parse the shell command to extract components + // The shellCmd format is: cd && + log.Printf("Parsing shell command: %s", shellCmd) + + // Create the command without context cancellation + cmd := exec.Command("sh", "-c", shellCmd) + + // Set up stdout and stderr pipes + stdout, err := cmd.StdoutPipe() + if err != nil { + isGameRunning = false + return err + } + stderr, err := cmd.StderrPipe() + if err != nil { + isGameRunning = false + return err + } + + currentGameProcess = cmd + + // Start the process + if err := cmd.Start(); err != nil { + isGameRunning = false + return err + } + + // Monitor output in goroutines + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + line := scanner.Text() + log.Printf("GAME STDOUT: %s", line) + } + }() + + go func() { + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + line := scanner.Text() + log.Printf("GAME STDERR: %s", line) + } + }() + + // Wait for the process to complete in a goroutine + go func() { + defer func() { + gameMutex.Lock() + isGameRunning = false + currentGameProcess = nil + gameMutex.Unlock() + }() + + if err := cmd.Wait(); err != nil { + log.Printf("Game process ended with error: %v", err) + } else { + log.Println("Game process ended successfully") + } + }() + + return nil +} + func LaunchGame(myWindow fyne.Window) { log.Println("Launch Game button clicked") @@ -36,6 +121,15 @@ func LaunchGame(myWindow fyne.Window) { } } + // Check if game is already running + gameMutex.Lock() + if isGameRunning { + gameMutex.Unlock() + dialog.ShowInformation("Game Already Running", "The game is already running.", myWindow) + return + } + gameMutex.Unlock() + log.Println("Preparing to launch TurtleSilicon...") rosettaInTurtlePath := filepath.Join(paths.TurtlewowPath, "rosettax87") @@ -82,13 +176,53 @@ func LaunchGame(myWindow fyne.Window) { utils.QuotePathForShell(wineloader2Path), utils.QuotePathForShell(wowExePath)) - escapedShellCmd := utils.EscapeStringForAppleScript(shellCmd) - cmd2Script := fmt.Sprintf("tell application \"Terminal\" to do script \"%s\"", escapedShellCmd) + // Check user preference for terminal display + prefs, _ := utils.LoadPrefs() - log.Println("Executing WoW launch command via AppleScript...") - if !utils.RunOsascript(cmd2Script, myWindow) { - return + if prefs.ShowTerminalNormally { + // Use the old method with external Terminal.app + escapedShellCmd := utils.EscapeStringForAppleScript(shellCmd) + cmd2Script := fmt.Sprintf("tell application \"Terminal\" to do script \"%s\"", escapedShellCmd) + + log.Println("Executing WoW launch command via AppleScript...") + if !utils.RunOsascript(cmd2Script, myWindow) { + return + } + + log.Println("Launch command executed. Check the new terminal window.") + } else { + // Use integrated terminal + log.Printf("Shell command for integrated terminal: %s", shellCmd) + log.Println("Executing WoW launch command with integrated terminal...") + if err := runGameIntegrated(myWindow, shellCmd); err != nil { + dialog.ShowError(fmt.Errorf("failed to launch game: %v", err), myWindow) + return + } + log.Println("Game launched with integrated terminal. Check the application logs for output.") + } +} + +// IsGameRunning returns true if the game is currently running +func IsGameRunning() bool { + gameMutex.Lock() + defer gameMutex.Unlock() + return isGameRunning +} + +// StopGame forcefully stops the running game +func StopGame() error { + gameMutex.Lock() + defer gameMutex.Unlock() + + if !isGameRunning || currentGameProcess == nil { + return fmt.Errorf("no game process is running") } - log.Println("Launch command executed. Check the new terminal window.") + // Try to terminate gracefully first + if err := currentGameProcess.Process.Signal(os.Interrupt); err != nil { + // If that fails, force kill + return currentGameProcess.Process.Kill() + } + + return nil } diff --git a/pkg/ui/ui.go b/pkg/ui/ui.go index 3babbe0..37fbd9f 100644 --- a/pkg/ui/ui.go +++ b/pkg/ui/ui.go @@ -35,6 +35,7 @@ var ( startServiceButton *widget.Button stopServiceButton *widget.Button metalHudCheckbox *widget.Check + showTerminalCheckbox *widget.Check envVarsEntry *widget.Entry pulsingActive = false ) @@ -267,6 +268,15 @@ func CreateUI(myWindow fyne.Window) fyne.CanvasObject { }) metalHudCheckbox.SetChecked(launcher.EnableMetalHud) + showTerminalCheckbox = widget.NewCheck("Show Terminal", func(checked bool) { + // Save to preferences + prefs, _ := utils.LoadPrefs() + prefs.ShowTerminalNormally = checked + utils.SavePrefs(prefs) + log.Printf("Show terminal normally: %v", checked) + }) + showTerminalCheckbox.SetChecked(prefs.ShowTerminalNormally) + // Load environment variables from preferences if prefs.EnvironmentVariables != "" { launcher.CustomEnvVars = prefs.EnvironmentVariables @@ -356,7 +366,11 @@ func CreateUI(myWindow fyne.Window) fyne.CanvasObject { logoContainer, pathSelectionForm, patchOperationsLayout, - metalHudCheckbox, + container.NewHBox( + metalHudCheckbox, + showTerminalCheckbox, + ), + widget.NewSeparator(), widget.NewLabel("Environment Variables:"), envVarsEntry, container.NewPadded(launchButton), diff --git a/pkg/utils/prefs.go b/pkg/utils/prefs.go index b913e77..5cff097 100644 --- a/pkg/utils/prefs.go +++ b/pkg/utils/prefs.go @@ -12,6 +12,7 @@ type UserPrefs struct { CrossOverPath string `json:"crossover_path"` EnvironmentVariables string `json:"environment_variables"` SaveSudoPassword bool `json:"save_sudo_password"` + ShowTerminalNormally bool `json:"show_terminal_normally"` } func getPrefsPath() (string, error) {