1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
package main
import (
"bufio"
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
// WindowConfig holds the configuration for a single terminal window.
type WindowConfig struct {
Title string
Path string
Geometry string // In WIDTHxHEIGHT+X+Y format
Workspace string
}
func main() {
// 1. Get current working directory.
pwd, err := os.Getwd()
if err != nil {
fmt.Println("Failed to get current directory:", err)
return
}
// 2. Read and parse the configuration file.
configFile := "/home/jcarr/go/src/gemini/xstartplacement.out"
configs, err := parseConfig(configFile)
if err != nil {
fmt.Printf("Failed to parse config file '%s': %v\n", configFile, err)
return
}
// 3. Find the best matching configuration for the current directory.
var bestMatch *WindowConfig
longestPrefix := 0
for i, config := range configs {
if strings.HasPrefix(pwd, config.Path) {
if len(config.Path) > longestPrefix {
longestPrefix = len(config.Path)
bestMatch = &configs[i]
}
}
}
if bestMatch == nil {
fmt.Printf("No configuration found for directory: %s\n", pwd)
return
}
targetConfig := bestMatch
fmt.Printf("Found matching configuration for path: %s\n", targetConfig.Path)
// 4. Get the list of windows before launching the new terminal.
windowsBefore, err := getWindowList()
if err != nil {
fmt.Println("Failed to get initial window list:", err)
return
}
// 5. Launch mate-terminal.
geomString := targetConfig.Geometry
cmd := exec.Command("mate-terminal", "--geometry", geomString)
if err := cmd.Start(); err != nil {
fmt.Println("Failed to start mate-terminal:", err)
return
}
fmt.Printf("Launched mate-terminal with geometry %s\n", geomString)
// 6. Find the new window by comparing the window lists.
var newWindowID string
for i := 0; i < 10; i++ {
time.Sleep(500 * time.Millisecond)
windowsAfter, err := getWindowList()
if err != nil {
fmt.Println("Failed to get updated window list:", err)
continue
}
newWindowID = findNewWindow(windowsBefore, windowsAfter)
if newWindowID != "" {
break
}
}
if newWindowID == "" {
fmt.Println("Could not find the new terminal window.")
return
}
fmt.Printf("Found new window with ID: %s\n", newWindowID)
// 7. Move the window to the correct workspace.
cmd = exec.Command("wmctrl", "-i", "-r", newWindowID, "-t", targetConfig.Workspace)
if err := cmd.Run(); err != nil {
fmt.Println("Failed to move window to workspace:", err)
} else {
fmt.Printf("Moved window to workspace %s\n", targetConfig.Workspace)
}
// 8. Set the final window title.
finalTitle := fmt.Sprintf("jcarr@framebook: %s", pwd)
cmd = exec.Command("wmctrl", "-i", "-r", newWindowID, "-T", finalTitle)
if err := cmd.Run(); err != nil {
fmt.Println("Failed to set final window title:", err)
} else {
fmt.Println("Window setup complete.")
}
}
// getWindowList returns a map of window IDs to their titles.
func getWindowList() (map[string]string, error) {
cmd := exec.Command("wmctrl", "-l")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return nil, err
}
windows := make(map[string]string)
scanner := bufio.NewScanner(&out)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) > 0 {
windows[fields[0]] = strings.Join(fields[3:], " ")
}
}
return windows, nil
}
// findNewWindow compares two maps of windows and returns the ID of the new window.
func findNewWindow(before, after map[string]string) string {
for id := range after {
if _, ok := before[id]; !ok {
return id
}
}
return ""
}
// parseConfig remains the same as before.
func parseConfig(filePath string) ([]WindowConfig, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
var configs []WindowConfig
scanner := bufio.NewScanner(file)
var currentConfig WindowConfig
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("could not get user home directory: %w", err)
}
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, " Title: ") {
title := strings.TrimSpace(strings.TrimPrefix(line, " Title: "))
currentConfig.Title = title
parts := strings.SplitN(title, ": ", 2)
if len(parts) == 2 {
path := parts[1]
if strings.HasPrefix(path, "~") {
path = filepath.Join(homeDir, path[1:])
}
currentConfig.Path = path
}
} else if strings.HasPrefix(line, " Geometry: ") {
geomStr := strings.TrimSpace(strings.TrimPrefix(line, " Geometry: "))
var x, y, w, h string
_, err := fmt.Sscanf(geomStr, "X=%s Y=%s Width=%s Height=%s", &x, &y, &w, &h)
if err == nil {
x = strings.TrimSuffix(x, ",")
y = strings.TrimSuffix(y, ",")
w = strings.TrimSuffix(w, ",")
currentConfig.Geometry = fmt.Sprintf("%sx%s+%s+%s", w, h, x, y)
}
} else if strings.HasPrefix(line, " Workspace: ") {
currentConfig.Workspace = strings.TrimSpace(strings.TrimPrefix(line, " Workspace: "))
} else if line == "---" {
if currentConfig.Path != "" {
configs = append(configs, currentConfig)
}
currentConfig = WindowConfig{} // Reset for the next entry
}
}
if currentConfig.Path != "" {
configs = append(configs, currentConfig)
}
if err := scanner.Err(); err != nil {
return nil, err
}
return configs, nil
}
|