swadhinbiswas Initial de-omarchy: Omarchy UI layer for Arch-based distros · 8/22/2026
9f393b2
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#!/bin/bash
# omarchy:summary=Install, launch, stop, inspect, or remove the Windows VM
# omarchy:args=<install|remove|launch|stop|status> [options]
# omarchy:requires-sudo=true
COMPOSE_FILE="$HOME/.config/windows/docker-compose.yml"
check_prerequisites() {
local DISK_SIZE_GB=${1:-64}
local REQUIRED_SPACE=$((DISK_SIZE_GB + 10)) # Add 10GB for Windows ISO and overhead
# Check for KVM support
if [[ ! -e /dev/kvm ]]; then
gum style \
--border normal \
--padding "1 2" \
--margin "1" \
"❌ KVM virtualization not available!" \
"" \
"Please enable virtualization in BIOS or run:" \
" sudo modprobe kvm-intel # for Intel CPUs" \
" sudo modprobe kvm-amd # for AMD CPUs"
exit 1
fi
# Check disk space
AVAILABLE_SPACE=$(df "$HOME" | awk 'NR==2 {print int($4/1024/1024)}')
if (( AVAILABLE_SPACE < REQUIRED_SPACE )); then
echo "❌ Insufficient disk space!"
echo " Available: ${AVAILABLE_SPACE}GB"
echo " Required: ${REQUIRED_SPACE}GB (${DISK_SIZE_GB}GB disk + 10GB for Windows image)"
exit 1
fi
}
install_windows() {
# Set up trap to handle Ctrl+C
trap "echo ''; echo 'Installation cancelled by user'; exit 1" INT
check_prerequisites
omarchy-pkg-add freerdp openbsd-netcat gum
mkdir -p "$HOME/.windows"
mkdir -p "$HOME/.config/windows"
mkdir -p "$HOME/.local/share/applications"
cat << EOF | tee "$HOME/.local/share/applications/windows-vm.desktop" > /dev/null
[Desktop Entry]
Name=Windows
Comment=Start Windows VM via Docker and connect with RDP
Exec=uwsm app -- omarchy-windows-vm launch
Icon=windows
Terminal=false
Type=Application
Categories=System;Virtualization;
EOF
# Get system resources
TOTAL_RAM=$(free -h | awk 'NR==2 {print $2}')
TOTAL_RAM_GB=$(awk 'NR==1 {printf "%d", $2/1024/1024}' /proc/meminfo)
TOTAL_CORES=$(nproc)
echo ""
echo "System Resources Detected:"
echo " Total RAM: $TOTAL_RAM"
echo " Total CPU Cores: $TOTAL_CORES"
echo ""
RAM_OPTIONS=""
for size in 2 4 8 16 32 64; do
if (( size <= TOTAL_RAM_GB )); then
RAM_OPTIONS="$RAM_OPTIONS ${size}G"
fi
done
SELECTED_RAM=$(echo $RAM_OPTIONS | tr ' ' '\n' | gum choose --selected="4G" --header="How much RAM would you like to allocate to Windows VM?")
# Check if user cancelled
if [[ -z $SELECTED_RAM ]]; then
echo "Installation cancelled by user"
exit 1
fi
SELECTED_CORES=$(gum input --placeholder="Number of CPU cores (1-$TOTAL_CORES)" --value="2" --header="How many CPU cores would you like to allocate to Windows VM?" --char-limit=2)
# Check if user cancelled (Ctrl+C in gum input returns empty string)
if [[ -z $SELECTED_CORES ]]; then
echo "Installation cancelled by user"
exit 1
fi
if ! [[ $SELECTED_CORES =~ ^[0-9]+$ ]] || (( SELECTED_CORES < 1 )) || (( SELECTED_CORES > TOTAL_CORES )); then
echo "Invalid input. Using default: 2 cores"
SELECTED_CORES=2
fi
AVAILABLE_SPACE=$(df "$HOME" | awk 'NR==2 {print int($4/1024/1024)}')
MAX_DISK_GB=$((AVAILABLE_SPACE - 10)) # Leave 10GB for Windows image
# Check if we have enough space for minimum
if (( MAX_DISK_GB < 32 )); then
echo "❌ Insufficient disk space for Windows VM!"
echo " Available: ${AVAILABLE_SPACE}GB"
echo " Minimum required: 42GB (32GB disk + 10GB for Windows image)"
exit 1
fi
DISK_OPTIONS=""
for size in 32 64 128 256 512; do
if (( size <= MAX_DISK_GB )); then
DISK_OPTIONS="$DISK_OPTIONS ${size}G"
fi
done
# Default to 64G if available, otherwise 32G
DEFAULT_DISK="64G"
if ! echo "$DISK_OPTIONS" | grep -q "64G"; then
DEFAULT_DISK="32G"
fi
SELECTED_DISK=$(echo $DISK_OPTIONS | tr ' ' '\n' | gum choose --selected="$DEFAULT_DISK" --header="How much disk space would you like to give Windows VM? (64GB+ recommended)")
# Check if user cancelled
if [[ -z $SELECTED_DISK ]]; then
echo "Installation cancelled by user"
exit 1
fi
# Extract just the number for prerequisite check
DISK_SIZE_NUM=$(echo "$SELECTED_DISK" | sed 's/G//')
# Re-check prerequisites with selected disk size
check_prerequisites "$DISK_SIZE_NUM"
# Prompt for username and password
USERNAME=$(gum input --placeholder="Username (Press enter to use default: docker)" --header="Enter Windows username:")
if [[ -z $USERNAME ]]; then
USERNAME="docker"
fi
PASSWORD=$(gum input --placeholder="Password (Press enter to use default: admin)" --password --header="Enter Windows password:")
if [[ -z $PASSWORD ]]; then
PASSWORD="admin"
PASSWORD_DISPLAY="(default)"
else
PASSWORD_DISPLAY="(user-defined)"
fi
# Display configuration summary
gum style \
--border normal \
--padding "1 2" \
--margin "1" \
--align left \
--bold \
"Windows VM Configuration" \
"" \
"RAM: $SELECTED_RAM" \
"CPU: $SELECTED_CORES cores" \
"Disk: $SELECTED_DISK" \
"Username: $USERNAME" \
"Password: $PASSWORD_DISPLAY"
# Ask for confirmation
echo ""
if ! gum confirm "Proceed with this configuration?"; then
echo "Installation cancelled by user"
exit 1
fi
mkdir -p $HOME/Windows
# Create docker-compose.yml in user config directory
cat << EOF | tee "$COMPOSE_FILE" > /dev/null
services:
windows:
image: dockurr/windows
container_name: omarchy-windows
environment:
VERSION: "11"
RAM_SIZE: "$SELECTED_RAM"
CPU_CORES: "$SELECTED_CORES"
DISK_SIZE: "$SELECTED_DISK"
USERNAME: "$USERNAME"
PASSWORD: "$PASSWORD"
TZ: "$(timedatectl show -p Timezone --value 2>/dev/null || echo UTC)"
ARGUMENTS: "-rtc base=localtime,clock=host,driftfix=slew"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 127.0.0.1:8006:8006
- 127.0.0.1:3389:3389/tcp
- 127.0.0.1:3389:3389/udp
volumes:
- $HOME/.windows:/storage
- $HOME/Windows:/shared
restart: "no"
stop_grace_period: 2m
EOF
echo ""
echo "Starting Windows VM installation..."
echo "This will download a Windows 11 image (may take 10-15 minutes)."
echo ""
echo "Monitor installation progress at: http://127.0.0.1:8006"
echo ""
# Start docker-compose with user's config
echo "Starting Windows VM with docker-compose..."
if ! docker-compose -f "$COMPOSE_FILE" up -d 2>&1; then
echo "❌ Failed to start Windows VM!"
echo " Common issues:"
echo " - Docker daemon not running: sudo systemctl start docker"
echo " - Port already in use: check if another VM is running"
echo " - Permission issues: make sure you're in the docker group"
exit 1
fi
echo ""
echo "Windows VM is starting up!"
echo ""
echo "Opening browser to monitor installation..."
# Open browser to monitor installation
sleep 3
xdg-open "http://127.0.0.1:8006"
echo ""
echo "Installation is running in the background."
echo "You can monitor progress at: http://127.0.0.1:8006"
echo ""
echo "Once finished, launch 'Windows' via Super + Space"
echo ""
echo "To stop the VM: omarchy-windows-vm stop"
echo "To change resources: ~/.config/windows/docker-compose.yml"
echo ""
}
remove_windows() {
if ! gum confirm --default=false "Remove Windows VM and delete all associated data?"; then
echo "Removal cancelled by user"
exit 1
fi
echo "Removing Windows VM..."
docker-compose -f "$COMPOSE_FILE" down 2>/dev/null || true
docker rmi dockurr/windows 2>/dev/null || echo "Image already removed or not found"
rm "$HOME/.local/share/applications/windows-vm.desktop"
rm -rf "$HOME/.config/windows"
rm -rf "$HOME/.windows"
echo ""
echo "Windows VM removal completed!"
}
launch_windows() {
KEEP_ALIVE=false
if [[ $1 = "--keep-alive" ]] || [[ $1 = "-k" ]]; then
KEEP_ALIVE=true
fi
# Check if config exists
if [[ ! -f $COMPOSE_FILE ]]; then
echo "Windows VM not configured. Please run: omarchy-windows-vm install"
exit 1
fi
# Extract credentials from compose file
WIN_USER=$(grep "USERNAME:" "$COMPOSE_FILE" | sed 's/.*USERNAME: "\(.*\)"/\1/')
WIN_PASS=$(grep "PASSWORD:" "$COMPOSE_FILE" | sed 's/.*PASSWORD: "\(.*\)"/\1/')
# Use defaults if not found
[[ -z $WIN_USER ]] && WIN_USER="docker"
[[ -z $WIN_PASS ]] && WIN_PASS="admin"
# Check if container is already running
CONTAINER_STATUS=$(docker inspect --format='{{.State.Status}}' omarchy-windows 2>/dev/null)
if [[ $CONTAINER_STATUS != "running" ]]; then
echo "Starting Windows VM..."
if ! docker-compose -f "$COMPOSE_FILE" up -d 2>&1; then
echo "❌ Failed to start Windows VM!"
echo " Try checking: omarchy-windows-vm status"
echo " View logs: docker logs omarchy-windows"
omarchy-notification-send -u critical "Windows VM" "Failed to start Windows VM"
exit 1
fi
fi
# docker logs keeps output across stop/start and is only cleared when the
# container is removed, so an unanchored grep matches "started successfully"
# from an earlier boot and returns immediately. Anchor the scan to the current
# container start, and run it even when the container was already up: the
# image restarts the guest in place whenever Windows reboots.
windows_started() {
local started_at
started_at=$(docker inspect --format='{{.State.StartedAt}}' omarchy-windows 2>/dev/null)
# An empty --since would drop the filter and match a stale boot again
[[ -n $started_at ]] || return 1
docker logs --since "$started_at" omarchy-windows 2>&1 | grep -qi "windows started successfully"
}
echo "Waiting for Windows VM to start..."
WAIT_COUNT=0
until windows_started; do
sleep 2
WAIT_COUNT=$((WAIT_COUNT + 1))
if (( WAIT_COUNT > 60 )); then # 2 minutes timeout
echo ""
echo "❌ Timeout: Windows VM failed to start within 2 minutes"
echo " Check logs: docker logs omarchy-windows"
exit 1
fi
done
# Build the connection info
if [[ $KEEP_ALIVE = "true" ]]; then
LIFECYCLE="VM will keep running after RDP closes
To stop: omarchy-windows-vm stop"
else
LIFECYCLE="VM will auto-stop when RDP closes"
fi
gum style \
--border normal \
--padding "1 2" \
--margin "1" \
--align center \
"Connecting to Windows VM" \
"" \
"$LIFECYCLE"
# FreeRDP 3 tries Kerberos before NTLM for NLA, and krb5 ships /etc/krb5.conf
# as the MIT sample with default_realm = ATHENA.MIT.EDU. Every connect then
# goes looking for MIT's KDC: with internet up it fails fast, but off the
# network each attempt blocks ~23s and no RDP window is ever drawn. The VM
# authenticates against a local Windows account, so point FreeRDP at a
# realm-less config and let it fall straight through to NTLM.
KRB5_CONF="$(dirname "$COMPOSE_FILE")/krb5.conf"
if [[ ! -f $KRB5_CONF ]]; then
printf '[libdefaults]\n dns_lookup_kdc = false\n dns_lookup_realm = false\n' >"$KRB5_CONF"
fi
export KRB5_CONFIG="$KRB5_CONF"
# Detect display scale from Hyprland
HYPR_SCALE=$(hyprctl monitors -j | jq -r '.[] | select (.focused == true) | .scale')
SCALE_PERCENT=$(echo "$HYPR_SCALE" | awk '{print int($1 * 100)}')
RDP_SCALE=""
if (( SCALE_PERCENT >= 170 )); then
RDP_SCALE="/scale:180"
elif (( SCALE_PERCENT >= 130 )); then
RDP_SCALE="/scale:140"
fi
# If scale is less than 130%, don't set any scale (use default 100)
# Connect with RDP in fullscreen (auto-detects resolution)
xfreerdp3 /u:"$WIN_USER" /p:"$WIN_PASS" /v:127.0.0.1:3389 -grab-keyboard /sound /microphone /clipboard /cert:ignore /title:"Windows VM - Omarchy" /dynamic-resolution /gfx:AVC444 /floatbar:sticky:off,default:visible,show:fullscreen $RDP_SCALE
# After RDP closes, stop the container unless --keep-alive was specified
if [[ $KEEP_ALIVE = "false" ]]; then
echo ""
echo "RDP session closed. Stopping Windows VM..."
docker-compose -f "$COMPOSE_FILE" down
echo "Windows VM stopped."
else
echo ""
echo "RDP session closed. Windows VM is still running."
echo "To stop it: omarchy-windows-vm stop"
fi
}
stop_windows() {
if [[ ! -f $COMPOSE_FILE ]]; then
echo "Windows VM not configured."
exit 1
fi
echo "Stopping Windows VM..."
docker-compose -f "$COMPOSE_FILE" down
echo "Windows VM stopped."
}
status_windows() {
if [[ ! -f $COMPOSE_FILE ]]; then
echo "Windows VM not configured."
echo "To set up: omarchy-windows-vm install"
exit 1
fi
CONTAINER_STATUS=$(docker inspect --format='{{.State.Status}}' omarchy-windows 2>/dev/null)
if [[ -z $CONTAINER_STATUS ]]; then
echo "Windows VM container not found."
echo "To start: omarchy-windows-vm launch"
elif [[ $CONTAINER_STATUS = "running" ]]; then
gum style \
--border normal \
--padding "1 2" \
--margin "1" \
--align left \
"Windows VM Status: RUNNING" \
"" \
"Web interface: http://127.0.0.1:8006" \
"RDP available: port 3389" \
"" \
"To connect: omarchy-windows-vm launch" \
"To stop: omarchy-windows-vm stop"
else
echo "Windows VM is stopped (status: $CONTAINER_STATUS)"
echo "To start: omarchy-windows-vm launch"
fi
}
show_usage() {
echo "Usage: omarchy-windows-vm [command] [options]"
echo ""
echo "Commands:"
echo " install Install and configure Windows VM"
echo " remove Remove Windows VM and optionally its data"
echo " launch [options] Start Windows VM (if needed) and connect via RDP"
echo " Options:"
echo " --keep-alive, -k Keep VM running after RDP closes"
echo " stop Stop the running Windows VM"
echo " status Show current VM status"
echo " help Show this help message"
echo ""
echo "Examples:"
echo " omarchy-windows-vm install # Set up Windows VM for first time"
echo " omarchy-windows-vm launch # Connect to VM (auto-stop on exit)"
echo " omarchy-windows-vm launch -k # Connect to VM (keep running)"
echo " omarchy-windows-vm stop # Shut down the VM"
}
# Main command dispatcher
case "$1" in
install)
install_windows
;;
remove)
remove_windows
;;
launch|start)
launch_windows "$2"
;;
stop|down)
stop_windows
;;
status)
status_windows
;;
help|--help|-h|"")
show_usage
;;
*)
echo "Unknown command: $1" >&2
echo "" >&2
show_usage >&2
exit 1
;;
esac