@@ -61,7 +61,8 @@ ensure_user_in_kvm_group() {
6161 return 0
6262 fi
6363
64- if sudo usermod -aG kvm " $USER " 2> /dev/null; then
64+ # Use -n to avoid blocking in background processes
65+ if sudo -n usermod -aG kvm " $USER " 2> /dev/null; then
6566 return 1
6667 else
6768 return 2
@@ -1301,6 +1302,7 @@ show_installation_summary() {
13011302
13021303connect_looking_glass () {
13031304 local KEEP_ALIVE=" ${1:- true} "
1305+ local WINDOWED=" ${2:- false} "
13041306
13051307 # Note: sudo -v removed - no longer needed with sudoers rules configured
13061308 # Socket permissions are fixed automatically via passwordless sudo rules
@@ -1387,15 +1389,15 @@ connect_looking_glass() {
13871389 fi
13881390
13891391 # Try to read escape key from client.ini
1390- local escape_key=" Right Ctrl "
1392+ local escape_key=" Scroll Lock "
13911393 local lg_config=" $HOME /.config/looking-glass/client.ini"
13921394 if [[ -f " $lg_config " ]]; then
13931395 local raw_key=$( grep -E ' ^\s*escapeKey\s*=' " $lg_config " | sed ' s/^.*=\s*//' | tr -d ' "' )
13941396 case " $raw_key " in
13951397 KEY_SCROLLLOCK | 71) escape_key=" Scroll Lock" ;;
13961398 KEY_RIGHTCTRL | 97) escape_key=" Right Ctrl" ;;
13971399 KEY_LEFTCTRL | 29) escape_key=" Left Ctrl" ;;
1398- * ) escape_key=" ${raw_key:- Right Ctrl } " ;;
1400+ * ) escape_key=" ${raw_key:- Scroll Lock } " ;;
13991401 esac
14001402 fi
14011403
@@ -1406,9 +1408,9 @@ connect_looking_glass() {
14061408
14071409 while [[ " $ELAPSED " -lt " $MAX_WAIT " ]]; do
14081410 # Check socket and fix permissions if needed
1409- if sudo test -S " $SPICE_SOCKET_PATH " 2> /dev/null; then
1410- sudo chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
1411- sudo chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
1411+ if sudo -n test -S " $SPICE_SOCKET_PATH " 2> /dev/null; then
1412+ sudo -n chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
1413+ sudo -n chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
14121414 fi
14131415
14141416 if timeout 1 env SOCKET_PATH=" $SPICE_SOCKET_PATH " python3 -c " import socket, os; s=socket.socket(socket.AF_UNIX); s.connect(os.environ['SOCKET_PATH'])" 2> /dev/null; then
@@ -1435,13 +1437,16 @@ connect_looking_glass() {
14351437 sleep 3
14361438
14371439 # Launch Looking Glass client in background (hide logs, immune to Ctrl+C)
1440+ local lg_args=" -F"
1441+ [[ " $WINDOWED " == true ]] && lg_args=" win:fullScreen=no"
1442+
14381443 if [[ " $USE_SG_KVM " == true ]]; then
14391444 # User needs temporary kvm group access - run through sg kvm
1440- sg kvm -c " setsid uwsm-app -- looking-glass-client -F >/dev/null 2>&1" &
1445+ sg kvm -c " setsid uwsm-app -- looking-glass-client $lg_args >/dev/null 2>&1" &
14411446 LG_PID=$!
14421447 else
14431448 # Normal launch (user has direct access to /dev/kvmfr0)
1444- setsid uwsm-app -- looking-glass-client -F > /dev/null 2>&1 &
1449+ setsid uwsm-app -- looking-glass-client $lg_args > /dev/null 2>&1 &
14451450 LG_PID=$!
14461451 fi
14471452
@@ -1487,31 +1492,14 @@ launch_after_install() {
14871492 echo " VM is running - access via: http://127.0.0.1:8006"
14881493 return
14891494 fi
1490- echo " "
1491- msg_info " Launching Looking Glass..."
1492-
1493- # Check permissions
1494- local use_sg_kvm=false
1495- if [[ ! -r /dev/kvmfr0 ]]; then
1496- ensure_user_in_kvm_group
1497- local kvm_status=$?
1498- [[ " $kvm_status " -le 1 ]] && use_sg_kvm=true
1499- fi
1500-
1501- # Launch LG in windowed mode, detached (don't block)
1502- if [[ " $use_sg_kvm " == true ]]; then
1503- sg kvm -c " setsid uwsm-app -- looking-glass-client win:fullScreen=no >/dev/null 2>&1" &
1504- else
1505- setsid uwsm-app -- looking-glass-client win:fullScreen=no > /dev/null 2>&1 &
1506- fi
1507- disown
15081495
15091496 echo " "
1510- msg_info " Windows VM is running in background"
1511- echo " → Looking Glass opened in separate window"
1512- echo " → Scroll Lock + F to toggle fullscreen"
1513- echo " → To stop VM: omarchy-windows-vm stop"
1497+ echo " Launching Looking Glass..."
1498+ echo " To stop VM: omarchy-windows-vm stop"
15141499 echo " "
1500+
1501+ # Launch via the same command that works manually, in new session
1502+ setsid " $0 " launch --lg -k --windowed > /dev/null 2>&1 &
15151503 else
15161504 echo " Launching RDP connection..."
15171505 sleep 3
@@ -2890,6 +2878,7 @@ check_passwordless_configuration() {
28902878launch_windows () {
28912879 KEEP_ALIVE=false
28922880 USE_LOOKING_GLASS=false
2881+ USE_WINDOWED=false
28932882 USER_PROVIDED_PARAMS=false
28942883
28952884 # Parse command line arguments
@@ -2905,6 +2894,11 @@ launch_windows() {
29052894 USER_PROVIDED_PARAMS=true
29062895 shift
29072896 ;;
2897+ --windowed | -w)
2898+ USE_WINDOWED=true
2899+ USER_PROVIDED_PARAMS=true
2900+ shift
2901+ ;;
29082902 * )
29092903 shift
29102904 ;;
@@ -2913,7 +2907,7 @@ launch_windows() {
29132907
29142908 check_vm_configured
29152909 check_docker_running
2916- check_passwordless_configuration
2910+ [[ " $USE_WINDOWED " != true ]] && check_passwordless_configuration
29172911
29182912 # Interactive mode if no params provided
29192913 if [[ " $USER_PROVIDED_PARAMS " == false ]]; then
@@ -3051,10 +3045,10 @@ launch_windows() {
30513045 SPICE_WAIT=0
30523046 while [[ " $SPICE_WAIT " -lt 30 ]]; do
30533047 # Check socket and fix permissions if needed
3054- if sudo test -S " $SPICE_SOCKET_PATH " 2> /dev/null; then
3048+ if sudo -n test -S " $SPICE_SOCKET_PATH " 2> /dev/null; then
30553049 msg_success " SPICE socket created"
3056- sudo chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
3057- sudo chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
3050+ sudo -n chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
3051+ sudo -n chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
30583052 break
30593053 fi
30603054 sleep 1
@@ -3071,9 +3065,9 @@ launch_windows() {
30713065 # Fix SPICE socket permissions if GPU passthrough is enabled (even if container already running)
30723066 if grep -q " vfio-pci" " $COMPOSE_FILE " 2> /dev/null; then
30733067 # Check socket and fix permissions if needed
3074- if sudo test -S " $SPICE_SOCKET_PATH " 2> /dev/null && [[ ! -r " $SPICE_SOCKET_PATH " ]]; then
3075- sudo chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
3076- sudo chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
3068+ if sudo -n test -S " $SPICE_SOCKET_PATH " 2> /dev/null && [[ ! -r " $SPICE_SOCKET_PATH " ]]; then
3069+ sudo -n chmod 660 " $SPICE_SOCKET_PATH " 2> /dev/null || true
3070+ sudo -n chgrp kvm " $SPICE_SOCKET_PATH " 2> /dev/null || true
30773071 fi
30783072 fi
30793073
@@ -3120,7 +3114,7 @@ launch_windows() {
31203114 fi
31213115
31223116 if [[ " $USE_LOOKING_GLASS " == true ]]; then
3123- connect_looking_glass " $KEEP_ALIVE "
3117+ connect_looking_glass " $KEEP_ALIVE " " $USE_WINDOWED "
31243118
31253119 else
31263120 # Extract credentials for RDP connection
@@ -3376,6 +3370,7 @@ show_usage() {
33763370 echo " Options:"
33773371 echo " --keep-alive, -k Keep VM running after RDP closes"
33783372 echo " --looking-glass, --lg Connect via Looking Glass"
3373+ echo " --windowed, -w Start Looking Glass in windowed mode"
33793374 echo " stop Stop the running Windows VM"
33803375 echo " status Show current VM status"
33813376 echo " show-compose Display generated docker-compose.yml configuration (for testing/debugging)"
0 commit comments