integrated launch terminal into launcher with option to show it
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
package launcher
|
package launcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"turtlesilicon/pkg/paths" // Corrected import path
|
"turtlesilicon/pkg/paths" // Corrected import path
|
||||||
"turtlesilicon/pkg/utils" // Corrected import path
|
"turtlesilicon/pkg/utils" // Corrected import path
|
||||||
@@ -15,6 +19,87 @@ import (
|
|||||||
var EnableMetalHud = true // Default to enabled
|
var EnableMetalHud = true // Default to enabled
|
||||||
var CustomEnvVars = "" // Custom environment variables
|
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 <path> && <envVars> <rosettaExec> <wineloader> <wowExe>
|
||||||
|
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) {
|
func LaunchGame(myWindow fyne.Window) {
|
||||||
log.Println("Launch Game button clicked")
|
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...")
|
log.Println("Preparing to launch TurtleSilicon...")
|
||||||
|
|
||||||
rosettaInTurtlePath := filepath.Join(paths.TurtlewowPath, "rosettax87")
|
rosettaInTurtlePath := filepath.Join(paths.TurtlewowPath, "rosettax87")
|
||||||
@@ -82,13 +176,53 @@ func LaunchGame(myWindow fyne.Window) {
|
|||||||
utils.QuotePathForShell(wineloader2Path),
|
utils.QuotePathForShell(wineloader2Path),
|
||||||
utils.QuotePathForShell(wowExePath))
|
utils.QuotePathForShell(wowExePath))
|
||||||
|
|
||||||
escapedShellCmd := utils.EscapeStringForAppleScript(shellCmd)
|
// Check user preference for terminal display
|
||||||
cmd2Script := fmt.Sprintf("tell application \"Terminal\" to do script \"%s\"", escapedShellCmd)
|
prefs, _ := utils.LoadPrefs()
|
||||||
|
|
||||||
log.Println("Executing WoW launch command via AppleScript...")
|
if prefs.ShowTerminalNormally {
|
||||||
if !utils.RunOsascript(cmd2Script, myWindow) {
|
// Use the old method with external Terminal.app
|
||||||
return
|
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
|
||||||
}
|
}
|
||||||
|
16
pkg/ui/ui.go
16
pkg/ui/ui.go
@@ -35,6 +35,7 @@ var (
|
|||||||
startServiceButton *widget.Button
|
startServiceButton *widget.Button
|
||||||
stopServiceButton *widget.Button
|
stopServiceButton *widget.Button
|
||||||
metalHudCheckbox *widget.Check
|
metalHudCheckbox *widget.Check
|
||||||
|
showTerminalCheckbox *widget.Check
|
||||||
envVarsEntry *widget.Entry
|
envVarsEntry *widget.Entry
|
||||||
pulsingActive = false
|
pulsingActive = false
|
||||||
)
|
)
|
||||||
@@ -267,6 +268,15 @@ func CreateUI(myWindow fyne.Window) fyne.CanvasObject {
|
|||||||
})
|
})
|
||||||
metalHudCheckbox.SetChecked(launcher.EnableMetalHud)
|
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
|
// Load environment variables from preferences
|
||||||
if prefs.EnvironmentVariables != "" {
|
if prefs.EnvironmentVariables != "" {
|
||||||
launcher.CustomEnvVars = prefs.EnvironmentVariables
|
launcher.CustomEnvVars = prefs.EnvironmentVariables
|
||||||
@@ -356,7 +366,11 @@ func CreateUI(myWindow fyne.Window) fyne.CanvasObject {
|
|||||||
logoContainer,
|
logoContainer,
|
||||||
pathSelectionForm,
|
pathSelectionForm,
|
||||||
patchOperationsLayout,
|
patchOperationsLayout,
|
||||||
metalHudCheckbox,
|
container.NewHBox(
|
||||||
|
metalHudCheckbox,
|
||||||
|
showTerminalCheckbox,
|
||||||
|
),
|
||||||
|
widget.NewSeparator(),
|
||||||
widget.NewLabel("Environment Variables:"),
|
widget.NewLabel("Environment Variables:"),
|
||||||
envVarsEntry,
|
envVarsEntry,
|
||||||
container.NewPadded(launchButton),
|
container.NewPadded(launchButton),
|
||||||
|
@@ -12,6 +12,7 @@ type UserPrefs struct {
|
|||||||
CrossOverPath string `json:"crossover_path"`
|
CrossOverPath string `json:"crossover_path"`
|
||||||
EnvironmentVariables string `json:"environment_variables"`
|
EnvironmentVariables string `json:"environment_variables"`
|
||||||
SaveSudoPassword bool `json:"save_sudo_password"`
|
SaveSudoPassword bool `json:"save_sudo_password"`
|
||||||
|
ShowTerminalNormally bool `json:"show_terminal_normally"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPrefsPath() (string, error) {
|
func getPrefsPath() (string, error) {
|
||||||
|
Reference in New Issue
Block a user