diff --git a/.gitignore b/.gitignore index c000e0c..403937f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /.idea /.vscode /result +.DS_Store +**/.DS_Store diff --git a/LICENSE.md b/LICENSE.md index cab3299..19a36a7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -8,7 +8,7 @@ Due to lack of a license, it is All Rights Reserved by the original author. We have tried contacting Fmstrat about this, but they abandoned the project and did not reply nor apply an open-source license to the project. However, almost all parts of the codebase have been rewritten and all new contributions require a Contributor License Agreement ([for individuals](https://gist.github.com/oskardotglobal/35f0a72eb45fcc7087e535561383dbc5), [for legal entities](https://gist.github.com/oskardotglobal/75a8cc056e56a439fa6a1551129ae47f)) to be signed. Therefore, the below license is applied to all new contributions made to the project. -Refer to a specific file for it's respective license. +Refer to a specific file for its respective license. # GNU AFFERO GENERAL PUBLIC LICENSE diff --git a/README.md b/README.md index 8389b90..2db5aa5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ WinApps works by: - The GNU/Linux `/home` directory is accessible within Windows via the `\\tsclient\home` mount. - Integration with `Nautilus`, allowing you to right-click files to open them with specific Windows applications based on the file MIME type. - The [official taskbar widget](https://github.com/winapps-org/WinApps-Launcher) enables seamless administration of the Windows subsystem and offers an easy way to launch Windows applications. -- Microsoft Office links (e.g. ms-word://) from the host system are automatically opened in the Windows subsystem. (Note: You may need to use an [User Agent switcher](https://github.com/ray-lothian/UserAgent-Switcher/) Browser Extension and set the User-Agent to Windows, as as the Office webapps typically hide the "Open in Desktop App" option for Linux users.) +- Microsoft Office links (e.g. ms-word://) from the host system are automatically opened in the Windows subsystem. (Note: You may need to use a [User Agent Switcher](https://github.com/ray-lothian/UserAgent-Switcher/) browser extension and set the User-Agent to Windows, as the Office webapps typically hide the "Open in Desktop App" option for Linux users.) ## Supported Applications **WinApps supports *ALL* Windows applications.** @@ -398,7 +398,7 @@ RDP_SCALE="100" # This improves compatibility with most desktop environments (DEs). # ATTENTION: The Filesystem Hierarchy Standard (FHS) recommends /media instead. Verify your system's configuration. # - To manually mount devices, you may optionally use /mnt. -# REFERRENCE: https://wiki.archlinux.org/title/Udisks#Mount_to_/media +# REFERENCE: https://wiki.archlinux.org/title/Udisks#Mount_to_/media REMOVABLE_MEDIA="/run/media" # [ADDITIONAL FREERDP FLAGS & ARGUMENTS] diff --git a/bin/winapps b/bin/winapps index f7a5c0e..306890b 100755 --- a/bin/winapps +++ b/bin/winapps @@ -107,15 +107,15 @@ Please run: notify-send --expire-time=8000 --icon="dialog-error" --app-name="WinApps" --urgency="low" "WinApps" "Windows failed to resume." ;; "$EC_FAIL_DESTROY") - dprint "ERROR: WINDOWS FAILED TO IMMEDIATELY UNGRACEFULLY SHUT DOWN WINDOWS. EXITING." - notify-send --expire-time=8000 --icon="dialog-error" --app-name="WinApps" --urgency="low" "WinApps" "Failed to ungracefully shut down Windows." + dprint "ERROR: FAILED TO FORCE STOP WINDOWS. EXITING." + notify-send --expire-time=8000 --icon="dialog-error" --app-name="WinApps" --urgency="low" "WinApps" "Failed to forcibly stop Windows." ;; "$EC_SD_TIMEOUT") dprint "ERROR: WINDOWS TOOK TOO LONG TO SHUT DOWN. EXITING." notify-send --expire-time=8000 --icon="dialog-error" --app-name="WinApps" --urgency="low" "WinApps" "Windows took too long to shut down." ;; "$EC_DIE_TIMEOUT") - dprint "ERROR: WINDOWS TOOK TOO LONG TO SHUT DOWN. EXITING." + dprint "ERROR: WINDOWS TOOK TOO LONG TO DIE. EXITING." notify-send --expire-time=8000 --icon="dialog-error" --app-name="WinApps" --urgency="low" "WinApps" "Windows took too long to die." ;; "$EC_RESTART_TIMEOUT") @@ -158,7 +158,7 @@ function dprint() { [ "$DEBUG" = "true" ] && echo "[$(date)-$RUNID] $1" >>"$LOG_PATH" } # Name: 'waFixRemovableMedia' -# Role: If user left REMOVABLE_MEDIA config null,fallback to /run/media for udisks defaults ,warning. +# Role: If REMOVABLE_MEDIA is empty, default to /run/media (udisks default) and show a warning. function waFixRemovableMedia() { if [ -z "$REMOVABLE_MEDIA" ]; then REMOVABLE_MEDIA="/run/media" # Default for udisks @@ -301,9 +301,10 @@ function waGetFreeRDPCommand() { function waCheckGroupMembership() { # Identify groups the current user belongs to. # shellcheck disable=SC2155 # Silence warnings regarding masking return values through simultaneous declaration and assignment. - local USER_GROUPS=$(groups "$(whoami)") + local USER_GROUPS=$(id -nG "$(whoami)") - if ! (echo "$USER_GROUPS" | grep -q -E "\blibvirt\b") || ! (echo "$USER_GROUPS" | grep -q -E "\bkvm\b"); then + if ! echo "$USER_GROUPS" | grep -qE '\b(libvirt|libvirtd)\b' || \ + ! echo "$USER_GROUPS" | grep -qE '\bkvm\b'; then waThrowExit "$EC_NOT_IN_GROUP" fi } @@ -677,7 +678,7 @@ function waRunCommand() { +auto-reconnect \ /drive:media,"$REMOVABLE_MEDIA" \ /wm-class:"$FULL_NAME" \ - /app:program:"$WIN_EXECUTABLE",icon:"$ICON",name:$"FULL_NAME",cmd:\""$FILE_PATH"\" \ + /app:program:"$WIN_EXECUTABLE",icon:"$ICON",name:"$FULL_NAME",cmd:\""$FILE_PATH"\" \ /v:"$RDP_IP" &>/dev/null & # Capture the process ID. diff --git a/compose.yaml b/compose.yaml index 955f0fc..8888a01 100644 --- a/compose.yaml +++ b/compose.yaml @@ -44,6 +44,6 @@ services: # NOTE: 'disk1' will be mounted as the main drive. THIS DISK WILL BE FORMATTED BY DOCKER. # All following disks (disk2, ...) WILL NOT BE FORMATTED. # - /dev/disk/by-id/:/disk1 - # - dev/disk/by-id/:/disk2 + # - /dev/disk/by-id/:/disk2 # group_add: # uncomment this line and the next one for using rootless podman containers # - keep-groups # to make /dev/kvm work with podman. needs "crun" installed, "runc" will not work! Add your user to the 'kvm' group or another that can access /dev/kvm. diff --git a/docs/docker.md b/docs/docker.md index 47b1d5d..7b92b94 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -13,8 +13,8 @@ Although WinApps supports using `QEMU+KVM+libvirt` as a backend for running Wind > [!IMPORTANT] > The iptables kernel module must be loaded for folder sharing with the host to work. -> Check that the output of `lsmod | grep ip_tables` and `lsmod | grep iptable_nat` is non empty. -> If the output of one of the previous command is empty, run `echo -e "ip_tables\niptable_nat" | sudo tee /etc/modules-load.d/iptables.conf` and reboot. +> Check that the output of `lsmod | grep ip_tables` and `lsmod | grep iptable_nat` is non-empty. +> If the output of one of the previous commands is empty, run `echo -e "ip_tables\niptable_nat" | sudo tee /etc/modules-load.d/iptables.conf` and reboot. ## `Docker` ### Installation diff --git a/docs/libvirt.md b/docs/libvirt.md index 0f0ddc1..1b41038 100644 --- a/docs/libvirt.md +++ b/docs/libvirt.md @@ -46,6 +46,8 @@ Together, these components form a powerful and flexible virtualization stack, wi sudo reboot # Reboot the system to ensure the user is added to the relevant groups. ``` + Note: On NixOS, the group name for libvirt is `libvirtd` and not `libvirt`. In addition, user and group management on NixOS is handled through the Nix configuration files and not via traditional tools like `usermod`. Please see "Adding User to a group" on [this NixOS Wiki page](https://wiki.nixos.org/wiki/User_management). + Note: Due to a known bug in `rpm-ostree`, which affects various distributions such as Silverblue, Bazzite, Bluefin, Kinoite, Aurora, UCore, and others, the commands provided earlier may not properly add your user to all required groups. If the `groups $USER` command does not show your user as being part of the necessary groups, you'll need to manually add these groups to `/etc/group` if they are present in `/usr/lib/group`. To resolve this: @@ -193,7 +195,7 @@ Together, these components form a powerful and flexible virtualization stack, wi Example 1: - CPU cores share the same singular L3 cache, so this cannot be optimised. - - CPU cores utilise different L1 and L2 caches, so isolatng corresponding thread pairs will help improve performance. + - CPU cores utilise different L1 and L2 caches, so isolating corresponding thread pairs will help improve performance. - Thus, if limiting the virtual machine to a maximum of 4 threads, there are 10 possible optimal configurations: - T0+T4 - T1+T5 diff --git a/install/ExtractPrograms.ps1 b/install/ExtractPrograms.ps1 index fcfbf3d..537e94c 100644 --- a/install/ExtractPrograms.ps1 +++ b/install/ExtractPrograms.ps1 @@ -49,7 +49,7 @@ Function GetApplicationIcon { # Args: # - 'Names': An array of application names. # - 'Paths': An array of executable paths. -# - 'Source': The source of the applications (e.g. Windows Registry, Package manangers, Universal Windows Platform (UWP), etc.) +# - 'Source': The source of the applications (e.g. Windows Registry, Package managers, Universal Windows Platform (UWP), etc.) function PrintArrayData { param ( [string[]]$Names, @@ -240,7 +240,7 @@ function AppSearchUWP { PrintArrayData -Names $exeNames -Paths $exePaths -Source "uwp" } -# Name: 'AppSearchWinReg' +# Name: 'AppSearchChocolatey' # Role: Search for chocolatey shims. function AppSearchChocolatey { # Initialise empty arrays. @@ -272,7 +272,7 @@ function AppSearchChocolatey { } } -# Name: 'AppSearchWinReg' +# Name: 'AppSearchScoop' # Role: Search for scoop shims. function AppSearchScoop { # Initialise empty arrays. diff --git a/oem/install.bat b/oem/install.bat index 018c510..92bcc38 100644 --- a/oem/install.bat +++ b/oem/install.bat @@ -1,25 +1,66 @@ @echo off +title WinApps Setup Wizard -reg import %~dp0\RDPApps.reg - -if exists %~dp0\Container.reg ( - reg import %~dp0\Container.reg +REM Check for administrative privileges +fltmc >nul 2>&1 || ( + echo [INFO] Script not running as administrator. Attempting to relaunch with elevation... + powershell -Command "Start-Process '%~f0' -Verb runAs" + exit /b 0 ) -REM Create network profile cleanup scheduled task -copy %~dp0\NetProfileCleanup.ps1 %windir% -set "taskname=NetworkProfileCleanup" -set "command=powershell.exe -ExecutionPolicy Bypass -File "%windir%\NetProfileCleanup.ps1^"" +REM Confirm the user wants to proceed with setup +echo ============================================ +echo WinApps Setup Wizard +echo ============================================ +echo. +echo Press any key to continue or close this window to cancel... +pause >nul +echo. +echo [INFO] Starting setup... -schtasks /query /tn "%taskname%" >nul 2>&1 +REM Apply RDP and system configuration tweaks +echo [INFO] Importing "RDPApps.reg"... +reg import "%~dp0RDPApps.reg" >nul 2>&1 if %ERRORLEVEL% equ 0 ( - echo Task "%taskname%" already exists, deleting it first... - schtasks /delete /tn "%taskname%" /f -) - -schtasks /create /tn "%taskname%" /tr "%command%" /sc onstart /ru "SYSTEM" /rl HIGHEST /f -if %ERRORLEVEL% equ 0 ( - echo Scheduled task "%taskname%" created successfully. + echo [SUCCESS] Imported "RDPApps.reg". ) else ( - echo Failed to create scheduled task. + echo [ERROR] Failed to import "RDPApps.reg". ) + +REM Configure the system clock to use UTC instead of local time +if exist "%~dp0Container.reg" ( + echo [INFO] Importing "Container.reg"... + reg import "%~dp0Container.reg" >nul 2>&1 + if %ERRORLEVEL% equ 0 ( + echo [SUCCESS] Imported "Container.reg". + ) else ( + echo [ERROR] Failed to import "Container.reg". + ) +) else ( + echo [WARNING] "Container.reg" not found. Skipping... +) + +REM Create a startup task to clean up stale network profiles +echo [INFO] Creating network profile cleanup task... + +REM Initialise values required to create the startup task +set "scriptpath=%windir%\NetProfileCleanup.ps1" +set "taskname=WinApps_NetworkProfileCleanup" +set "command=powershell.exe -ExecutionPolicy Bypass -File ""%scriptpath%""" + +REM Copy the script to the Windows directory +copy /Y "%~dp0NetProfileCleanup.ps1" "%scriptpath%" >nul +if %ERRORLEVEL% neq 0 ( + echo [ERROR] Failed to copy "NetProfileCleanup.ps1" to "%windir%". +) else ( + schtasks /create /tn "%taskname%" /tr "%command%" /sc onstart /ru "SYSTEM" /rl HIGHEST /f >nul 2>&1 + if %ERRORLEVEL% equ 0 ( + echo [SUCCESS] Created scheduled task "%taskname%". + ) else ( + echo [ERROR] Failed to create scheduled task "%taskname%". + ) +) + +echo. +echo Press any key to exit... +pause >nul diff --git a/packages/winapps/default.nix b/packages/winapps/default.nix index 715d071..4be5b18 100644 --- a/packages/winapps/default.nix +++ b/packages/winapps/default.nix @@ -38,7 +38,6 @@ stdenv.mkDerivation rec { ]; patches = [ - ./winapps.patch ./setup.patch ]; diff --git a/packages/winapps/setup.patch b/packages/winapps/setup.patch index b7c95fb..ed23bfb 100644 --- a/packages/winapps/setup.patch +++ b/packages/winapps/setup.patch @@ -7,9 +7,9 @@ index 0debe4d..6aeea08 100755 readonly USER_BIN_PATH_WIN='\\tsclient\home\.local\bin' # WINDOWS path to 'bin' directory for a '--user' WinApps installation. # 'SOURCE' -readonly SYS_SOURCE_PATH="${SYS_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation. --readonly USER_SOURCE_PATH="${USER_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation. +-readonly USER_SOURCE_PATH="${USER_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--user' WinApps installation. +readonly SYS_SOURCE_PATH="@out@/src" # UNIX path to WinApps source directory for a '--system' WinApps installation. -+readonly USER_SOURCE_PATH="@out@/src" # UNIX path to WinApps source directory for a '--system' WinApps installation. ++readonly USER_SOURCE_PATH="@out@/src" # UNIX path to WinApps source directory for a '--user' WinApps installation. # 'APP' readonly SYS_APP_PATH="/usr/share/applications" # UNIX path to 'applications' directory for a '--system' WinApps installation. readonly USER_APP_PATH="${HOME}/.local/share/applications" # UNIX path to 'applications' directory for a '--user' WinApps installation. diff --git a/packages/winapps/winapps.patch b/packages/winapps/winapps.patch deleted file mode 100644 index 478d0ac..0000000 --- a/packages/winapps/winapps.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/bin/winapps -+++ b/bin/winapps -@@ -295,7 +295,7 @@ function waCheckGroupMembership() { - # shellcheck disable=SC2155 # Silence warnings regarding masking return values through simultaneous declaration and assignment. - local USER_GROUPS=$(groups "$(whoami)") - -- if ! (echo "$USER_GROUPS" | grep -q -E "\blibvirt\b") || ! (echo "$USER_GROUPS" | grep -q -E "\bkvm\b"); then -+ if ! (echo "$USER_GROUPS" | grep -q -E "\blibvirtd\b") || ! (echo "$USER_GROUPS" | grep -q -E "\bkvm\b"); then - waThrowExit "$EC_NOT_IN_GROUP" - fi - } diff --git a/setup.sh b/setup.sh index 7b77254..d514bcc 100755 --- a/setup.sh +++ b/setup.sh @@ -21,7 +21,7 @@ readonly EC_BAD_ARGUMENT="2" # Unsupported argument passed to script. readonly EC_EXISTING_INSTALL="3" # Existing conflicting WinApps installation. readonly EC_NO_CONFIG="4" # Absence of a valid WinApps configuration file. readonly EC_MISSING_DEPS="5" # Missing dependencies. -readonly EC_NO_SUDO="6" # Insufficient privilages to invoke superuser access. +readonly EC_NO_SUDO="6" # Insufficient privileges to invoke superuser access. readonly EC_NOT_IN_GROUP="7" # Current user not in group 'libvirt' and/or 'kvm'. readonly EC_VM_OFF="8" # Windows 'libvirt' VM powered off. readonly EC_VM_PAUSED="9" # Windows 'libvirt' VM paused. @@ -40,7 +40,7 @@ readonly USER_BIN_PATH="${HOME}/.local/bin" # UNIX path to 'bin' dir readonly USER_BIN_PATH_WIN='\\tsclient\home\.local\bin' # WINDOWS path to 'bin' directory for a '--user' WinApps installation. # 'SOURCE' readonly SYS_SOURCE_PATH="${SYS_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation. -readonly USER_SOURCE_PATH="${USER_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation. +readonly USER_SOURCE_PATH="${USER_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--user' WinApps installation. # 'APP' readonly SYS_APP_PATH="/usr/share/applications" # UNIX path to 'applications' directory for a '--system' WinApps installation. readonly USER_APP_PATH="${HOME}/.local/share/applications" # UNIX path to 'applications' directory for a '--user' WinApps installation. @@ -151,7 +151,7 @@ function waGetSourceCode() { SCRIPT_DIR_PATH=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")") # Check if winapps is currently installed on $SOURCE_PATH - if [[ -f "$SCRIPT_DIR_PATH/winapps" && "$SCRIPT_DIR_PATH" -ne "$SOURCE_PATH" ]]; then + if [[ -f "$SCRIPT_DIR_PATH/winapps" && "$SCRIPT_DIR_PATH" != "$SOURCE_PATH" ]]; then # Display a warning. echo -e "${WARNING_TEXT}[WARNING]${CLEAR_TEXT} You are running a WinApps installation located outside of default location '${SOURCE_PATH}'. A new installation will be created." echo -e "${WARNING_TEXT}[WARNING]${CLEAR_TEXT} You might want to remove your old installation on '${SCRIPT_DIR_PATH}'." @@ -1156,7 +1156,7 @@ function waFindInstalled() { echo "IF EXIST \"${WIN_EXECUTABLE}\" ECHO ${APPLICATION} >> ${TMP_INST_FILE_PATH_WIN}" >>"$BATCH_SCRIPT_PATH" done - # Append a command to the batch script to run the PowerShell script and store it's output in the 'detected' file. + # Append a command to the batch script to run the PowerShell script and store its output in the 'detected' file. # shellcheck disable=SC2129 # Silence warning regarding repeated redirects. echo "powershell.exe -ExecutionPolicy Bypass -File ${PS_SCRIPT_HOME_PATH_WIN} > ${DETECTED_FILE_PATH_WIN}" >>"$BATCH_SCRIPT_PATH" @@ -1279,7 +1279,7 @@ function waConfigureApp() { # Source 'Info' File Containing: # - The Application Name (FULL_NAME) - # - The Shortcut Nsame (NAME) + # - The Shortcut Name (NAME) # - Application Categories (CATEGORIES) # - Executable Path (WIN_EXECUTABLE) # - Supported MIME Types (MIME_TYPES) @@ -1379,7 +1379,7 @@ function waConfigureApps() { for OSA in "${OSA_LIST[@]}"; do # Source 'Info' File Containing: # - The Application Name (FULL_NAME) - # - The Shortcut Nsame (NAME) + # - The Shortcut Name (NAME) # - Application Categories (CATEGORIES) # - Executable Path (WIN_EXECUTABLE) # - Supported MIME Types (MIME_TYPES)