diff --git a/Configs/.local/bin/hyde-shell b/Configs/.local/bin/hyde-shell
index aaf5c19cc0..72e6d28675 100755
--- a/Configs/.local/bin/hyde-shell
+++ b/Configs/.local/bin/hyde-shell
@@ -532,8 +532,18 @@ export BIN_DIR LIB_DIR SHARE_DIR PATH HYDE_SCRIPTS_PATH
#*--------------------------------------------------------------------------------
+if [[ -z "${XDG_RUNTIME_DIR:-}" ]]; then
+ if [[ "$(uname -s)" == "FreeBSD" ]]; then
+ export XDG_RUNTIME_DIR="/tmp/runtime-$(id -u)"
+ else
+ export XDG_RUNTIME_DIR="/run/user/$(id -u)"
+ fi
+fi
+[[ -d "${XDG_RUNTIME_DIR}" ]] || mkdir -p "${XDG_RUNTIME_DIR}"
+chmod 700 "${XDG_RUNTIME_DIR}" 2>/dev/null || true
+
# Prepare runtime directory for hyde
-[[ -d "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/hyde" ]] || mkdir -p "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/hyde"
+[[ -d "${XDG_RUNTIME_DIR}/hyde" ]] || mkdir -p "${XDG_RUNTIME_DIR}/hyde"
# Priority commands
case "$1" in
diff --git a/Configs/.local/lib/hyde/globalcontrol.sh b/Configs/.local/lib/hyde/globalcontrol.sh
index 59c5e638f3..8ec4a80e6a 100755
--- a/Configs/.local/lib/hyde/globalcontrol.sh
+++ b/Configs/.local/lib/hyde/globalcontrol.sh
@@ -3,7 +3,15 @@ export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
-export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
+if [[ -z "${XDG_RUNTIME_DIR:-}" ]]; then
+ if [[ "$(uname -s)" == "FreeBSD" ]]; then
+ export XDG_RUNTIME_DIR="/tmp/runtime-$(id -u)"
+ else
+ export XDG_RUNTIME_DIR="/run/user/$(id -u)"
+ fi
+fi
+[[ -d "${XDG_RUNTIME_DIR}" ]] || mkdir -p "${XDG_RUNTIME_DIR}"
+chmod 700 "${XDG_RUNTIME_DIR}" 2>/dev/null || true
export HYDE_CONFIG_HOME="$XDG_CONFIG_HOME/hyde"
export HYDE_DATA_HOME="$XDG_DATA_HOME/hyde"
export HYDE_CACHE_HOME="$XDG_CACHE_HOME/hyde"
@@ -178,6 +186,7 @@ get_themes() {
unset thmSort
unset thmList
unset thmWall
+ [ -d "$HYDE_CONFIG_HOME/themes" ] || return 0
while read -r thmDir; do
local realWallPath
realWallPath="$(readlink "$thmDir/wall.set")"
@@ -215,7 +224,7 @@ case "$enableWallDcol" in
esac
if [ -z "$HYDE_THEME" ] || [ ! -d "$HYDE_CONFIG_HOME/themes/$HYDE_THEME" ]; then
get_themes
- HYDE_THEME="${thmList[0]}"
+ [ "${#thmList[@]}" -gt 0 ] && HYDE_THEME="${thmList[0]}"
fi
HYDE_THEME_DIR="$HYDE_CONFIG_HOME/themes/$HYDE_THEME"
WALLBASH_DIRS=(
diff --git a/Configs/.local/lib/hyde/pm.sh b/Configs/.local/lib/hyde/pm.sh
index 75ddc2145e..2ea285c61e 100755
--- a/Configs/.local/lib/hyde/pm.sh
+++ b/Configs/.local/lib/hyde/pm.sh
@@ -207,7 +207,7 @@ skip_table_header() {
xargs_self() {
xargs -r sh -c '"$0" "$@" /dev/null || pkg search -x "$1"
+}
+pkg_list_all() {
+ pkg rquery '%n %v'
+}
+pkg_list_installed() {
+ pkg query '%n %v'
+}
+pkg_format_all() {
+ awk "{ print $FMT_NAME \$1 $FMT_VERSION \$2 $FMT_RESET }"
+}
+pkg_format_installed() {
+ awk "{ print $FMT_NAME \$1 $FMT_VERSION \$2 $FMT_RESET }"
+}
+pkg_is_installed() {
+ pkg info -e "$1" > /dev/null 2>&1 && echo "Installed" || {
+ echo "Not installed" && return 1
+ }
+}
+pkg_file_query() {
+ pkg which "$1"
+}
AUR_HELPERS="paru paru-bin yay yay-bin"
aur_helpers_contain() {
for NAME in $AUR_HELPERS; do
diff --git a/Configs/.local/lib/hyde/pyutils/pip_env.py b/Configs/.local/lib/hyde/pyutils/pip_env.py
index 2562e248af..cf8c645a6a 100644
--- a/Configs/.local/lib/hyde/pyutils/pip_env.py
+++ b/Configs/.local/lib/hyde/pyutils/pip_env.py
@@ -20,7 +20,7 @@
def is_venv_valid(venv_path):
"""Returns whether the venv is valid or not
-
+
Args:
venv_path: Path to the virtual environment to validate
"""
@@ -32,8 +32,8 @@ def is_venv_valid(venv_path):
# 1.- Must have its own python file and it must be executable
if not (os.path.isfile(python_exe) and os.access(python_exe, os.X_OK)):
return False
-
- # 2.- Python inside venv must be able to import pip
+
+ # 2.- Python inside venv must be able to import pip
try:
res = subprocess.run(
[python_exe, "-c", "import pip"],
@@ -45,7 +45,7 @@ def is_venv_valid(venv_path):
return False
except Exception:
return False
-
+
# 3.- Python version used to create the venv must match current one
if os.path.exists(pyvenv_cfg):
try:
@@ -345,9 +345,12 @@ def main(args):
args = parser.parse_args(args)
venv_path = get_venv_path()
- requirements_file = os.path.join(
- xdg_base_dirs.user_lib_dir(), "hyde", "pyutils", "requirements.txt"
- )
+ requirements_dir = os.path.join(xdg_base_dirs.user_lib_dir(), "hyde", "pyutils")
+ requirements_file = os.path.join(requirements_dir, "requirements.txt")
+ if sys.platform.startswith("freebsd"):
+ freebsd_requirements = os.path.join(requirements_dir, "requirements-freebsd.txt")
+ if os.path.exists(freebsd_requirements):
+ requirements_file = freebsd_requirements
if args.command == "create":
args.func(venv_path, requirements_file)
diff --git a/Configs/.local/lib/hyde/pyutils/requirements-freebsd.txt b/Configs/.local/lib/hyde/pyutils/requirements-freebsd.txt
new file mode 100644
index 0000000000..521d7770dd
--- /dev/null
+++ b/Configs/.local/lib/hyde/pyutils/requirements-freebsd.txt
@@ -0,0 +1,4 @@
+loguru==0.7.3
+pulsectl==24.12.0
+requests==2.32.4
+PyGObject
diff --git a/Configs/.local/lib/hyde/resetxdgportal.sh b/Configs/.local/lib/hyde/resetxdgportal.sh
index a955a2fa91..6e9e6c8b9a 100755
--- a/Configs/.local/lib/hyde/resetxdgportal.sh
+++ b/Configs/.local/lib/hyde/resetxdgportal.sh
@@ -6,6 +6,8 @@ killall -e xdg-desktop-portal
sleep 1
if [ -d /run/current-system/sw/libexec ]; then
libDir=/run/current-system/sw/libexec
+elif [ -d /usr/local/libexec ]; then
+ libDir=/usr/local/libexec
else
libDir=/usr/lib
fi
diff --git a/Configs/.local/lib/hyde/theme.switch.sh b/Configs/.local/lib/hyde/theme.switch.sh
index c652124351..c7e91239a2 100755
--- a/Configs/.local/lib/hyde/theme.switch.sh
+++ b/Configs/.local/lib/hyde/theme.switch.sh
@@ -3,6 +3,13 @@
[ -z "$HYDE_THEME" ] && echo "ERROR: unable to detect theme" && exit 1
get_themes
confDir="${XDG_CONFIG_HOME:-$HOME/.config}"
+sed_in_place() {
+ if sed --version >/dev/null 2>&1; then
+ sed -i "$@"
+ else
+ sed -i '' "$@"
+ fi
+}
Theme_Change() {
local x_switch=$1
for i in "${!thmList[@]}"; do
@@ -85,7 +92,7 @@ sanitize_hypr_theme() {
dirty_regex+=("${HYPR_CONFIG_SANITIZE[@]}")
for pattern in "${dirty_regex[@]}"; do
grep -E "$pattern" "$buffer_file" | while read -r line; do
- sed -i "\|$line|d" "$buffer_file"
+ sed_in_place "\|$line|d" "$buffer_file"
print_log -sec "theme" -warn "sanitize" "$line"
done
done
@@ -130,8 +137,12 @@ if [[ -r $HYPRLAND_CONFIG ]]; then
load_hypr_variables "${XDG_STATE_DIR:-$HOME/.local/state}/hyde/hyprland.conf"
fi
show_theme_status
-if ! dconf write /org/gnome/desktop/interface/icon-theme "'$ICON_THEME'"; then
- print_log -sec "theme" -warn "dconf" "failed to set icon theme"
+if command -v dconf >/dev/null 2>&1 && { [[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]] || [[ -n "${DISPLAY:-}" ]]; }; then
+ if ! dconf write /org/gnome/desktop/interface/icon-theme "'$ICON_THEME'"; then
+ print_log -sec "theme" -warn "dconf" "failed to set icon theme"
+ fi
+else
+ print_log -sec "theme" -warn "dconf" "no active DBus session; skipping icon theme write"
fi
if [ -d /run/current-system/sw/share/themes ]; then
export themesDir=/run/current-system/sw/share/themes
@@ -159,10 +170,10 @@ toml_write "$confDir/kdeglobals" "UiSettings" "ColorScheme" "colors"
toml_write "$confDir/kdeglobals" "KDE" "widgetStyle" "kvantum"
toml_write "$XDG_DATA_HOME/icons/default/index.theme" "Icon Theme" "Inherits" "$CURSOR_THEME"
toml_write "$HOME/.icons/default/index.theme" "Icon Theme" "Inherits" "$CURSOR_THEME"
-sed -i -e "/^gtk-theme-name=/c\gtk-theme-name=\"$GTK_THEME\"" \
- -e "/^include /c\include \"$HOME/.gtkrc-2.0.mime\"" \
- -e "/^gtk-cursor-theme-name=/c\gtk-cursor-theme-name=\"$CURSOR_THEME\"" \
- -e "/^gtk-icon-theme-name=/c\gtk-icon-theme-name=\"$ICON_THEME\"" "$HOME/.gtkrc-2.0"
+sed_in_place -e "s|^gtk-theme-name=.*$|gtk-theme-name=\"$GTK_THEME\"|" \
+ -e "s|^include .*$|include \"$HOME/.gtkrc-2.0.mime\"|" \
+ -e "s|^gtk-cursor-theme-name=.*$|gtk-cursor-theme-name=\"$CURSOR_THEME\"|" \
+ -e "s|^gtk-icon-theme-name=.*$|gtk-icon-theme-name=\"$ICON_THEME\"|" "$HOME/.gtkrc-2.0"
GTK3_FONT="${GTK3_FONT:-$FONT}"
GTK3_FONT_SIZE="${GTK3_FONT_SIZE:-$FONT_SIZE}"
toml_write "$confDir/gtk-3.0/settings.ini" "Settings" "gtk-theme-name" "$GTK_THEME"
@@ -193,10 +204,10 @@ if pkg_installed flatpak; then
--env=ICON_THEME="$ICON_THEME"
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo &
fi
-sed -i -e "/^Net\/ThemeName /c\Net\/ThemeName \"$GTK_THEME\"" \
- -e "/^Net\/IconThemeName /c\Net\/IconThemeName \"$ICON_THEME\"" \
- -e "/^Gtk\/CursorThemeName /c\Gtk\/CursorThemeName \"$CURSOR_THEME\"" \
- -e "/^Gtk\/CursorThemeSize /c\Gtk\/CursorThemeSize $CURSOR_SIZE" \
+sed_in_place -e "s|^Net/ThemeName .*$|Net/ThemeName \"$GTK_THEME\"|" \
+ -e "s|^Net/IconThemeName .*$|Net/IconThemeName \"$ICON_THEME\"|" \
+ -e "s|^Gtk/CursorThemeName .*$|Gtk/CursorThemeName \"$CURSOR_THEME\"|" \
+ -e "s|^Gtk/CursorThemeSize .*$|Gtk/CursorThemeSize $CURSOR_SIZE|" \
"$confDir/xsettingsd/xsettingsd.conf"
if [ ! -L "$HOME/.themes/$GTK_THEME" ] && [ -d "$themesDir/$GTK_THEME" ]; then
print_log -sec "theme" -warn "linking" "$GTK_THEME to ~/.themes to fix GTK4 not following xdg"
@@ -205,8 +216,8 @@ if [ ! -L "$HOME/.themes/$GTK_THEME" ] && [ -d "$themesDir/$GTK_THEME" ]; then
ln -snf "$themesDir/$GTK_THEME" "$HOME/.themes/"
fi
if [ -f "$HOME/.Xresources" ]; then
- sed -i -e "/^Xcursor\.theme:/c\Xcursor.theme: $CURSOR_THEME" \
- -e "/^Xcursor\.size:/c\Xcursor.size: $CURSOR_SIZE" "$HOME/.Xresources"
+ sed_in_place -e "s|^Xcursor\.theme:.*$|Xcursor.theme: $CURSOR_THEME|" \
+ -e "s|^Xcursor\.size:.*$|Xcursor.size: $CURSOR_SIZE|" "$HOME/.Xresources"
grep -q "^Xcursor\.theme:" "$HOME/.Xresources" || echo "Xcursor.theme: $CURSOR_THEME" >>"$HOME/.Xresources"
grep -q "^Xcursor\.size:" "$HOME/.Xresources" || echo "Xcursor.size: 30" >>"$HOME/.Xresources"
else
@@ -216,8 +227,8 @@ Xcursor.size: $CURSOR_SIZE
EOF
fi
if [ -f "$HOME/.Xdefaults" ]; then
- sed -i -e "/^Xcursor\.theme:/c\Xcursor.theme: $CURSOR_THEME" \
- -e "/^Xcursor\.size:/c\Xcursor.size: $CURSOR_SIZE" "$HOME/.Xdefaults"
+ sed_in_place -e "s|^Xcursor\.theme:.*$|Xcursor.theme: $CURSOR_THEME|" \
+ -e "s|^Xcursor\.size:.*$|Xcursor.size: $CURSOR_SIZE|" "$HOME/.Xdefaults"
grep -q "^Xcursor\.theme:" "$HOME/.Xdefaults" || echo "Xcursor.theme: $CURSOR_THEME" >>"$HOME/.Xdefaults"
grep -q "^Xcursor\.size:" "$HOME/.Xdefaults" || echo "Xcursor.size: 30" >>"$HOME/.Xdefaults"
fi
diff --git a/Configs/.local/lib/hyde/waybar.py b/Configs/.local/lib/hyde/waybar.py
index 8cc598226b..50e03981a6 100755
--- a/Configs/.local/lib/hyde/waybar.py
+++ b/Configs/.local/lib/hyde/waybar.py
@@ -68,6 +68,7 @@
STATE_FILE = Path(os.path.join(str(xdg_state_home()), "hyde", "staterc"))
HYDE_CONFIG = Path(os.path.join(str(xdg_state_home()), "hyde", "config"))
UNIT_NAME = f"hyde-{os.environ.get('XDG_SESSION_DESKTOP', 'unknown')}-bar.service"
+HAS_SYSTEMCTL = shutil.which("systemctl") is not None
def source_env_file(filepath):
@@ -500,6 +501,10 @@ def signal_handler(sig, frame):
def is_waybar_running_for_current_user():
"""Check if Waybar or Waybar-wrapped is running for the current user only."""
+ if not HAS_SYSTEMCTL:
+ result = subprocess.run(["pgrep", "-x", "waybar"], capture_output=True, text=True)
+ return result.returncode == 0
+
check_cmd = ["systemctl", "--user", "is-active", UNIT_NAME]
try:
result = subprocess.run(check_cmd, capture_output=True, text=True)
@@ -514,6 +519,14 @@ def is_waybar_running_for_current_user():
def run_waybar():
"""Run Waybar using hyde-shell app with systemd unit, let systemd handle logging."""
+ if not HAS_SYSTEMCTL:
+ if not is_waybar_running_for_current_user():
+ subprocess.Popen(["waybar"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ logger.debug("Waybar launched directly (no systemctl available)")
+ else:
+ logger.debug("Waybar already running (direct mode)")
+ return
+
# check_cmd = ["systemctl", "--user", "is-active", "--quiet", UNIT_NAME]
run_cmd = ["hyde-shell", "app", "-u", UNIT_NAME, "-t", "service", "--", "waybar"]
# Check if the unit is active
@@ -528,6 +541,11 @@ def run_waybar():
def kill_waybar():
"""Kill only the current user's Waybar process."""
"""Stop Waybar systemd unit for current session desktop."""
+ if not HAS_SYSTEMCTL:
+ subprocess.run(["pkill", "-x", "waybar"])
+ logger.debug("Stopped Waybar process directly (no systemctl available)")
+ return
+
subprocess.run(["systemctl", "--user", "stop", UNIT_NAME])
logger.debug(f"Stopped Waybar systemd unit: {UNIT_NAME}")
@@ -544,6 +562,9 @@ def kill_waybar_and_watcher():
kill_waybar()
logger.debug("Killed Waybar processes for current user.")
+ if not HAS_SYSTEMCTL:
+ return
+
try:
watcher_unit = f"hyde-{os.getenv('XDG_SESSION_DESKTOP')}-waybar-watcher.service"
result = subprocess.run(
@@ -1441,8 +1462,12 @@ def main():
if args.hide:
# Send SIGUSR1 to Waybar systemd unit
- cmd = ["systemctl", "--user", "kill", "-s", "SIGUSR1", UNIT_NAME]
- logger.info(f"Sending SIGUSR1 to {UNIT_NAME} via systemctl")
+ if HAS_SYSTEMCTL:
+ cmd = ["systemctl", "--user", "kill", "-s", "SIGUSR1", UNIT_NAME]
+ logger.info(f"Sending SIGUSR1 to {UNIT_NAME} via systemctl")
+ else:
+ cmd = ["pkill", "-USR1", "-x", "waybar"]
+ logger.info("Sending SIGUSR1 to waybar directly (no systemctl)")
subprocess.run(cmd)
sys.exit(0)
diff --git a/README.md b/README.md
index ac7be2fd14..0620590eca 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ Multi-language README support
+
@@ -73,6 +74,8 @@ While installing HyDE alongside another [DE](https://wiki.archlinux.org/title/De
For NixOS support there is a separate project being maintained @ [Hydenix](https://github.com/richen604/hydenix/tree/main)
+[FreeBSD](https://www.freebsd.org) is supported via HydeBSD. Due to differences in bootloader, kernel, userspace, and package availability, not all features of HyDE may be present.
+
> [!IMPORTANT]
> The install script will auto-detect an NVIDIA card and install nvidia-open-dkms drivers for your kernel.
> For legacy cards [check this first](./Scripts/nvidia-db/)
diff --git a/Scripts/global_fn.sh b/Scripts/global_fn.sh
index 922b729497..461935a22d 100755
--- a/Scripts/global_fn.sh
+++ b/Scripts/global_fn.sh
@@ -23,8 +23,19 @@ export shlList
pkg_installed() {
local PkgIn=$1
+ local PkgResolved
- if pacman -Q "${PkgIn}" &>/dev/null; then
+ case "${PkgIn}" in
+ kvantum) PkgResolved="Kvantum" ;;
+ imagemagick) PkgResolved="ImageMagick7" ;;
+ *) PkgResolved="${PkgIn}" ;;
+ esac
+
+ if [[ "${PkgIn}" == "zsh-theme-powerlevel10k" ]] && [[ -d "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k" ]]; then
+ return 0
+ fi
+
+ if "${pacmanCmd}" query "${PkgResolved}" &>/dev/null; then
return 0
else
return 1
diff --git a/Scripts/hydevm/README.md b/Scripts/hydevm/README.md
index 8b34c504ae..7491a920c8 100644
--- a/Scripts/hydevm/README.md
+++ b/Scripts/hydevm/README.md
@@ -4,10 +4,12 @@ HydeVM is a streamlined development tool that automatically sets up HyDE in a vi
- [HydeVM - Simplified VM Tool for HyDE Contributors](#hydevm---simplified-vm-tool-for-hyde-contributors)
- [Hardware Requirements](#hardware-requirements)
+ - [Hardware Requirements - FreeBSD](#hardware-requirements---freebsd)
- [Features](#features)
- [Quick Start](#quick-start)
- [Arch Linux](#arch-linux)
- [NixOS](#nixos)
+ - [FreeBSD](#freebsd)
- [First-Time Setup](#first-time-setup)
- [Usage](#usage)
- [Basic Commands](#basic-commands)
@@ -28,9 +30,9 @@ HydeVM is a streamlined development tool that automatically sets up HyDE in a vi
- [Verification Steps](#verification-steps)
- [Troubleshooting Hyprland in VM](#troubleshooting-hyprland-in-vm)
-**Supported Host Operating Systems:** Arch Linux, NixOS
+**Supported Host Operating Systems:** Arch Linux, NixOS, FreeBSD, macOS Silicon
-## Hardware Requirements
+## Hardware Requirements (non macOS)
**CPU:** x86_64 with virtualization support (Intel VT-x or AMD-V, enabled in BIOS)
**Memory:** 4GB+ RAM (VM uses 4GB by default)
@@ -43,6 +45,22 @@ HydeVM is a streamlined development tool that automatically sets up HyDE in a vi
**OpenGL:** 3.3+ support required for Hyprland
**Note:** Tested on AMD GPU + Intel CPU. Hyprland VM support is experimental.
+### Hardware Requirements - FreeBSD
+
+**CPU:** `x86_64/amd64` machines require `EPT` if *Intel* or `RVI/NPT` if AMD
+
+**GPU & OpenGL Support:** From [Chapter 5.2. Graphics Drivers - FreeBSD Handbook](https://docs.freebsd.org/en/books/handbook/x11/#x-graphic-card-drivers)
+
+| *Type* | *License* | *Module* | *Port* |
+|-----------------------------|--------------|------------------------------------|-----------------------------------------------|
+| Intel® | Open Source | `i915kms` | `graphics/drm-kmod` |
+| AMD® | Open Source | `amdgpu` / `radeonkms` | `graphics/drm-kmod` |
+| NVIDIA® | Proprietary | `nvidia-drm` / `nvidia-modeset` / `nvidia` | `graphics/nvidia-drm-kmod`, `x11/nvidia-driver` |
+| System Console Framebuffer | Open Source | `scfb` | `x11-drivers`/`xf86-video-scfb` |
+| VESA BIOS Extension | Open Source | `vesa` | `x11-drivers`/`xf86-video-vesa` |
+| VirtualBox® | Open Source | `vboxvideo` | `emulators`/`virtualbox-ose-additions` |
+| VMware® | Open Source | `vmwgfx` | `x11-drivers`/`xf86-video-vmware` |
+
## Features
- **Zero Configuration**: Automatically downloads Arch Linux base image and sets up HyDE
@@ -53,7 +71,7 @@ HydeVM is a streamlined development tool that automatically sets up HyDE in a vi
## Quick Start
-### Arch Linux
+### Arch Linux, FreeBSD, and macOS Silicon
```bash
# Download and run (will auto-detect missing packages)
@@ -77,7 +95,7 @@ nix run
When you run a new branch/commit for the first time, hydevm will:
1. **OS Detection**: Automatically detects your OS and checks dependencies
-2. **Dependency Installation**: (Arch only) Prompts to install missing packages
+2. **Dependency Installation**: (Arch & FreeBSD only) Prompts to install missing packages
3. **VM Setup**: Shows a VM window with setup instructions
4. **HyDE Installation**: You'll need to:
- Login as `arch` / `arch`
@@ -116,7 +134,7 @@ hydevm --clean
# Check dependencies
hydevm --check-deps
-# Install dependencies (Arch only)
+# Install dependencies (Arch & FreeBSD only)
hydevm --install-deps
```
@@ -154,10 +172,53 @@ sudo usermod -a -G kvm $USER
virtualisation.libvirtd.enable = true;
```
+### FreeBSD - command not found: qemu
+> [!NOTE]
+> Adopted from [Chapter 24.6. Virtualization with QEMU on FreeBSD](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-virtualization-host-guest) by @MFarabi619
+
+```bash
+# modified to not override pre-existing ones, and restore broken setups to a working default from handbook as of March 21, 2026, 1:34 PM
+sudo pkg install qemu
+
+# checks if symlink doesn't exist or points to the wrong location
+if [ "$(readlink /usr/local/bin/qemu)" != "/usr/local/bin/qemu-system-x86_64" ]; then
+ sudo ln -sf /usr/local/bin/qemu-system-x86_64 /usr/local/bin/qemu
+fi
+
+sudo sysctl net.link.tap.user_open=1
+sudo grep -qxF "net.link.tap.user_open=1" /etc/sysctl.conf || \
+echo 'net.link.tap.user_open=1' | sudo tee -a /etc/sysctl.conf
+sudo grep -qxF "add path 'tap*' mode 0660 group operator" /etc/devfs.rules || \
+printf "add path 'tap*' mode 0660 group operator\n" | sudo tee -a /etc/devfs.rules
+
+# should show window saying boot failed .... no bootable device, proves that qemu is working as intended
+qemu
+```
+
+#### FreeBSD - [Bhyve](https://bhyve.org)
+> [!NOTE]
+> Adopted from [Chapter 24.6. Virtualization with QEMU on FreeBSD](https://docs.freebsd.org/en/books/handbook/virtualization/#virtualization-host-bhyve) by @MFarabi619
+
+```bash
+sudo kldload vmm
+
+sudo ifconfig tap0 create
+sudo sysctl net.link.tap.up_on_open=1
+sudo grep -qxF "net.link.tap.up_on_open=1" /etc/sysctl.conf || \
+echo 'net.link.tap.up_on_open=1' | sudo tee -a /etc/sysctl.conf
+sudo grep -qxF "add path 'tap*' mode 0660 group operator" /etc/devfs.rules || \
+printf "add path 'tap*' mode 0660 group operator\n" | sudo tee -a /etc/devfs.rules
+
+sudo ifconfig bridge0 create
+sudo ifconfig bridge0 addm igb0 addm tap0
+sudo ifconfig bridge0 up
+```
+
### Missing Dependencies
- **Arch**: Script will prompt to install missing packages
- **NixOS**: Nix will automatically install missing packages
+- **FreeBSD**: Script will prompt to install missing packages
### Clean Start
@@ -213,6 +274,7 @@ nixGL nix run github:HyDE-Project/HyDE
**Packages (Arch):** `qemu-desktop mesa`
**Packages (NixOS):** `qemu mesa`
+**Packages (FreeBSD):** `qemu drm-kmod`
**NixOS Configuration:**
@@ -241,6 +303,7 @@ hydevm
**Packages (Arch):** `qemu-desktop mesa intel-media-driver`
**Packages (NixOS):** `qemu mesa intel-media-driver`
+**Packages (FreeBSD):** `qemu drm-kmod`
**NixOS Configuration:**
@@ -265,6 +328,12 @@ lsmod | grep virtio
hydevm
```
+**FreeBSD Configuration:**
+
+```bash
+sudo pkg install qemu drm-kmod
+```
+
### NVIDIA GPU + Any CPU ⚠️
Option 1: Proprietary Drivers (May have issues)
@@ -311,6 +380,9 @@ glxinfo | grep "OpenGL renderer"
hydevm
```
+#### FreeBSD (WIP)
+TODO: cover various NVIDIA installation paths and common problems
+
Option 3: Software Rendering (Fallback)
```bash
diff --git a/Scripts/hydevm/hydevm.sh b/Scripts/hydevm/hydevm.sh
index c2ea3386dd..cbf3660ceb 100755
--- a/Scripts/hydevm/hydevm.sh
+++ b/Scripts/hydevm/hydevm.sh
@@ -1,7 +1,7 @@
-#!/bin/bash
+#!/usr/bin/env bash
# HydeVM - Simplified VM tool for HyDE contributors
-# Works on both Arch Linux and NixOS with automatic OS detection
+# Works on Arch Linux, NixOS, and FreeBSD with automatic OS detection
set -e
@@ -10,12 +10,21 @@ CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/hydevm"
BASE_IMAGE="$CACHE_DIR/archbase.qcow2"
SNAPSHOTS_DIR="$CACHE_DIR/snapshots"
HYDE_REPO="https://github.com/HyDE-Project/HyDE.git"
+
+COMMON_PACKAGES=(
+ "curl" "python" "git"
+)
+
# Required packages for Arch Linux
ARCH_PACKAGES=(
"qemu-desktop"
- "curl"
- "python"
- "git"
+ "${COMMON_PACKAGES[@]}"
+)
+
+# Required packages for FreeBSD
+FREEBSD_PACKAGES=(
+ "qemu"
+ "${COMMON_PACKAGES[@]}"
)
# Create cache directories
@@ -29,6 +38,8 @@ function detect_os() {
echo "nixos"
elif [[ "$ID" == "arch" ]]; then
echo "arch"
+ elif [[ "$ID" == "freebsd" ]]; then
+ echo "freebsd"
else
echo "unknown"
fi
@@ -36,6 +47,10 @@ function detect_os() {
echo "nixos"
elif command -v pacman >/dev/null 2>&1; then
echo "arch"
+ elif [[ "$(uname -s)" == "FreeBSD" ]]; then
+ echo "freebsd"
+ elif [[ "$(uname -s)" == "Darwin" ]]; then
+ echo "darwin"
else
echo "unknown"
fi
@@ -43,7 +58,7 @@ function detect_os() {
function print_usage() {
echo "HydeVM - Simplified VM tool for HyDE contributors"
- echo "Supports: Arch Linux, NixOS"
+ echo "Supports: Arch Linux, NixOS, FreeBSD, and Darwin"
echo ""
echo "Usage: hydevm [OPTIONS] [BRANCH/COMMIT]"
echo ""
@@ -54,7 +69,7 @@ function print_usage() {
echo " --persist Make VM changes persistent"
echo " --list List available snapshots"
echo " --clean Clean all cached data"
- echo " --install-deps Install required dependencies (Arch only)"
+ echo " --install-deps Install required dependencies (Arch, FreeBSD, Darwin)"
echo " --check-deps Check if dependencies are installed"
echo " --help Show this help"
echo ""
@@ -71,9 +86,11 @@ function print_usage() {
echo " hydevm abc123 # Run specific commit"
echo " hydevm --persist dev # Run dev branch with persistence"
echo ""
- echo "OS-specific notes:"
- echo " Arch Linux: Missing packages will be auto-detected and offered for install"
- echo " NixOS: automatically installs dependencies"
+ echo "Auto-detected OS-specific install notes:"
+ echo " Arch Linux: Missing packages will be offered for installation via 'pacman'"
+ echo " NixOS: Missing packages will be installed via 'nix shell'"
+ echo " FreeBSD: Missing packages will be installed via 'pkg'"
+ echo " Darwin : Missing packages can be installed via 'nix shell', 'brew', or direct download"
}
function check_root() {
@@ -99,8 +116,14 @@ function check_dependencies() {
"arch")
check_arch_dependencies
;;
+ "freebsd")
+ check_freebsd_dependencies
+ ;;
+ "darwin")
+ check_darwin_dependencies
+ ;;
*)
- echo "⚠️ Unsupported OS. This script supports Arch Linux and NixOS."
+ echo "⚠️ Unsupported OS. This script supports Arch Linux, NixOS, and FreeBSD."
echo " Please ensure qemu, curl, python, and git are installed."
return 0
;;
@@ -169,6 +192,255 @@ function check_arch_dependencies() {
return 0
}
+function check_freebsd_dependencies() {
+ local missing_packages=()
+
+ for package in "${FREEBSD_PACKAGES[@]}"; do
+ if ! pkg info -e "$package" > /dev/null 2>&1; then
+ missing_packages+=("$package")
+ fi
+ done
+
+ if [ ${#missing_packages[@]} -gt 0 ]; then
+ echo "❌ Missing required packages: ${missing_packages[*]}"
+ echo ""
+ read -p "Would you like to install them now? (y/N): " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ install_freebsd_packages "${missing_packages[@]}"
+ else
+ echo " You can install them manually with: sudo pkg install ${missing_packages[*]}"
+ return 1
+ fi
+ fi
+
+ # Check if qemu is available; if not, prompt for QEMU or bhyve setup
+ if ! command -v qemu >/dev/null 2>&1; then
+ cat <<'EOF'
+⚠️ Additional system setup is required (not applied automatically).
+❌ QEMU not available.
+ You can use either QEMU or bhyve on FreeBSD.
+
+ 1) QEMU
+ 2) bhyve
+
+EOF
+ read -p "Choose a virtualization backend to set up (1/2, or anything else to skip): " -r
+
+ if [[ $REPLY == "1" ]]; then
+ cat <<'EOF'
+Adopted from [Chapter 24.6. Virtualization with QEMU on FreeBSD](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-virtualization-host-guest) by @MFarabi619
+ To set up QEMU, run:
+ sudo pkg install qemu
+
+ # Fix missing or broken qemu symlink
+ if [ "$(readlink /usr/local/bin/qemu)" != "/usr/local/bin/qemu-system-x86_64" ]; then
+ sudo ln -sf /usr/local/bin/qemu-system-x86_64 /usr/local/bin/qemu
+ fi
+
+ sudo sysctl net.link.tap.user_open=1
+ sudo grep -qxF "net.link.tap.user_open=1" /etc/sysctl.conf || \
+ echo 'net.link.tap.user_open=1' | sudo tee -a /etc/sysctl.conf
+ sudo grep -qxF "add path 'tap*' mode 0660 group operator" /etc/devfs.rules || \
+ printf "add path 'tap*' mode 0660 group operator\n" | sudo tee -a /etc/devfs.rules
+
+ Then test with:
+ qemu
+EOF
+ elif [[ $REPLY == "2" ]]; then
+ cat <<'EOF'
+Adopted from [Chapter 24.6. Virtualization with bhyve on FreeBSD](https://docs.freebsd.org/en/books/handbook/virtualization/#virtualization-host-bhyve) by @MFarabi619
+ To set up bhyve, run:
+ sudo kldload vmm
+
+ sudo ifconfig tap0 create
+ sudo sysctl net.link.tap.up_on_open=1
+ sudo grep -qxF "net.link.tap.up_on_open=1" /etc/sysctl.conf || \
+ echo 'net.link.tap.up_on_open=1' | sudo tee -a /etc/sysctl.conf
+ sudo grep -qxF "add path 'tap*' mode 0660 group operator" /etc/devfs.rules || \
+ printf "add path 'tap*' mode 0660 group operator\n" | sudo tee -a /etc/devfs.rules
+
+ sudo ifconfig bridge0 create
+ sudo ifconfig bridge0 addm igb0 addm tap0
+ sudo ifconfig bridge0 up
+EOF
+ else
+ echo " Skipping virtualization backend setup."
+ fi
+ fi
+
+ # Check if /dev/vmm exists for bhyve acceleration
+if ! kldstat -q -m vmm; then
+ cat <<'EOF'
+⚠️ bhyve/VMM not available. Native FreeBSD virtualization may not work.
+ Make sure the vmm module is loaded: sudo kldload vmm
+EOF
+fi
+
+ # Check if tap access is likely unavailable for non-root users
+ if ! sysctl -n net.link.tap.user_open >/dev/null 2>&1 || [ "$(sysctl -n net.link.tap.user_open 2>/dev/null)" != "1" ]; then
+ cat <<'EOF'
+⚠️ Non-root tap access is not enabled.
+ To enable it, run: sudo sysctl net.link.tap.user_open=1
+ Then persist it in /etc/sysctl.conf.
+EOF
+ fi
+
+ return 0
+}
+
+check_darwin_dependencies() {
+ if [[ "$(uname -p 2>/dev/null || true)" != "arm" && "$(uname -p 2>/dev/null || true)" != "arm64" ]]; then
+ echo "❌ x86_64-darwin is not supported"
+ exit 1
+ fi
+
+ # NOTE: temporary UTM-first workflow for Darwin. Later we should simplify
+ # this by removing UTM and driving qemu directly.
+ if command -v utmctl >/dev/null 2>&1; then
+ echo "UTM version $(utmctl version) is installed"
+
+ if [[ "${HYDEVM_CHECK_DEPS_ONLY:-0}" == "1" ]]; then
+ echo "Supported VM guests on macOS Host: NixOS, FreeBSD"
+ return 0
+ fi
+
+ echo "Supported VM guests on macOS Host: NixOS, FreeBSD"
+ echo ""
+ echo "Choose a VM target OS:"
+ echo " 1) NixOS"
+ echo " 2) FreeBSD"
+ read -r -p "Select target OS (1/2): " reply
+
+ if [[ "$reply" == "1" ]]; then
+ HYDEVM_DARWIN_TARGET="nixos"
+ export HYDEVM_DARWIN_TARGET
+ echo "Selected target: NixOS"
+ exit 0
+ elif [[ "$reply" == "2" ]]; then
+ HYDEVM_DARWIN_TARGET="freebsd"
+ export HYDEVM_DARWIN_TARGET
+ echo "Selected target: FreeBSD"
+ exit 0
+ fi
+
+ echo "❌ Invalid selection. Please choose 1 for NixOS or 2 for FreeBSD."
+ return 1
+ fi
+
+ if command -v nix >/dev/null 2>&1; then
+ cat <<'EOF'
+❌ UTM is not installed.
+
+You can set it up with nix using:
+ nix shell nixpkgs#utm
+
+Or manually:
+1. Install UTM via https://mac.getutm.app.
+2. Install UTM via brew (requires brew): brew install --cask utm
+3. Install UTM via Determinate Nix (if needed):
+ curl -fsSL https://install.determinate.systems/nix | sh -s -- install
+ Then use a nix shell, home manager, or nix-darwin.
+
+For nix-darwin, ensure Homebrew paths are available when using Homebrew-managed UTM:
+environment.systemPath = [
+ "/usr/local/bin"
+ "/opt/homebrew/bin"
+];
+
+More info: https://nix-darwin.github.io/nix-darwin/manual/index.html#opt-homebrew.enable
+EOF
+ return 1
+ fi
+
+ if command -v brew >/dev/null 2>&1; then
+ cat <<'EOF'
+❌ UTM is not installed.
+
+Homebrew is available. Install UTM with:
+ brew install --cask utm
+
+Or manually:
+1. Install UTM via https://mac.getutm.app.
+2. Install UTM via Determinate Nix:
+ curl -fsSL https://install.determinate.systems/nix | sh -s -- install
+ Then use a nix shell, home manager, or nix-darwin.
+
+For nix-darwin, ensure Homebrew paths are available when using Homebrew-managed UTM:
+environment.systemPath = [
+ "/usr/local/bin"
+ "/opt/homebrew/bin"
+];
+
+More info: https://nix-darwin.github.io/nix-darwin/manual/index.html#opt-homebrew.enable
+EOF
+ return 1
+ fi
+
+ cat <<'EOF'
+UTM is required on macOS for the current HyDE VM flow.
+
+You can set it up manually in one of these ways:
+1. Install UTM via https://mac.getutm.app.
+2. Install UTM via brew, requires installing brew.
+3. Install UTM via Determinate Nix, requires installing Determinate nix with:
+ curl -fsSL https://install.determinate.systems/nix | sh -s -- install
+ Then use a nix shell, home manager, or nix-darwin.
+EOF
+
+ return 1
+}
+
+function install_darwin_dependencies() {
+ if [[ "$(uname -p 2>/dev/null || true)" != "arm" && "$(uname -p 2>/dev/null || true)" != "arm64" ]]; then
+ echo "❌ x86_64-darwin is not supported"
+ exit 1
+ fi
+
+ if command -v utmctl >/dev/null 2>&1; then
+ echo "✅ UTM is already installed: $(utmctl version)"
+ return 0
+ fi
+
+ echo "📦 UTM is required on macOS for the current HyDE VM flow."
+
+ if command -v brew >/dev/null 2>&1; then
+ read -r -p "Install UTM with Homebrew now? (y/N): " reply
+ if [[ "$reply" =~ ^[Yy]$ ]]; then
+ brew install --cask utm
+ return 0
+ fi
+ fi
+
+ if command -v nix >/dev/null 2>&1; then
+ read -r -p "Open nix shell with UTM now (nix shell nixpkgs#utm)? (y/N): " reply
+ if [[ "$reply" =~ ^[Yy]$ ]]; then
+ nix shell nixpkgs#utm
+ echo "Re-run hydevm after entering the nix shell."
+ return 1
+ fi
+ fi
+
+ cat <<'EOF'
+Install UTM manually with one of these options:
+1. Install UTM via https://mac.getutm.app.
+2. Install UTM via brew, requires installing brew.
+3. Install UTM via Determinate Nix, requires installing Determinate nix with:
+ curl -fsSL https://install.determinate.systems/nix | sh -s -- install
+ Then use a nix shell, home manager, or nix-darwin.
+
+For nix-darwin, ensure Homebrew paths are available when using Homebrew-managed UTM:
+environment.systemPath = [
+ "/usr/local/bin"
+ "/opt/homebrew/bin"
+];
+
+More info: https://nix-darwin.github.io/nix-darwin/manual/index.html#opt-homebrew.enable
+EOF
+
+ return 1
+}
+
function install_arch_packages() {
local packages=("$@")
@@ -192,36 +464,94 @@ function install_arch_packages() {
echo "✅ Packages installed successfully"
}
-function install_all_arch_dependencies() {
+function install_freebsd_packages() {
+ local packages=("$@")
+
+ echo "📦 Installing missing packages: ${packages[*]}"
+
+ # Update package database
+ echo "🔄 Updating package database..."
+ sudo pkg update
+
+ # Install required packages
+ echo "📥 Installing packages..."
+ sudo pkg install -y "${packages[@]}"
+
+ echo "✅ Packages installed successfully"
+}
+
+function install_all_dependencies() {
local os
os=$(detect_os)
- if [[ "$os" != "arch" ]]; then
- echo "❌ --install-deps is only supported on Arch Linux"
+ if [[ "$os" != "arch" && "$os" != "freebsd" && "$os" != "darwin" ]]; then
+ echo "❌ --install-deps is only supported on Arch Linux, FreeBSD, and Darwin"
echo " Current OS: $os"
exit 1
fi
echo "📦 Installing all HydeVM dependencies..."
- install_arch_packages "${ARCH_PACKAGES[@]}"
+
+ if [[ "$os" == "arch" ]]; then
+ install_arch_packages "${ARCH_PACKAGES[@]}"
echo "💡 You may need to reboot or logout/login for all changes to take effect"
+ elif [[ "$os" == "freebsd" ]]; then
+ install_freebsd_packages "${FREEBSD_PACKAGES[@]}"
+ elif [[ "$os" == "darwin" ]]; then
+ install_darwin_dependencies
+ fi
}
function check_deps_only() {
local os
+ local memory
+ local accel_available
+ local accel_label
+ local cpu_cores
+
os=$(detect_os)
echo "🔍 Checking HydeVM dependencies..."
echo " Detected OS: $os"
+ HYDEVM_CHECK_DEPS_ONLY=1
+ export HYDEVM_CHECK_DEPS_ONLY
if check_dependencies; then
+ unset HYDEVM_CHECK_DEPS_ONLY
echo "✅ All dependencies are installed"
# Check additional system info
echo ""
echo "📊 System Information:"
- echo " CPU cores: $(nproc)"
- echo " Memory: $(free -h | awk '/^Mem:/ {print $2}' 2>/dev/null || echo "Unknown")"
- echo " KVM available: $([ -r /dev/kvm ] && echo "Yes" || echo "No")"
+ cpu_cores="$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo "Unknown")"
+
+ case "$os" in
+ freebsd)
+ memory="$(sysctl -n hw.physmem 2>/dev/null | awk '{printf "%.1fGiB", $1/1024/1024/1024}' || echo "Unknown")"
+ accel_available="$(kldstat -q -m vmm && echo "Yes" || echo "No")"
+ accel_label="BSD Hypervisor (bhyve)"
+ ;;
+ darwin)
+ memory="$(sysctl -n hw.memsize 2>/dev/null | awk '{printf "%.1fGiB", $1/1024/1024/1024}' || echo "Unknown")"
+
+ if command -v qemu-system-aarch64 >/dev/null 2>&1 && \
+ qemu-system-aarch64 -accel help 2>/dev/null | grep -q hvf; then
+ accel_available="Yes"
+ else
+ accel_available="No"
+ fi
+
+ accel_label="Apple HVF"
+ ;;
+ *)
+ memory="$(free -h 2>/dev/null | awk '/^Mem:/ {print $2}' || echo "Unknown")"
+ accel_available="$([ -r /dev/kvm ] && echo "Yes" || echo "No")"
+ accel_label="KVM"
+ ;;
+ esac
+
+ echo " CPU cores: $cpu_cores"
+ echo " Memory: $memory"
+ echo " $accel_label: $accel_available"
if command -v qemu-system-x86_64 >/dev/null 2>&1; then
echo " QEMU version: $(qemu-system-x86_64 --version | head -1)"
@@ -229,6 +559,7 @@ function check_deps_only() {
return 0
else
+ unset HYDEVM_CHECK_DEPS_ONLY
return 1
fi
}
@@ -321,6 +652,22 @@ function download_archbox() {
fi
}
+function get_latest_freebsd_image_url() {
+# https://download.freebsd.org/releases/ISO-IMAGES/15.0/FreeBSD-15.0-RELEASE-amd64-dvd1.iso
+# https://download.freebsd.org/releases/ISO-IMAGES/15.0/FreeBSD-15.0-RELEASE-arm64-aarch64-dvd1.iso
+ echo "https://download.freebsd.org/releases/VM-IMAGES/15.0-RELEASE/amd64/Latest/FreeBSD-15.0-RELEASE-amd64-ufs.qcow2.xz"
+}
+
+function download_freebsdbox() {
+ if [ ! -f "$BASE_IMAGE" ]; then
+ echo "📦 Downloading FreeBSD base image..."
+ local latest_url
+ latest_url=$(get_latest_freebsd_image_url)
+ curl -L "$latest_url" -o "$BASE_IMAGE"
+ echo "✅ Base image downloaded successfully"
+ fi
+}
+
function get_snapshot_name() {
local ref="$1"
if [ -z "$ref" ]; then
@@ -532,6 +879,20 @@ check_root
persistent="false"
ref="master"
+original_argc=$#
+
+if [ "$original_argc" -eq 0 ]; then
+ os=$(detect_os)
+ case "$os" in
+ arch|nixos|freebsd|darwin) ;;
+ *)
+ print_usage
+ echo ""
+ echo "❌ Unsupported OS: $os"
+ exit 1
+ ;;
+ esac
+fi
# Parse arguments
while [ $# -gt 0 ]; do
@@ -549,7 +910,7 @@ while [ $# -gt 0 ]; do
exit 0
;;
--install-deps)
- install_all_arch_dependencies
+ install_all_dependencies
exit 0
;;
--check-deps)
diff --git a/Scripts/install.sh b/Scripts/install.sh
index 0b7620cc4b..c92462d427 100755
--- a/Scripts/install.sh
+++ b/Scripts/install.sh
@@ -23,6 +23,11 @@ EOF
# import variables and functions #
#--------------------------------#
scrDir="$(dirname "$(realpath "$0")")"
+
+if [[ "$(uname -s)" == "FreeBSD" ]]; then
+ exec "${scrDir}/install_freebsd.sh" "$@"
+fi
+
# shellcheck disable=SC1091
if ! source "${scrDir}/global_fn.sh"; then
echo "Error: unable to source global_fn.sh..."
diff --git a/Scripts/install_freebsd.sh b/Scripts/install_freebsd.sh
new file mode 100755
index 0000000000..ce6d1c93da
--- /dev/null
+++ b/Scripts/install_freebsd.sh
@@ -0,0 +1,159 @@
+#!/usr/bin/env bash
+# shellcheck disable=SC2154
+
+cat <<"EOF"
+
+-------------------------------------------------
+ _ _ _ ____ ____ ____
+| | | |_ _ __| | ___| __ ) ___|| _ \
+| |_| | | | |/ _` |/ _ \ _ \___ \| | | |
+| _ | |_| | (_| | __/ |_) |__) | |_| |
+|_| |_|\__, |\__,_|\___|____/____/|____/
+ |___/
+-------------------------------------------------
+
+EOF
+
+scrDir="$(dirname "$(realpath "$0")")"
+# shellcheck disable=SC1091
+if ! source "${scrDir}/global_fn.sh"; then
+ echo "Error: unable to source global_fn.sh..."
+ exit 1
+fi
+
+if [[ "$(uname -s)" != "FreeBSD" ]]; then
+ print_log -crit "unsupported" "install_freebsd.sh must be run on FreeBSD."
+ exit 1
+fi
+
+flg_Install=0
+flg_Restore=0
+flg_DryRun=0
+flg_ThemeInstall=1
+
+while getopts idrtmh RunStep; do
+ case $RunStep in
+ i) flg_Install=1 ;;
+ d)
+ flg_Install=1
+ export use_default="--noconfirm"
+ ;;
+ r) flg_Restore=1 ;;
+ t) flg_DryRun=1 ;;
+ m) flg_ThemeInstall=0 ;;
+ *)
+ cat <>"${scrDir}/install_pkg.lst"
+ if [ -f "${custom_pkg}" ] && [ -n "${custom_pkg}" ]; then
+ cat "${custom_pkg}" >>"${scrDir}/install_pkg.lst"
+ fi
+
+ echo ""
+ if ! chk_list "myShell" "${shlList[@]}"; then
+ print_log -c "Shell :: "
+ for i in "${!shlList[@]}"; do
+ print_log -sec "$((i + 1))" " ${shlList[$i]} "
+ done
+ prompt_timer 120 "Enter option number [default: zsh] | q to quit "
+
+ case "${PROMPT_INPUT}" in
+ 1) export myShell="zsh" ;;
+ 2) export myShell="fish" ;;
+ q)
+ print_log -sec "shell" -crit "Quit" "Exiting..."
+ exit 1
+ ;;
+ *)
+ print_log -sec "shell" -warn "Defaulting to zsh"
+ export myShell="zsh"
+ ;;
+ esac
+ print_log -sec "shell" -stat "Added as shell" "${myShell}"
+ echo "${myShell}" >>"${scrDir}/install_pkg.lst"
+ fi
+
+ if ! grep -q "^#user packages" "${scrDir}/install_pkg.lst"; then
+ print_log -sec "pkg" -crit "No user packages found..." "Log file at ${cacheDir}/logs/${HYDE_LOG}/install_freebsd.sh"
+ exit 1
+ fi
+
+ "${scrDir}/install_pkg.sh" "${scrDir}/install_pkg.lst"
+fi
+
+if [ ${flg_Restore} -eq 1 ]; then
+ cat <<"EOF"
+
+ _ _
+ ___ ___ ___| |_ ___ ___|_|___ ___
+| _| -_|_ -| _| . | _| | | . |
+|_| |___|___|_| |___|_| |_|_|_|_ |
+ |___|
+
+EOF
+
+ if [ "${flg_DryRun}" -ne 1 ] && [ -n "${HYPRLAND_INSTANCE_SIGNATURE}" ]; then
+ hyprctl keyword misc:disable_autoreload 1 -q
+ fi
+
+ "${scrDir}/restore_fnt.sh"
+ "${scrDir}/restore_cfg.sh"
+ "${scrDir}/restore_thm.sh"
+ "${scrDir}/restore_shl.sh"
+ print_log -g "[generate] " "cache ::" "Wallpapers..."
+ if [ "${flg_DryRun}" -ne 1 ]; then
+ export PATH="$HOME/.local/lib/hyde:$HOME/.local/bin:${PATH}"
+ "$HOME/.local/lib/hyde/swwwallcache.sh" -t ""
+ "$HOME/.local/lib/hyde/theme.switch.sh" -q || true
+ "$HOME/.local/lib/hyde/waybar.py" --update || true
+ echo "[install] reload :: Hyprland"
+ fi
+fi
+
+if [ $flg_Install -eq 1 ]; then
+ echo ""
+ print_log -g "Installation" " :: " "COMPLETED!"
+fi
+print_log -b "Log" " :: " -y "View logs at ${cacheDir}/logs/${HYDE_LOG}"
+print_log -warn "Reboot" "Please reboot the system to apply all changes."
diff --git a/Scripts/install_pkg.sh b/Scripts/install_pkg.sh
index 62e5770be9..ad0efad6f5 100755
--- a/Scripts/install_pkg.sh
+++ b/Scripts/install_pkg.sh
@@ -14,9 +14,12 @@ fi
flg_DryRun=${flg_DryRun:-0}
export log_section="package"
+currentPm="$(${pacmanCmd} which)"
-"${scrDir}/install_aur.sh" "${getAur}" 2>&1
-chk_list "aurhlpr" "${aurList[@]}"
+if [[ "${currentPm}" == "pacman" || "${currentPm}" == "yay" || "${currentPm}" == "paru" ]]; then
+ "${scrDir}/install_aur.sh" "${getAur}" 2>&1
+ chk_list "aurhlpr" "${aurList[@]}"
+fi
listPkg="${1:-"${scrDir}/pkg_core.lst"}"
archPkg=()
aurhPkg=()
@@ -58,11 +61,15 @@ while read -r pkg deps; do
if pkg_installed "${pkg}"; then
print_log -y "[skip] " "${pkg}"
- elif pkg_available "${pkg}"; then
- repo=$(pacman -Si "${pkg}" | awk -F ': ' '/Repository / {print $2}' | tr '\n' ' ')
+ elif "${pacmanCmd}" info "${pkg}" &>/dev/null; then
+ if [[ "${currentPm}" == "pacman" || "${currentPm}" == "yay" || "${currentPm}" == "paru" ]]; then
+ repo=$(pacman -Si "${pkg}" | awk -F ': ' '/Repository / {print $2}' | tr '\n' ' ')
+ else
+ repo="${currentPm}"
+ fi
print_log -b "[queue] " "${pkg}" -b " :: " -g "${repo}"
archPkg+=("${pkg}")
- elif aur_available "${pkg}"; then
+ elif [[ "${currentPm}" == "pacman" || "${currentPm}" == "yay" || "${currentPm}" == "paru" ]] && aur_available "${pkg}"; then
print_log -b "[queue] " "${pkg}" -b " :: " -g "aur"
aurhPkg+=("${pkg}")
else
@@ -84,12 +91,20 @@ install_packages() {
print_log -b "[pkg] " "${pkg}"
done
else
- $install_cmd ${use_default:+"$use_default"} -S "${pkg_array[@]}"
+ if [[ "${currentPm}" == "pacman" || "${currentPm}" == "yay" || "${currentPm}" == "paru" ]]; then
+ $install_cmd ${use_default:+"$use_default"} -S "${pkg_array[@]}"
+ else
+ $install_cmd install "${pkg_array[@]}"
+ fi
fi
fi
}
echo ""
-install_packages archPkg "arch" "sudo pacman"
-echo ""
-install_packages aurhPkg "aur" "${aurhlpr}"
+if [[ "${currentPm}" == "pacman" || "${currentPm}" == "yay" || "${currentPm}" == "paru" ]]; then
+ install_packages archPkg "arch" "sudo pacman"
+ echo ""
+ install_packages aurhPkg "aur" "${aurhlpr}"
+else
+ install_packages archPkg "${currentPm}" "${pacmanCmd}"
+fi
diff --git a/Scripts/pkg_core_freebsd.lst b/Scripts/pkg_core_freebsd.lst
new file mode 100644
index 0000000000..ce4f4ebc67
--- /dev/null
+++ b/Scripts/pkg_core_freebsd.lst
@@ -0,0 +1,102 @@
+# --------------------------------------------------- // System
+# uwsm # A standalone Wayland session manager
+pipewire # audio/video server
+# pipewire-module-xrdp-0.1 PipeWire module which enables xrdp to use audio redirection
+# pipewire-spa-oss-g20251117_1 PipeWire SPA plugin implementing a FreeBSD OSS backend
+# plasma6-kpipewire-6.5.5 Components relating to Flatpak 'pipewire' use in Plasma
+
+# pipewire-alsa # pipewire alsa client
+# pipewire-audio # pipewire audio client
+# pipewire-jack # pipewire jack client
+# pipewire-pulse # pipewire pulseaudio client
+# gst-plugin-pipewire # pipewire gstreamer client
+wireplumber # pipewire session manager
+pavucontrol # pulseaudio volume control
+pamixer # pulseaudio cli mixer
+# networkmanager # network manager
+# network-manager-applet # network manager system tray utility
+# bluez # bluetooth protocol stack
+bluez-firmware
+# bluez-utils # bluetooth utility cli
+# blueman # bluetooth manager gui
+FreeBSD-bluetooth
+# use `backlight` instead. https://docs.freebsd.org/en/books/handbook/config/index.html#acpi-config
+# brightnessctl # screen brightness control
+playerctl # media controls
+# udiskie # manage removable media
+dconf
+dconf-editor
+
+# --------------------------------------------------- // Display Manager
+sddm # display manager for KDE plasma
+qt5-quickcontrols # for sddm theme ui elements
+qt5-quickcontrols2 # for sddm theme ui elements
+qt5-graphicaleffects # for sddm theme effects
+
+# --------------------------------------------------- // Window Manager
+hyprland # wlroots-based wayland compositor
+dunst # notification daemon
+rofi # application launcher
+waybar # system bar
+swww # wallpaper
+hyprlock # lock screen
+wlogout # logout menu
+grim # screenshot tool
+hyprpicker # color picker
+slurp # region select for screenshot/screenshare
+satty # Modern Screenshot Annotation
+cliphist # clipboard manager
+wl-clipboard
+# wl-clip-persist # Keep Wayland clipboard even after programs close (avoids crashes)
+hyprsunset # blue light filter
+
+# --------------------------------------------------- // Dependencies
+polkit-gnome # authentication agent
+xdg-desktop-portal-hyprland # xdg desktop portal for hyprland
+xdg-desktop-portal-gtk # file picker and dbus integration
+xdg-user-dirs # Manage user directories like ~/Desktop and ~/Music
+# pacman-contrib # for system update check
+parallel # for parallel processing
+jq # for json processing
+ImageMagick7 # for image processing
+qt5-imageformats # for dolphin image thumbnails
+ffmpeg
+ffmpegthumbnailer
+# ffmpegthumbs # for dolphin video thumbnails
+# kde-cli-tools # for dolphin file type defaults
+plasma6-kde-cli-tools
+libnotify # for notifications
+# noto-fonts-emoji # emoji font
+noto-emoji
+
+# --------------------------------------------------- // Theming
+nwg-look # gtk configuration tool
+qt5ct # qt5 configuration tool
+qt6ct # qt6 configuration tool
+Kvantum
+# kvantum # svg based qt6 theme engine
+# kvantum-qt5 # svg based qt5 theme engine
+qt5-wayland # wayland support in qt5
+qt6-wayland # wayland support in qt6
+
+# --------------------------------------------------- // Applications
+firefox # browser
+kitty # terminal
+dolphin # kde file manager
+ark # kde file archiver
+unzip # extracting zip files
+vim # terminal text editor
+# code # ide text editor
+# nwg-displays # monitor management utility
+py311-nwg-displays
+fzf # Command-line fuzzy finder
+
+# --------------------------------------------------- // Shell
+starship|zsh # customizable shell prompt written in Rust
+# starship-git # The cross-shell prompt for astronauts
+starship|fish # customizable shell prompt
+
+fastfetch # system information fetch tool
+
+# --------------------------------------------------- // HyDE
+hypridle # idle daemon
diff --git a/Scripts/restore_cfg.sh b/Scripts/restore_cfg.sh
index a5aed3615d..c5122cf7df 100755
--- a/Scripts/restore_cfg.sh
+++ b/Scripts/restore_cfg.sh
@@ -193,6 +193,10 @@ deploy_psv() {
}
hyprland_hook() {
+ if [[ "$(uname -s)" == "FreeBSD" ]]; then
+ print_log -y "[hook] " -b "hyprland :: " "Skipping hyq marker validation on FreeBSD."
+ return 0
+ fi
local hyde_config="${cloneDir}/Configs/.config/hypr/hyprland.conf"
local hyprland_default_config="${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprland.conf"
@@ -267,10 +271,18 @@ echo ""
hyprland_hook
print_log -g "[python env]" -b " :: " "Rebuilding HyDE Python environment..."
-if command -v hyde-shell >/dev/null 2>&1; then
- hyde-shell pyinit
+if [[ "$(uname -s)" == "FreeBSD" ]]; then
+ if command -v hyde-shell >/dev/null 2>&1; then
+ hyde-shell pyinit || print_log -warn "python env" "Failed to rebuild Python environment on FreeBSD (non-fatal)."
+ else
+ "${HOME}/.local/bin/hyde-shell" pyinit || print_log -warn "python env" "Failed to rebuild Python environment on FreeBSD (non-fatal)."
+ fi
else
- "${HOME}/.local/bin/hyde-shell" pyinit
+ if command -v hyde-shell >/dev/null 2>&1; then
+ hyde-shell pyinit
+ else
+ "${HOME}/.local/bin/hyde-shell" pyinit
+ fi
fi
print_log -g "[version]" -b " :: " "saving version info..."
diff --git a/Scripts/restore_shl.sh b/Scripts/restore_shl.sh
index 8102e65ed5..2e6cb25168 100755
--- a/Scripts/restore_shl.sh
+++ b/Scripts/restore_shl.sh
@@ -54,7 +54,8 @@ if pkg_installed zsh; then
Zsh_rc="${ZDOTDIR:-$HOME}/.zshenv"
Zsh_Path="${Zsh_Path:-$HOME/.oh-my-zsh}"
Zsh_Plugins="$Zsh_Path/custom/plugins"
- Fix_Completion=""
+ Add_Completion=0
+ [ -f "${Zsh_rc}" ] || touch "${Zsh_rc}"
# generate plugins from list
while read -r r_plugin; do
@@ -67,7 +68,7 @@ if pkg_installed zsh; then
fi
fi
if [ "${z_plugin}" == "zsh-completions" ] && [ "$(grep -c 'fpath+=.*plugins/zsh-completions/src' "${Zsh_rc}")" -eq 0 ]; then
- Fix_Completion='\nfpath+=${ZSH_CUSTOM:-${ZSH:-/usr/share/oh-my-zsh}/custom}/plugins/zsh-completions/src'
+ Add_Completion=1
else
[ -z "${z_plugin}" ] || w_plugin+=" ${z_plugin}"
fi
@@ -75,7 +76,31 @@ if pkg_installed zsh; then
# update plugin array in zshrc
print_log -sec "SHELL" -stat "installing" "plugins (${w_plugin} )"
- sed -i "/^hyde_plugins=/c\hyde_plugins=(${w_plugin} )${Fix_Completion}" "${Zsh_rc}"
+ plugin_line="hyde_plugins=(${w_plugin} )"
+ completion_line='fpath+=${ZSH_CUSTOM:-${ZSH:-/usr/share/oh-my-zsh}/custom}/plugins/zsh-completions/src'
+
+ if grep -q '^hyde_plugins=' "${Zsh_rc}"; then
+ awk -v repl="${plugin_line}" '
+ BEGIN { done = 0 }
+ /^hyde_plugins=/ {
+ if (!done) {
+ print repl
+ done = 1
+ }
+ next
+ }
+ { print }
+ END {
+ if (!done) print repl
+ }
+ ' "${Zsh_rc}" >"${Zsh_rc}.tmp" && mv "${Zsh_rc}.tmp" "${Zsh_rc}"
+ else
+ printf '%s\n' "${plugin_line}" >>"${Zsh_rc}"
+ fi
+
+ if [ "${Add_Completion}" -eq 1 ] && ! grep -q 'plugins/zsh-completions/src' "${Zsh_rc}"; then
+ printf '%s\n' "${completion_line}" >>"${Zsh_rc}"
+ fi
else
if [ "${flg_DryRun}" -eq "1" ]; then
while read -r r_plugin; do
diff --git a/Scripts/themepatcher.sh b/Scripts/themepatcher.sh
index f6336aa9b6..e582e30073 100755
--- a/Scripts/themepatcher.sh
+++ b/Scripts/themepatcher.sh
@@ -160,7 +160,7 @@ Fav_Theme_Dir="${Theme_Dir}/Configs/.config/hyde/themes/${Fav_Theme}"
[ ! -d "${Fav_Theme_Dir}" ] && print_prompt -r "[ERROR] " "'${Fav_Theme_Dir}'" -y " Do not Exist" && exit 1
# config=$(find "${dcolDir}" -type f -name "*.dcol" | awk -v favTheme="${Fav_Theme}" -F 'theme/' '{gsub(/\.dcol$/, ".theme"); print ".config/hyde/themes/" favTheme "/" $2}')
-config=$(find "${wallbashDirs[@]}" -type f -path "*/theme*" -name "*.dcol" 2>/dev/null | awk '!seen[substr($0, match($0, /[^/]+$/))]++' | awk -v favTheme="${Fav_Theme}" -F 'theme/' '{gsub(/\.dcol$/, ".theme"); print ".config/hyde/themes/" favTheme "/" $2}')
+config=$(find "${wallbashDirs[@]}" -type f -path "*/theme*" -name "*.dcol" 2>/dev/null | awk -F/ '{print $NF "|" $0}' | awk -F'|' '!seen[$1]++ {print $2}' | awk -v favTheme="${Fav_Theme}" -F 'theme/' '{gsub(/\.dcol$/, ".theme"); print ".config/hyde/themes/" favTheme "/" $2}')
restore_list=""
while IFS= read -r fileCheck; do
diff --git a/Source/assets/freebsd.png b/Source/assets/freebsd.png
new file mode 100644
index 0000000000..2a5ccb1417
Binary files /dev/null and b/Source/assets/freebsd.png differ
diff --git a/flake.nix b/flake.nix
index 3391b620d6..46c63e4eea 100644
--- a/flake.nix
+++ b/flake.nix
@@ -13,6 +13,7 @@
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
+ # "x86_64-freebsd" # TODO: evaluate stability, broken as of March 20th, 2026
];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
in