Last active
April 15, 2026 01:24
-
-
Save rsheldiii/a184caff1dd850bf34a9155901be6b1e to your computer and use it in GitHub Desktop.
Hyprland v0.54.3 build + config setup for Pop!_OS 24.04 (Ubuntu Noble) with NVIDIA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ─── Hyprland build+install for Pop!_OS 24.04 (Ubuntu Noble) ───────────────── | |
| # Builds Hyprland and its full dependency chain from source. | |
| # nvidia-drm.modeset=1 is already set by Pop!_OS NVIDIA — no changes needed. | |
| # | |
| # Run from a terminal: sudo bash ~/install-hyprland.sh | |
| # Takes ~60 min on first run. Safe to re-run — skips already-built components. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| set -euo pipefail | |
| SCRIPT_USER="${SUDO_USER:-$USER}" | |
| SCRIPT_HOME=$(getent passwd "$SCRIPT_USER" | cut -d: -f6) | |
| BUILD_DIR="$SCRIPT_HOME/Code/hyprland-build" | |
| INSTALL_PREFIX="/usr/local" | |
| # ── helpers ────────────────────────────────────────────────────────────────── | |
| info() { echo -e "\e[34m==>\e[0m $*"; } | |
| ok() { echo -e "\e[32m ✓\e[0m $*"; } | |
| step() { echo -e "\n\e[1;36m━━━ $* ━━━\e[0m"; } | |
| run_as_user() { | |
| sudo -u "$SCRIPT_USER" bash -c " | |
| export CC=gcc-15 | |
| export CXX=g++-15 | |
| export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/lib/x86_64-linux-gnu/pkgconfig:/usr/local/share/pkgconfig\${PKG_CONFIG_PATH:+:\$PKG_CONFIG_PATH} | |
| export CMAKE_PREFIX_PATH=/usr/local | |
| export LDFLAGS=\"-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib \${LDFLAGS:-}\" | |
| export CPPFLAGS=\"-I/usr/local/include \${CPPFLAGS:-}\" | |
| $* | |
| " | |
| } | |
| # ── 0a. GCC 15 from ubuntu-toolchain-r (GCC 14.2 Ubuntu backport lacks C++26) ─ | |
| step "Installing GCC 15" | |
| if ! command -v gcc-15 &>/dev/null; then | |
| apt-get install -y software-properties-common | |
| add-apt-repository -y ppa:ubuntu-toolchain-r/test | |
| apt-get update -qq | |
| apt-get install -y gcc-15 g++-15 | |
| ok "GCC 15 installed" | |
| else | |
| ok "GCC 15 already installed" | |
| fi | |
| # ── 0b. CMake 3.30+ from Kitware (Ubuntu 24.04 ships 3.28) ─────────────────── | |
| step "Installing CMake 3.30+ from Kitware" | |
| if ! cmake --version 2>/dev/null | awk 'NR==1{split($3,v,"."); exit (v[1]>3 || (v[1]==3 && v[2]>=30)) ? 0 : 1}'; then | |
| apt-get install -y ca-certificates gpg wget | |
| wget -qO /tmp/kitware-archive-keyring.gpg \ | |
| https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null || \ | |
| curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc \ | |
| -o /tmp/kitware-archive-keyring.gpg | |
| gpg --dearmor < /tmp/kitware-archive-keyring.gpg \ | |
| > /usr/share/keyrings/kitware-archive-keyring.gpg | |
| echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' \ | |
| > /etc/apt/sources.list.d/kitware.list | |
| apt-get update -qq | |
| apt-get install -y cmake | |
| ok "CMake $(cmake --version | head -1) installed from Kitware" | |
| else | |
| ok "CMake $(cmake --version | head -1) already satisfies 3.30+" | |
| fi | |
| # ── 1. Build dependencies ──────────────────────────────────────────────────── | |
| step "Installing build dependencies" | |
| apt-get update -qq | |
| apt-get install -y \ | |
| build-essential meson ninja-build pkg-config git bison \ | |
| autoconf automake libtool \ | |
| xcb-proto \ | |
| libwayland-dev wayland-protocols libwayland-bin \ | |
| libxkbcommon-dev libinput-dev libdrm-dev libgbm-dev \ | |
| libseat-dev libsystemd-dev libudev-dev \ | |
| libvulkan-dev libvulkan1 glslang-tools glslang-dev \ | |
| libpixman-1-dev libcairo2-dev libpango1.0-dev \ | |
| libgles2-mesa-dev libgl1-mesa-dev \ | |
| libegl1-mesa-dev libegl-dev \ | |
| libxcb1-dev libxcb-composite0-dev libxcb-damage0-dev \ | |
| libxcb-dpms0-dev libxcb-dri3-dev libxcb-ewmh-dev \ | |
| libxcb-icccm4-dev libxcb-render0-dev \ | |
| libxcb-render-util0-dev libxcb-res0-dev libxcb-shape0-dev \ | |
| libxcb-shm0-dev libxcb-sync-dev libxcb-util0-dev \ | |
| libxcb-xfixes0-dev libxcb-xinput-dev libxcb-xkb-dev \ | |
| libxcb-cursor-dev \ | |
| libx11-dev libx11-xcb-dev libxfixes-dev \ | |
| libmagic-dev libmagickwand-dev \ | |
| libdisplay-info-dev \ | |
| libliftoff-dev \ | |
| libtomlplusplus-dev \ | |
| libsdl2-dev \ | |
| libpugixml-dev \ | |
| libevdev-dev \ | |
| libmtdev-dev \ | |
| libwacom-dev \ | |
| libzip-dev \ | |
| libjpeg-dev \ | |
| libwebp-dev \ | |
| libre2-dev \ | |
| libffi-dev \ | |
| xutils-dev \ | |
| qt6-base-dev \ | |
| libpipewire-0.3-dev \ | |
| libspa-0.2-dev \ | |
| libmuparser-dev \ | |
| libxcb-util-dev \ | |
| uuid-dev \ | |
| hwdata \ | |
| xwayland \ | |
| python3-jinja2 | |
| ok "Build dependencies installed" | |
| # ── 2. Ecosystem tools (all in noble repos) ────────────────────────────────── | |
| step "Installing Hyprland ecosystem tools" | |
| apt-get install -y \ | |
| waybar \ | |
| wofi \ | |
| mako-notifier \ | |
| grim \ | |
| slurp \ | |
| wl-clipboard \ | |
| wlr-randr \ | |
| policykit-1-gnome \ | |
| xdg-desktop-portal-gtk \ | |
| xdg-utils \ | |
| brightnessctl \ | |
| playerctl \ | |
| pavucontrol \ | |
| network-manager-gnome \ | |
| kitty \ | |
| thunar tumbler ffmpegthumbnailer \ | |
| fonts-noto-color-emoji \ | |
| fonts-font-awesome \ | |
| imagemagick | |
| ok "Ecosystem tools installed" | |
| # ── 3. cliphist binary ─────────────────────────────────────────────────────── | |
| step "Installing cliphist" | |
| CLIPHIST_URL=$(curl -s https://api.github.com/repos/sentriz/cliphist/releases/latest \ | |
| | python3 -c "import sys,json; r=json.load(sys.stdin); \ | |
| [print(a['browser_download_url']) for a in r['assets'] \ | |
| if 'linux_amd64' in a['name'] and not a['name'].endswith('.sha256')]" \ | |
| | head -1) | |
| if [ -n "$CLIPHIST_URL" ]; then | |
| curl -sL "$CLIPHIST_URL" -o /usr/local/bin/cliphist | |
| chmod +x /usr/local/bin/cliphist | |
| ok "cliphist installed" | |
| else | |
| echo " WARNING: could not find cliphist release, skipping" | |
| fi | |
| # ── build helper: clone-or-update + cmake install ──────────────────────────── | |
| build_cmake() { | |
| local name="$1" url="$2" tag="$3" build_target="${4:-}" | |
| local dir="$BUILD_DIR/$name" | |
| info "Building $name $tag..." | |
| if [ -d "$dir" ]; then | |
| run_as_user "cd '$dir' && git fetch --tags -q && git checkout -q '$tag'" | |
| else | |
| run_as_user "git clone --depth 1 --branch '$tag' '$url' '$dir'" | |
| fi | |
| # ofstream::native_handle() is C++26; not in GCC 14.2 on Ubuntu 24.04. | |
| # The call only sets FD_CLOEXEC on the log file — safe to remove. | |
| # (grep exits 1 when no matches; suppress that with || true so set -e doesn't abort) | |
| grep -rl --include='*.cpp' --include='*.hpp' \ | |
| 'native_handle.*FD_CLOEXEC\|FD_CLOEXEC.*native_handle' "$dir" 2>/dev/null | \ | |
| while read -r f; do | |
| sed -i '/native_handle.*FD_CLOEXEC\|FD_CLOEXEC.*native_handle/d' "$f" | |
| info " Patched $f (removed native_handle/FD_CLOEXEC)" | |
| done || true | |
| run_as_user "cmake -S '$dir' -B '$dir/build' \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX='$INSTALL_PREFIX' \ | |
| -DCMAKE_PREFIX_PATH='$INSTALL_PREFIX' \ | |
| -DCMAKE_C_COMPILER=gcc-15 \ | |
| -DCMAKE_CXX_COMPILER=g++-15 \ | |
| -DCMAKE_SHARED_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DCMAKE_EXE_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DBUILD_TESTING=OFF \ | |
| --fresh \ | |
| -G Ninja" | |
| if [ -n "$build_target" ]; then | |
| run_as_user "cmake --build '$dir/build' --target '$build_target' --parallel $(nproc)" | |
| else | |
| run_as_user "cmake --build '$dir/build' --parallel $(nproc)" | |
| fi | |
| cmake --install "$dir/build" | |
| ldconfig | |
| ok "$name installed to $INSTALL_PREFIX" | |
| } | |
| run_as_user "mkdir -p '$BUILD_DIR'" | |
| # ── 4. Build dependency chain ──────────────────────────────────────────────── | |
| step "Building Hyprland dependency chain" | |
| info "Order: libinput → xkbcommon → hyprutils → hyprwayland-scanner → hyprlang → aquamarine → hyprcursor → hyprgraphics → hyprland" | |
| # libinput: Ubuntu 24.04 only has 1.25.0; Hyprland requires >= 1.28.0 | |
| LIBINPUT_DIR="$BUILD_DIR/libinput" | |
| if [ -d "$LIBINPUT_DIR" ]; then | |
| run_as_user "cd '$LIBINPUT_DIR' && git fetch --tags -q && git checkout -q '1.28.1'" | |
| else | |
| run_as_user "git clone --depth 1 --branch '1.28.1' \ | |
| https://gitlab.freedesktop.org/libinput/libinput.git '$LIBINPUT_DIR'" | |
| fi | |
| run_as_user "CC=gcc-15 CXX=g++-15 meson setup '$LIBINPUT_DIR/build' '$LIBINPUT_DIR' \ | |
| --buildtype=release \ | |
| --prefix='$INSTALL_PREFIX' \ | |
| --wipe \ | |
| -Ddocumentation=false \ | |
| -Ddebug-gui=false \ | |
| -Dtests=false \ | |
| -Dlibwacom=false" | |
| run_as_user "ninja -C '$LIBINPUT_DIR/build' -j$(nproc)" | |
| ninja -C "$LIBINPUT_DIR/build" install | |
| ldconfig | |
| ok "libinput 1.28.1 installed to $INSTALL_PREFIX" | |
| # xkbcommon: Ubuntu 24.04 ships 1.6.0; Hyprland requires >= 1.11.0 | |
| XKBCOMMON_DIR="$BUILD_DIR/xkbcommon" | |
| if [ -d "$XKBCOMMON_DIR" ]; then | |
| run_as_user "cd '$XKBCOMMON_DIR' && git fetch --tags -q && git checkout -q 'xkbcommon-1.11.0'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'xkbcommon-1.11.0' \ | |
| https://github.com/xkbcommon/libxkbcommon.git '$XKBCOMMON_DIR'" | |
| fi | |
| run_as_user "CC=gcc-15 CXX=g++-15 meson setup '$XKBCOMMON_DIR/build' '$XKBCOMMON_DIR' \ | |
| --buildtype=release \ | |
| --prefix='$INSTALL_PREFIX' \ | |
| --wipe \ | |
| -Denable-docs=false \ | |
| -Denable-tools=false" | |
| run_as_user "ninja -C '$XKBCOMMON_DIR/build' -j$(nproc)" | |
| ninja -C "$XKBCOMMON_DIR/build" install | |
| ldconfig | |
| ok "xkbcommon 1.11.0 installed to $INSTALL_PREFIX" | |
| build_cmake "hyprutils" "https://github.com/hyprwm/hyprutils" "v0.12.0" | |
| build_cmake "hyprwayland-scanner" "https://github.com/hyprwm/hyprwayland-scanner" "v0.4.5" | |
| build_cmake "hyprlang" "https://github.com/hyprwm/hyprlang" "v0.6.8" | |
| build_cmake "aquamarine" "https://github.com/hyprwm/aquamarine" "v0.10.0" "aquamarine" | |
| build_cmake "hyprcursor" "https://github.com/hyprwm/hyprcursor" "v0.1.13" | |
| build_cmake "hyprgraphics" "https://github.com/hyprwm/hyprgraphics" "v0.1.6" | |
| build_cmake "hyprwire" "https://github.com/hyprwm/hyprwire" "v0.3.0" | |
| # xcb-errors: not in Ubuntu 24.04 repos, required for XWayland support | |
| XCBERR_DIR="$BUILD_DIR/xcb-errors" | |
| if [ -d "$XCBERR_DIR" ]; then | |
| run_as_user "cd '$XCBERR_DIR' && git fetch --tags -q && git checkout -q 'xcb-util-errors-1.0.1'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'xcb-util-errors-1.0.1' \ | |
| https://gitlab.freedesktop.org/xorg/lib/libxcb-errors.git '$XCBERR_DIR'" | |
| fi | |
| # util-common-m4 submodule uses a dead protocol and the hosting server requires auth. | |
| # Skip autotools entirely — build with gcc directly using xcb-proto XML files. | |
| XCBPROTO_XMLDIR=$(pkg-config --variable=xcbincludedir xcb-proto) | |
| info "xcb-proto XML dir: $XCBPROTO_XMLDIR" | |
| # Generate extensions.c from xcb-proto XML | |
| run_as_user "python3 '$XCBERR_DIR/src/extensions.py' '$XCBERR_DIR/src/extensions.c.tmp' $XCBPROTO_XMLDIR/*.xml && \ | |
| mv '$XCBERR_DIR/src/extensions.c.tmp' '$XCBERR_DIR/src/extensions.c'" | |
| # Compile shared library | |
| XCB_CFLAGS=$(pkg-config --cflags xcb) | |
| XCB_LIBS=$(pkg-config --libs xcb) | |
| gcc -shared -fPIC -O2 \ | |
| -o "$XCBERR_DIR/libxcb-errors.so.0.0.0" \ | |
| "$XCBERR_DIR/src/xcb_errors.c" \ | |
| "$XCBERR_DIR/src/extensions.c" \ | |
| $XCB_CFLAGS -I"$XCBERR_DIR/src" $XCB_LIBS \ | |
| -Wl,-soname,libxcb-errors.so.0 | |
| ln -sf libxcb-errors.so.0.0.0 "$XCBERR_DIR/libxcb-errors.so.0" | |
| ln -sf libxcb-errors.so.0 "$XCBERR_DIR/libxcb-errors.so" | |
| # Install | |
| install -Dm755 "$XCBERR_DIR/libxcb-errors.so.0.0.0" \ | |
| "$INSTALL_PREFIX/lib/x86_64-linux-gnu/libxcb-errors.so.0.0.0" | |
| ln -sf libxcb-errors.so.0.0.0 "$INSTALL_PREFIX/lib/x86_64-linux-gnu/libxcb-errors.so.0" | |
| ln -sf libxcb-errors.so.0 "$INSTALL_PREFIX/lib/x86_64-linux-gnu/libxcb-errors.so" | |
| install -Dm644 "$XCBERR_DIR/src/xcb_errors.h" \ | |
| "$INSTALL_PREFIX/include/xcb/xcb_errors.h" | |
| # Write .pc file | |
| mkdir -p "$INSTALL_PREFIX/lib/pkgconfig" | |
| cat > "$INSTALL_PREFIX/lib/pkgconfig/xcb-errors.pc" << EOF | |
| prefix=$INSTALL_PREFIX | |
| exec_prefix=$INSTALL_PREFIX | |
| libdir=$INSTALL_PREFIX/lib/x86_64-linux-gnu | |
| includedir=$INSTALL_PREFIX/include | |
| Name: XCB errors library | |
| Description: XCB errors utility library | |
| Version: 1.0.1 | |
| Requires: xcb | |
| Libs: -L\${libdir} -lxcb-errors | |
| Cflags: -I\${includedir} | |
| EOF | |
| ldconfig | |
| ok "xcb-errors 1.0.1 installed to $INSTALL_PREFIX" | |
| # sdbus-c++: apt has 1.4.0; xdg-desktop-portal-hyprland requires >= 2.0.0 | |
| build_cmake "sdbus-cpp" "https://github.com/Kistler-Group/sdbus-cpp" "v2.2.1" | |
| # ── 5. Build Hyprland itself ───────────────────────────────────────────────── | |
| step "Building Hyprland v0.54.3" | |
| HYPR_DIR="$BUILD_DIR/hyprland" | |
| if [ -d "$HYPR_DIR" ]; then | |
| run_as_user "cd '$HYPR_DIR' && git fetch --tags -q && git checkout -q 'v0.54.3'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'v0.54.3' \ | |
| https://github.com/hyprwm/hyprland.git '$HYPR_DIR'" | |
| fi | |
| # Initialize submodules (udis86, hyprland-protocols, etc.) | |
| run_as_user "cd '$HYPR_DIR' && git submodule update --init --depth 1" | |
| # Install glaze headers system-wide so start-hyprland finds them (its CMakeLists | |
| # includes glaze/glaze.hpp but never links glaze::glaze — cmake target won't help) | |
| if [ ! -d /usr/local/include/glaze ]; then | |
| GLAZE_DIR="$BUILD_DIR/glaze" | |
| run_as_user "git clone --depth 1 --branch v7.0.0 \ | |
| https://github.com/stephenberry/glaze.git '$GLAZE_DIR'" | |
| cp -r "$GLAZE_DIR/include/glaze" /usr/local/include/glaze | |
| ok "glaze v7.0.0 headers installed to /usr/local/include" | |
| else | |
| ok "glaze headers already present" | |
| fi | |
| run_as_user "cmake -S '$HYPR_DIR' -B '$HYPR_DIR/build' \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX='$INSTALL_PREFIX' \ | |
| -DCMAKE_PREFIX_PATH='$INSTALL_PREFIX' \ | |
| -DCMAKE_C_COMPILER=gcc-15 \ | |
| -DCMAKE_CXX_COMPILER=g++-15 \ | |
| -DCMAKE_SHARED_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DCMAKE_EXE_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| --fresh \ | |
| -G Ninja" | |
| run_as_user "cmake --build '$HYPR_DIR/build' --parallel $(nproc)" | |
| cmake --install "$HYPR_DIR/build" | |
| ldconfig | |
| ok "Hyprland v0.54.3 installed" | |
| # ── 6. Wayland session entry ───────────────────────────────────────────────── | |
| step "Registering Hyprland session" | |
| mkdir -p /usr/share/wayland-sessions | |
| cat > /usr/share/wayland-sessions/hyprland.desktop << 'EOF' | |
| [Desktop Entry] | |
| Name=Hyprland | |
| Comment=A dynamic tiling Wayland compositor | |
| Exec=Hyprland | |
| Type=Application | |
| EOF | |
| ok "Session registered — will appear in login screen dropdown" | |
| # ── 7. xdg-desktop-portal-hyprland ────────────────────────────────────────── | |
| step "Building xdg-desktop-portal-hyprland" | |
| XDP_DIR="$BUILD_DIR/xdg-desktop-portal-hyprland" | |
| if [ -d "$XDP_DIR" ]; then | |
| run_as_user "cd '$XDP_DIR' && git fetch -q && git checkout -q master && git pull -q" | |
| else | |
| run_as_user "git clone --depth 1 https://github.com/hyprwm/xdg-desktop-portal-hyprland.git '$XDP_DIR'" | |
| fi | |
| run_as_user "cd '$XDP_DIR' && git submodule update --init --depth 1" | |
| run_as_user "cmake -S '$XDP_DIR' -B '$XDP_DIR/build' \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX=/usr \ | |
| -DCMAKE_PREFIX_PATH='$INSTALL_PREFIX' \ | |
| -DCMAKE_C_COMPILER=gcc-15 \ | |
| -DCMAKE_CXX_COMPILER=g++-15 \ | |
| -DCMAKE_SHARED_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DCMAKE_EXE_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| --fresh \ | |
| -G Ninja" | |
| run_as_user "cmake --build '$XDP_DIR/build' --parallel $(nproc)" | |
| cmake --install "$XDP_DIR/build" | |
| ldconfig | |
| ok "xdg-desktop-portal-hyprland installed" | |
| echo "" | |
| echo "╔═══════════════════════════════════════════════════════════╗" | |
| echo "║ Hyprland installation complete! ║" | |
| echo "╠═══════════════════════════════════════════════════════════╣" | |
| echo "║ Next: run the config setup script as yourself (no sudo): ║" | |
| echo "║ bash ~/setup-hyprland-config.sh ║" | |
| echo "╚═══════════════════════════════════════════════════════════╝" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ─── JaKooLit Hyprland-Dots dependency installer ───────────────────────────── | |
| # Installs the packages, fonts, and tools required by JaKooLit's Hyprland | |
| # dotfiles (https://github.com/JaKooLit/Hyprland-Dots), then copies the | |
| # dotfiles into ~/.config. | |
| # | |
| # Assumes install-hyprland.sh has already run successfully (Hyprland, GCC 15, | |
| # cmake 4.x, and the hyprwm dependency chain are already in place). | |
| # | |
| # Run as: sudo bash ~/install-jakoolit-deps.sh | |
| # Safe to re-run — skips already-installed components. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| set -euo pipefail | |
| SCRIPT_USER="${SUDO_USER:-$USER}" | |
| SCRIPT_HOME=$(getent passwd "$SCRIPT_USER" | cut -d: -f6) | |
| BUILD_DIR="$SCRIPT_HOME/Code/hyprland-build" | |
| INSTALL_PREFIX="/usr/local" | |
| info() { echo -e "\e[34m==>\e[0m $*"; } | |
| ok() { echo -e "\e[32m ✓\e[0m $*"; } | |
| step() { echo -e "\n\e[1;36m━━━ $* ━━━\e[0m"; } | |
| # Mirrors the run_as_user from install-hyprland.sh: runs commands as the | |
| # non-root user with the hyprwm build environment (GCC 15, /usr/local PKG paths). | |
| run_as_user() { | |
| sudo -u "$SCRIPT_USER" bash -c " | |
| export CC=gcc-15 | |
| export CXX=g++-15 | |
| export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/lib/x86_64-linux-gnu/pkgconfig:/usr/local/share/pkgconfig\${PKG_CONFIG_PATH:+:\$PKG_CONFIG_PATH} | |
| export CMAKE_PREFIX_PATH=/usr/local | |
| export LDFLAGS=\"-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib \${LDFLAGS:-}\" | |
| export CPPFLAGS=\"-I/usr/local/include \${CPPFLAGS:-}\" | |
| $* | |
| " | |
| } | |
| build_cmake() { | |
| local name="$1" url="$2" tag="$3" build_target="${4:-}" | |
| local dir="$BUILD_DIR/$name" | |
| info "Building $name $tag..." | |
| if [ -d "$dir" ]; then | |
| run_as_user "cd '$dir' && git fetch --tags -q && git checkout -q '$tag'" | |
| else | |
| run_as_user "git clone --depth 1 --branch '$tag' '$url' '$dir'" | |
| fi | |
| run_as_user "cmake -S '$dir' -B '$dir/build' \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX='$INSTALL_PREFIX' \ | |
| -DCMAKE_PREFIX_PATH='$INSTALL_PREFIX' \ | |
| -DCMAKE_C_COMPILER=gcc-15 \ | |
| -DCMAKE_CXX_COMPILER=g++-15 \ | |
| -DCMAKE_SHARED_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DCMAKE_EXE_LINKER_FLAGS='-L/usr/local/lib/x86_64-linux-gnu -L/usr/local/lib' \ | |
| -DBUILD_TESTING=OFF \ | |
| --fresh \ | |
| -G Ninja" | |
| if [ -n "$build_target" ]; then | |
| run_as_user "cmake --build '$dir/build' --target '$build_target' --parallel $(nproc)" | |
| else | |
| run_as_user "cmake --build '$dir/build' --parallel $(nproc)" | |
| fi | |
| cmake --install "$dir/build" | |
| ldconfig | |
| ok "$name installed to $INSTALL_PREFIX" | |
| } | |
| # ── 1. apt packages ─────────────────────────────────────────────────────────── | |
| step "Installing apt packages" | |
| # Notes on non-obvious packages and omissions: | |
| # sway-notification-center — swaync; JaKooLit uses this instead of mako/dunst. | |
| # It supports action buttons and inline replies in | |
| # notifications, which mako does not. | |
| # wlogout — full-screen logout/reboot/shutdown/suspend menu, | |
| # bound to Super+Shift+W in JaKooLit's keybinds. | |
| # qt5ct / qt6ct / kvantum — Qt theming tools. Without these, Qt apps ignore | |
| # GTK themes and render with a bare system style. | |
| # Kvantum adds SVG-based themes so Qt apps can match | |
| # the Catppuccin look. | |
| # pamixer — CLI PulseAudio/PipeWire volume control used by | |
| # waybar's volume widget. | |
| # yad — Yet Another Dialog; JaKooLit's scripts use it for | |
| # in-session GUI prompts (theme switcher, etc.). | |
| # btop — resource monitor with a polished TUI; replaces htop | |
| # in JaKooLit's default keybind (Super+Shift+B). | |
| # polkit-kde-agent-1 — graphical polkit authentication agent for Wayland; | |
| # replaces polkit-gnome from our original setup. The | |
| # KDE agent has better Wayland support. | |
| # libpam0g-dev — PAM headers; required to build hyprlock (the lock | |
| # screen uses PAM to verify your password). | |
| # libgtk-3-dev — GTK3 headers; required to build swappy. | |
| # jq / bc — JSON parser and math tool used by wallust and | |
| # JaKooLit's waybar scripts. | |
| # lib*-dev below — build deps for rofi-wayland (step 4). | |
| # | |
| # NOT in Ubuntu 24.04 repos — built from source in later steps: | |
| # fastfetch — GitHub .deb (step 2) | |
| # swappy — meson source build (step 3) | |
| # hyprland-protocols — cmake source build (step 4); was only a submodule | |
| # during our Hyprland build, needs a proper system install | |
| # so hypridle/hyprlock can find it via pkg-config | |
| # hypridle — cmake source build (step 5) | |
| # hyprlock — cmake source build (step 6) | |
| apt-get update -qq | |
| apt-get install -y \ | |
| sway-notification-center \ | |
| wlogout \ | |
| btop \ | |
| cava \ | |
| yad \ | |
| pamixer \ | |
| nvtop \ | |
| qt5ct \ | |
| qt5-style-kvantum \ | |
| qt5-style-kvantum-themes \ | |
| qt6ct \ | |
| inxi \ | |
| python3-requests \ | |
| polkit-kde-agent-1 \ | |
| gvfs gvfs-backends \ | |
| xdg-user-dirs \ | |
| loupe \ | |
| mousepad \ | |
| mpv \ | |
| qalculate-gtk \ | |
| gnome-system-monitor \ | |
| fonts-firacode \ | |
| fonts-noto fonts-noto-cjk \ | |
| jq \ | |
| bc \ | |
| libpam0g-dev \ | |
| libgtk-3-dev \ | |
| libmpdclient-dev \ | |
| libasound2-dev \ | |
| libxcb-keysyms1-dev \ | |
| libxcb-randr0-dev \ | |
| libxcb-xinerama0-dev \ | |
| libxkbcommon-x11-dev \ | |
| libstartup-notification0-dev \ | |
| liblz4-dev \ | |
| flex | |
| # swaync replaces mako — having both running causes duplicate notifications. | |
| apt-get remove -y mako-notifier 2>/dev/null || true | |
| ok "apt packages done" | |
| # ── 2. fastfetch (GitHub .deb) ──────────────────────────────────────────────── | |
| step "Installing fastfetch" | |
| # fastfetch is not in Ubuntu 24.04 repos. The project publishes .deb packages | |
| # on GitHub releases, so we grab the latest one directly. | |
| if ! command -v fastfetch &>/dev/null; then | |
| FASTFETCH_DEB=$(curl -s https://api.github.com/repos/fastfetch-cli/fastfetch/releases/latest \ | |
| | python3 -c "import sys,json; r=json.load(sys.stdin); \ | |
| [print(a['browser_download_url']) for a in r['assets'] \ | |
| if a['name'].endswith('amd64.deb')]" | head -1) | |
| curl -sL "$FASTFETCH_DEB" -o /tmp/fastfetch.deb | |
| dpkg -i /tmp/fastfetch.deb | |
| rm /tmp/fastfetch.deb | |
| ok "fastfetch installed" | |
| else | |
| ok "fastfetch already installed" | |
| fi | |
| # ── 3. swappy (from source) ─────────────────────────────────────────────────── | |
| step "Building swappy v1.8.0" | |
| # swappy is a screenshot annotation tool — JaKooLit's screenshot keybinds pipe | |
| # grim/slurp output into it. Not in Ubuntu 24.04 repos; built with meson. | |
| SWAPPY_DIR="$BUILD_DIR/swappy" | |
| if ! command -v swappy &>/dev/null; then | |
| if [ -d "$SWAPPY_DIR" ]; then | |
| run_as_user "cd '$SWAPPY_DIR' && git fetch --tags -q && git checkout -q 'v1.8.0'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'v1.8.0' \ | |
| https://github.com/jtheoof/swappy.git '$SWAPPY_DIR'" | |
| fi | |
| run_as_user "CC=gcc-15 CXX=g++-15 meson setup '$SWAPPY_DIR/build' '$SWAPPY_DIR' \ | |
| --buildtype=release \ | |
| --prefix='$INSTALL_PREFIX' \ | |
| --wipe \ | |
| -Dman-pages=disabled" | |
| run_as_user "ninja -C '$SWAPPY_DIR/build' -j$(nproc)" | |
| ninja -C "$SWAPPY_DIR/build" install | |
| ldconfig | |
| ok "swappy installed" | |
| else | |
| ok "swappy already installed" | |
| fi | |
| # ── 4. hyprland-protocols (from source) ────────────────────────────────────── | |
| step "Installing hyprland-protocols v0.7.0" | |
| # hyprland-protocols provides the Wayland protocol extension XML files used by | |
| # hyprlock and hypridle. During our Hyprland build it was only a git submodule — | |
| # it was never installed to /usr/local as a proper pkgconfig package. | |
| # Both hypridle and hyprlock require it via pkg-config at build time. | |
| # Uses meson (no compilation — just installs XML files and a .pc file). | |
| HPROTO_DIR="$BUILD_DIR/hyprland-protocols" | |
| if ! pkg-config --exists hyprland-protocols 2>/dev/null; then | |
| if [ -d "$HPROTO_DIR" ]; then | |
| run_as_user "cd '$HPROTO_DIR' && git fetch --tags -q && git checkout -q 'v0.7.0'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'v0.7.0' \ | |
| https://github.com/hyprwm/hyprland-protocols.git '$HPROTO_DIR'" | |
| fi | |
| run_as_user "meson setup '$HPROTO_DIR/build' '$HPROTO_DIR' \ | |
| --buildtype=release \ | |
| --prefix='$INSTALL_PREFIX' \ | |
| --wipe" | |
| ninja -C "$HPROTO_DIR/build" install | |
| ldconfig | |
| ok "hyprland-protocols installed" | |
| else | |
| ok "hyprland-protocols already installed" | |
| fi | |
| # ── 5. hypridle (from source) ───────────────────────────────────────────────── | |
| step "Building hypridle v0.1.7" | |
| # hypridle is the screen idle daemon from the hyprwm project. It watches for | |
| # inactivity and triggers actions (dim screen, lock, suspend). Not in Ubuntu | |
| # 24.04 repos, and it depends on the hyprwm libs we built from source | |
| # (hyprutils, hyprlang, sdbus-c++) — which is why apt can't provide it. | |
| build_cmake "hypridle" "https://github.com/hyprwm/hypridle" "v0.1.7" | |
| # ── 6. hyprlock (from source) ───────────────────────────────────────────────── | |
| step "Building hyprlock v0.9.4" | |
| # hyprlock is the Hyprland lock screen. Same situation as hypridle: depends on | |
| # hyprutils, hyprlang, hyprgraphics, sdbus-c++, and also libpam (for password | |
| # verification) and OpenGL/EGL (for GPU-accelerated rendering with blur effects). | |
| # Not in Ubuntu repos for the same reason — all its hyprwm deps are custom-built. | |
| build_cmake "hyprlock" "https://github.com/hyprwm/hyprlock" "v0.9.4" | |
| # ── 7. Nerd Fonts ───────────────────────────────────────────────────────────── | |
| step "Installing Nerd Fonts (JetBrainsMono + FantasqueSansMono)" | |
| # JaKooLit's waybar configs use Nerd Font icon glyphs (e.g. for home, for | |
| # CPU) that only render correctly with a Nerd Font installed. The apt package | |
| # fonts-nerd-fonts does not exist in Ubuntu 24.04 — these must be downloaded | |
| # directly from the ryanoasis/nerd-fonts GitHub releases. | |
| # JetBrainsMono — used as the primary monospace font in waybar and kitty. | |
| # FantasqueSansMono — used as an alternative in some waybar styles. | |
| FONT_DIR="$SCRIPT_HOME/.local/share/fonts" | |
| if [ ! -d "$FONT_DIR/JetBrainsMonoNerd" ]; then | |
| info "Downloading JetBrainsMono Nerd Font..." | |
| run_as_user "mkdir -p '$FONT_DIR/JetBrainsMonoNerd' && \ | |
| curl -sL https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.tar.xz \ | |
| | tar -xJf - -C '$FONT_DIR/JetBrainsMonoNerd'" | |
| ok "JetBrainsMono Nerd Font installed" | |
| else | |
| ok "JetBrainsMono already present" | |
| fi | |
| if [ ! -d "$FONT_DIR/FantasqueSansMonoNerd" ]; then | |
| info "Downloading FantasqueSansMono Nerd Font..." | |
| run_as_user "mkdir -p '$FONT_DIR/FantasqueSansMonoNerd' && \ | |
| curl -sL https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/FantasqueSansMono.zip \ | |
| -o /tmp/FantasqueSansMono.zip && \ | |
| unzip -q /tmp/FantasqueSansMono.zip -d '$FONT_DIR/FantasqueSansMonoNerd' && \ | |
| rm /tmp/FantasqueSansMono.zip" | |
| ok "FantasqueSansMono Nerd Font installed" | |
| else | |
| ok "FantasqueSansMono already present" | |
| fi | |
| run_as_user "fc-cache -f" | |
| ok "Font cache updated" | |
| # ── 8. wallust (from source via cargo) ─────────────────────────────────────── | |
| step "Installing wallust" | |
| # wallust is a pywal replacement that extracts a 16-color palette from your | |
| # wallpaper and applies it across all apps (waybar, kitty, rofi, swaync, etc.) | |
| # by regenerating their config files from templates. JaKooLit's entire theming | |
| # system is built around it — every theme switch runs wallust under the hood. | |
| # Not in Ubuntu apt. Distributed as a Rust crate, compiled with cargo. | |
| if ! command -v wallust &>/dev/null; then | |
| if ! sudo -u "$SCRIPT_USER" bash -c 'command -v cargo &>/dev/null'; then | |
| info "Installing Rust toolchain (needed for wallust)..." | |
| run_as_user "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y" | |
| fi | |
| run_as_user "source '$SCRIPT_HOME/.cargo/env' && cargo install wallust" | |
| install -m755 "$SCRIPT_HOME/.cargo/bin/wallust" /usr/local/bin/wallust | |
| ok "wallust installed" | |
| else | |
| ok "wallust already installed" | |
| fi | |
| # ── 9. rofi-wayland (from source, tag 1.7.8+wayland1) ──────────────────────── | |
| step "Building rofi-wayland 1.7.8+wayland1" | |
| # JaKooLit uses rofi for the app launcher, clipboard picker, theme switcher, | |
| # and several other menus — it's deeply integrated throughout the config. | |
| # The `rofi` package in Ubuntu apt is the X11 build: it runs via XWayland, | |
| # has poor HiDPI scaling on Wayland, and lacks the -normal-window flag and | |
| # native Wayland input handling. lbonn/rofi is a maintained fork that adds a | |
| # native Wayland backend while keeping full X11 compatibility. | |
| # Must be built from source — no Ubuntu PPA ships it. | |
| ROFI_DIR="$BUILD_DIR/rofi-wayland" | |
| if ! (rofi -version 2>/dev/null | grep -qi wayland); then | |
| if [ -d "$ROFI_DIR" ]; then | |
| run_as_user "cd '$ROFI_DIR' && git fetch --tags -q && git checkout -q '1.7.8+wayland1'" | |
| else | |
| run_as_user "git clone --depth 1 --branch '1.7.8+wayland1' \ | |
| https://github.com/lbonn/rofi.git '$ROFI_DIR'" | |
| fi | |
| run_as_user "cd '$ROFI_DIR' && git submodule update --init --depth 1" | |
| run_as_user "CC=gcc-15 CXX=g++-15 meson setup '$ROFI_DIR/build' '$ROFI_DIR' \ | |
| --buildtype=release \ | |
| --prefix=/usr/local \ | |
| -Dwayland=enabled \ | |
| -Dxcb=enabled \ | |
| --wipe" | |
| run_as_user "ninja -C '$ROFI_DIR/build' -j$(nproc)" | |
| ninja -C "$ROFI_DIR/build" install | |
| ldconfig | |
| ok "rofi-wayland installed" | |
| else | |
| ok "rofi-wayland already installed" | |
| fi | |
| # ── 10. swww (from source via cargo) ───────────────────────────────────────── | |
| step "Building swww v0.11.2" | |
| # swww is the wallpaper daemon JaKooLit uses for all wallpaper switching, | |
| # transitions, and effects. It runs as swww-daemon and is controlled by the | |
| # swww client. No binary releases are published — must be built with cargo. | |
| # Requires liblz4-dev for image compression at transition time. | |
| SWWW_DIR="$BUILD_DIR/swww" | |
| if ! command -v swww &>/dev/null; then | |
| sudo apt-get install -y liblz4-dev 2>/dev/null || true | |
| if [ -d "$SWWW_DIR" ]; then | |
| run_as_user "cd '$SWWW_DIR' && git fetch --tags -q && git checkout -q 'v0.11.2'" | |
| else | |
| run_as_user "git clone --depth 1 --branch 'v0.11.2' \ | |
| https://github.com/LGFae/swww.git '$SWWW_DIR'" | |
| fi | |
| run_as_user "source '$SCRIPT_HOME/.cargo/env' && cd '$SWWW_DIR' && cargo build --release" | |
| install -m755 "$SWWW_DIR/target/release/swww" /usr/local/bin/swww | |
| install -m755 "$SWWW_DIR/target/release/swww-daemon" /usr/local/bin/swww-daemon | |
| ok "swww installed" | |
| else | |
| ok "swww $(swww --version) already installed" | |
| fi | |
| # ── 11. Clone Hyprland-Dots ─────────────────────────────────────────────────── | |
| step "Cloning JaKooLit/Hyprland-Dots" | |
| # The dotfiles repo is separate from the Ubuntu install scripts — it contains | |
| # only configs, no package logic. We clone it here and copy the files manually | |
| # rather than running copy.sh, which is interactive and prompts for keyboard | |
| # layout, resolution, clock format, and per-app replace confirmations. | |
| DOTS_DIR="$BUILD_DIR/Hyprland-Dots" | |
| if [ -d "$DOTS_DIR" ]; then | |
| run_as_user "cd '$DOTS_DIR' && git pull -q" | |
| else | |
| run_as_user "git clone --depth 1 https://github.com/JaKooLit/Hyprland-Dots.git '$DOTS_DIR'" | |
| fi | |
| ok "Hyprland-Dots at $DOTS_DIR" | |
| # ── 12. Copy dotfiles ────────────────────────────────────────────────────────── | |
| step "Copying JaKooLit dotfiles to ~/.config" | |
| CONFIG="$SCRIPT_HOME/.config" | |
| # Back up everything we're about to overwrite (hypr, waybar, kitty, etc.) | |
| BACKUP="$SCRIPT_HOME/.config-backup-pre-jakoolit-$(date +%Y%m%d-%H%M%S)" | |
| run_as_user "mkdir -p '$BACKUP'" | |
| for d in hypr waybar kitty rofi swaync wofi mako; do | |
| [ -d "$CONFIG/$d" ] && run_as_user "cp -r '$CONFIG/$d' '$BACKUP/$d'" || true | |
| done | |
| ok "Existing configs backed up to $BACKUP" | |
| # Copy every top-level directory from config/ into ~/.config/ | |
| for d in "$DOTS_DIR/config"/*/; do | |
| name=$(basename "$d") | |
| run_as_user "rm -rf '$CONFIG/$name' && cp -r '$d' '$CONFIG/$name'" | |
| done | |
| ok "Dotfiles copied" | |
| # ── 13. Post-copy tweaks ─────────────────────────────────────────────────────── | |
| step "Applying post-copy tweaks" | |
| # JaKooLit separates user-specific settings into hypr/UserConfigs/ so they | |
| # survive future dot updates. Set keyboard layout to 'us' there. | |
| HYPR_USER="$CONFIG/hypr/UserConfigs" | |
| if [ -f "$HYPR_USER/UserSettings.conf" ]; then | |
| sed -i 's/kb_layout\s*=.*/kb_layout = us/' "$HYPR_USER/UserSettings.conf" 2>/dev/null || true | |
| ok "Keyboard layout set to 'us' in UserSettings.conf" | |
| fi | |
| # JaKooLit ships two waybar density configs: | |
| # "[TOP] Default" — for monitors < 1440p (more spacing, larger icons) | |
| # "[TOP] Default Higher" — for monitors >= 1440p (tighter layout) | |
| # The active config is selected via a symlink at configs/[TOP] Default. | |
| # Our monitors are 3440x1440 so we use the Higher variant. | |
| WAYBAR_CFG="$CONFIG/waybar" | |
| if [ -d "$WAYBAR_CFG/configs" ]; then | |
| HIGHER="$WAYBAR_CFG/configs/[TOP] Default Higher" | |
| ACTIVE="$WAYBAR_CFG/configs/[TOP] Default" | |
| if [ -f "$HIGHER" ] && [ ! -L "$ACTIVE" ]; then | |
| run_as_user "ln -sf '$HIGHER' '$ACTIVE'" 2>/dev/null || true | |
| ok "Waybar set to ≥1440p layout" | |
| fi | |
| fi | |
| ok "Post-copy tweaks done" | |
| # Reload Hyprland config if a session is running — otherwise the new dotfiles | |
| # won't take effect until the user manually runs hyprctl reload or logs out. | |
| if [ -n "$(ls /run/user/$(id -u "$SCRIPT_USER")/hypr/ 2>/dev/null)" ]; then | |
| HYPRLAND_INSTANCE_SIGNATURE=$(ls /run/user/$(id -u "$SCRIPT_USER")/hypr/ | head -1) | |
| export HYPRLAND_INSTANCE_SIGNATURE | |
| sudo -u "$SCRIPT_USER" hyprctl reload 2>/dev/null && ok "Hyprland config reloaded" || true | |
| fi | |
| echo "" | |
| echo "╔═══════════════════════════════════════════════════════════════╗" | |
| echo "║ JaKooLit deps + dotfiles installed! ║" | |
| echo "╠═══════════════════════════════════════════════════════════════╣" | |
| echo "║ Config reloaded automatically. If anything looks off, ║" | |
| echo "║ log out and back in for a clean session. ║" | |
| echo "║ ║" | |
| echo "║ Keybinds reference: ║" | |
| echo "║ https://github.com/JaKooLit/Hyprland-Dots/wiki/Keybinds ║" | |
| echo "╚═══════════════════════════════════════════════════════════════╝" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # ─── Hyprland user config setup for Pop!_OS 24.04 (NVIDIA, dual GPU) ───────── | |
| # Run after install-hyprland.sh: bash ~/setup-hyprland-config.sh | |
| CONFIG="$HOME/.config" | |
| mkdir -p "$CONFIG/hypr" "$CONFIG/waybar" "$CONFIG/wofi" "$CONFIG/mako" \ | |
| "$CONFIG/kitty" "$HOME/.local/share/wallpapers" | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # hyprland.conf | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/hypr/hyprland.conf" << 'EOF' | |
| # ── NVIDIA env vars (required for Pop!_OS NVIDIA build) ────────────────────── | |
| env = LIBVA_DRIVER_NAME,nvidia | |
| env = XDG_SESSION_TYPE,wayland | |
| env = GBM_BACKEND,nvidia-drm | |
| env = __GLX_VENDOR_LIBRARY_NAME,nvidia | |
| env = NVD_BACKEND,direct | |
| env = ELECTRON_OZONE_PLATFORM_HINT,wayland | |
| env = MOZ_ENABLE_WAYLAND,1 | |
| env = QT_QPA_PLATFORM,wayland | |
| env = QT_QPA_PLATFORMTHEME,qt5ct | |
| env = SDL_VIDEODRIVER,wayland | |
| # ── Monitors ───────────────────────────────────────────────────────────────── | |
| # Use `hyprctl monitors` to list your displays and adjust resolution/position. | |
| # Format: monitor=NAME,WIDTHxHEIGHT@RATE,POSITIONxY,SCALE | |
| monitor=,preferred,auto,1 | |
| # ── Autostart ──────────────────────────────────────────────────────────────── | |
| exec-once = /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 | |
| exec-once = waybar | |
| exec-once = hyprpaper | |
| exec-once = hypridle | |
| exec-once = mako | |
| exec-once = wl-paste --type text --watch cliphist store | |
| exec-once = wl-paste --type image --watch cliphist store | |
| exec-once = nm-applet --indicator | |
| # ── Look & feel ────────────────────────────────────────────────────────────── | |
| general { | |
| gaps_in = 5 | |
| gaps_out = 10 | |
| border_size = 2 | |
| col.active_border = rgba(cba6f7ff) rgba(89b4faff) 45deg | |
| col.inactive_border = rgba(595959aa) | |
| layout = dwindle | |
| resize_on_border = true | |
| } | |
| decoration { | |
| rounding = 10 | |
| blur { | |
| enabled = true | |
| size = 6 | |
| passes = 3 | |
| } | |
| shadow { | |
| enabled = true | |
| range = 4 | |
| render_power = 3 | |
| color = rgba(1a1a1aee) | |
| } | |
| } | |
| animations { | |
| enabled = true | |
| bezier = myBezier, 0.05, 0.9, 0.1, 1.05 | |
| animation = windows, 1, 7, myBezier | |
| animation = windowsOut, 1, 7, default, popin 80% | |
| animation = border, 1, 10, default | |
| animation = fade, 1, 7, default | |
| animation = workspaces, 1, 6, default | |
| } | |
| dwindle { | |
| pseudotile = true | |
| preserve_split = true | |
| } | |
| misc { | |
| force_default_wallpaper = 0 | |
| disable_hyprland_logo = true | |
| } | |
| # ── Input ───────────────────────────────────────────────────────────────────── | |
| input { | |
| kb_layout = us | |
| follow_mouse = 1 | |
| sensitivity = 0 | |
| touchpad { | |
| natural_scroll = true | |
| } | |
| } | |
| gestures { | |
| # workspace_swipe removed in newer Hyprland — use 3-finger swipe natively | |
| } | |
| # ── Keybindings ─────────────────────────────────────────────────────────────── | |
| $mod = SUPER | |
| # Basics | |
| bind = $mod, Return, exec, kitty | |
| bind = $mod, Q, killactive | |
| bind = $mod SHIFT, Q, exit | |
| bind = $mod, E, exec, thunar | |
| bind = $mod, Space, exec, wofi --show drun | |
| bind = $mod, V, exec, cliphist list | wofi --dmenu | cliphist decode | wl-copy | |
| bind = $mod, L, exec, hyprlock | |
| bind = $mod, F, fullscreen | |
| # Screenshot | |
| bind = , Print, exec, hyprshot -m output | |
| bind = SHIFT, Print, exec, hyprshot -m region | |
| bind = $mod, Print, exec, hyprshot -m window | |
| # Focus | |
| bind = $mod, left, movefocus, l | |
| bind = $mod, right, movefocus, r | |
| bind = $mod, up, movefocus, u | |
| bind = $mod, down, movefocus, d | |
| bind = $mod, H, movefocus, l | |
| bind = $mod, L, movefocus, r | |
| bind = $mod, K, movefocus, u | |
| bind = $mod, J, movefocus, d | |
| # Move windows | |
| bind = $mod SHIFT, left, movewindow, l | |
| bind = $mod SHIFT, right, movewindow, r | |
| bind = $mod SHIFT, up, movewindow, u | |
| bind = $mod SHIFT, down, movewindow, d | |
| bind = $mod SHIFT, H, movewindow, l | |
| bind = $mod SHIFT, L, movewindow, r | |
| bind = $mod SHIFT, K, movewindow, u | |
| bind = $mod SHIFT, J, movewindow, d | |
| # Resize | |
| binde = $mod CTRL, right, resizeactive, 30 0 | |
| binde = $mod CTRL, left, resizeactive, -30 0 | |
| binde = $mod CTRL, up, resizeactive, 0 -30 | |
| binde = $mod CTRL, down, resizeactive, 0 30 | |
| # Workspaces | |
| bind = $mod, 1, workspace, 1 | |
| bind = $mod, 2, workspace, 2 | |
| bind = $mod, 3, workspace, 3 | |
| bind = $mod, 4, workspace, 4 | |
| bind = $mod, 5, workspace, 5 | |
| bind = $mod, 6, workspace, 6 | |
| bind = $mod, 7, workspace, 7 | |
| bind = $mod, 8, workspace, 8 | |
| bind = $mod, 9, workspace, 9 | |
| bind = $mod, 0, workspace, 10 | |
| bind = $mod SHIFT, 1, movetoworkspace, 1 | |
| bind = $mod SHIFT, 2, movetoworkspace, 2 | |
| bind = $mod SHIFT, 3, movetoworkspace, 3 | |
| bind = $mod SHIFT, 4, movetoworkspace, 4 | |
| bind = $mod SHIFT, 5, movetoworkspace, 5 | |
| bind = $mod SHIFT, 6, movetoworkspace, 6 | |
| bind = $mod SHIFT, 7, movetoworkspace, 7 | |
| bind = $mod SHIFT, 8, movetoworkspace, 8 | |
| bind = $mod SHIFT, 9, movetoworkspace, 9 | |
| bind = $mod SHIFT, 0, movetoworkspace, 10 | |
| bind = $mod, mouse_down, workspace, e+1 | |
| bind = $mod, mouse_up, workspace, e-1 | |
| # Float / tile toggle | |
| bind = $mod SHIFT, space, togglefloating | |
| bind = $mod, P, pseudo | |
| # Mouse window control | |
| bindm = $mod, mouse:272, movewindow | |
| bindm = $mod, mouse:273, resizewindow | |
| # Media / brightness | |
| bindel = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ | |
| bindel = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- | |
| bindl = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle | |
| bindl = , XF86AudioPlay, exec, playerctl play-pause | |
| bindl = , XF86AudioNext, exec, playerctl next | |
| bindl = , XF86AudioPrev, exec, playerctl previous | |
| bindel = , XF86MonBrightnessUp, exec, brightnessctl set 5%+ | |
| bindel = , XF86MonBrightnessDown, exec, brightnessctl set 5%- | |
| # ── Window rules ───────────────────────────────────────────────────────────── | |
| windowrule { | |
| name = float-pavucontrol | |
| match:class = pavucontrol | |
| float = true | |
| } | |
| windowrule { | |
| name = float-nm-connection-editor | |
| match:class = nm-connection-editor | |
| float = true | |
| } | |
| windowrule { | |
| name = float-thunar-file-ops | |
| match:class = thunar | |
| match:title = File Operation.* | |
| float = true | |
| } | |
| windowrule { | |
| name = suppress-maximize-events | |
| match:class = .* | |
| suppress_event = maximize | |
| } | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # hyprpaper.conf — using a solid color until you add a wallpaper | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Create a minimal dark wallpaper with ImageMagick if available, else skip | |
| if command -v convert &>/dev/null; then | |
| convert -size 1920x1080 gradient:"#1e1e2e-#313244" \ | |
| "$HOME/.local/share/wallpapers/default.png" 2>/dev/null && \ | |
| cat > "$CONFIG/hypr/hyprpaper.conf" << WALLEOF | |
| preload = $HOME/.local/share/wallpapers/default.png | |
| wallpaper = ,$HOME/.local/share/wallpapers/default.png | |
| splash = false | |
| WALLEOF | |
| echo " Wallpaper generated" | |
| else | |
| cat > "$CONFIG/hypr/hyprpaper.conf" << 'WALLEOF' | |
| # Add your wallpaper: | |
| # preload = /path/to/image.png | |
| # wallpaper = ,/path/to/image.png | |
| splash = false | |
| WALLEOF | |
| echo " No imagemagick — add wallpaper path to ~/.config/hypr/hyprpaper.conf manually" | |
| fi | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # hypridle.conf | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/hypr/hypridle.conf" << 'EOF' | |
| general { | |
| lock_cmd = pidof hyprlock || hyprlock | |
| before_sleep_cmd = loginctl lock-session | |
| after_sleep_cmd = hyprctl dispatch dpms on | |
| } | |
| listener { | |
| timeout = 300 # 5 min: dim | |
| on-timeout = brightnessctl -s set 20% | |
| on-resume = brightnessctl -r | |
| } | |
| listener { | |
| timeout = 360 # 6 min: lock | |
| on-timeout = loginctl lock-session | |
| } | |
| listener { | |
| timeout = 600 # 10 min: turn off displays | |
| on-timeout = hyprctl dispatch dpms off | |
| on-resume = hyprctl dispatch dpms on | |
| } | |
| listener { | |
| timeout = 1200 # 20 min: suspend | |
| on-timeout = systemctl suspend | |
| } | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # hyprlock.conf | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/hypr/hyprlock.conf" << 'EOF' | |
| general { | |
| disable_loading_bar = true | |
| hide_cursor = true | |
| grace = 0 | |
| } | |
| background { | |
| monitor = | |
| path = screenshot | |
| blur_passes = 3 | |
| blur_size = 7 | |
| noise = 0.0117 | |
| contrast = 0.8917 | |
| brightness = 0.8172 | |
| vibrancy = 0.1696 | |
| } | |
| input-field { | |
| monitor = | |
| size = 250, 50 | |
| outline_thickness = 3 | |
| dots_size = 0.33 | |
| dots_spacing = 0.15 | |
| outer_color = rgb(151515) | |
| inner_color = rgb(200, 200, 200) | |
| font_color = rgb(10, 10, 10) | |
| fade_on_empty = true | |
| placeholder_text = <i>Password...</i> | |
| hide_input = false | |
| position = 0, -80 | |
| halign = center | |
| valign = center | |
| } | |
| label { | |
| monitor = | |
| text = cmd[update:1000] echo "<b>$(date +"%H:%M")</b>" | |
| color = rgba(200, 200, 200, 1.0) | |
| font_size = 64 | |
| font_family = Noto Sans Bold | |
| position = 0, 160 | |
| halign = center | |
| valign = center | |
| } | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # waybar config | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/waybar/config.jsonc" << 'EOF' | |
| { | |
| "layer": "top", | |
| "position": "top", | |
| "height": 36, | |
| "spacing": 4, | |
| "modules-left": ["hyprland/workspaces", "hyprland/window"], | |
| "modules-center": ["clock"], | |
| "modules-right": ["tray", "pulseaudio", "network", "battery", "cpu", "memory"], | |
| "hyprland/workspaces": { | |
| "format": "{id}", | |
| "on-click": "activate" | |
| }, | |
| "hyprland/window": { | |
| "max-length": 60 | |
| }, | |
| "clock": { | |
| "format": "{:%a %b %d %H:%M}", | |
| "tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>" | |
| }, | |
| "cpu": { | |
| "format": " {usage}%", | |
| "interval": 2 | |
| }, | |
| "memory": { | |
| "format": " {used:.1f}G", | |
| "interval": 5 | |
| }, | |
| "pulseaudio": { | |
| "format": "{icon} {volume}%", | |
| "format-muted": " muted", | |
| "format-icons": { "default": ["", "", ""] }, | |
| "on-click": "pavucontrol" | |
| }, | |
| "network": { | |
| "format-wifi": " {essid}", | |
| "format-ethernet": " {ipaddr}", | |
| "format-disconnected": " offline", | |
| "tooltip-format": "{ifname}: {ipaddr}/{cidr}" | |
| }, | |
| "battery": { | |
| "format": "{icon} {capacity}%", | |
| "format-charging": " {capacity}%", | |
| "format-icons": ["", "", "", "", ""], | |
| "states": { "warning": 30, "critical": 15 } | |
| }, | |
| "tray": { | |
| "spacing": 8 | |
| } | |
| } | |
| EOF | |
| cat > "$CONFIG/waybar/style.css" << 'EOF' | |
| * { | |
| font-family: "Noto Sans", "Font Awesome 6 Free", sans-serif; | |
| font-size: 13px; | |
| border: none; | |
| border-radius: 0; | |
| min-height: 0; | |
| } | |
| window#waybar { | |
| background-color: rgba(30, 30, 46, 0.92); | |
| color: #cdd6f4; | |
| } | |
| #workspaces button { | |
| padding: 0 8px; | |
| color: #6c7086; | |
| background: transparent; | |
| } | |
| #workspaces button.active { | |
| color: #cba6f7; | |
| border-bottom: 2px solid #cba6f7; | |
| } | |
| #workspaces button:hover { | |
| background: rgba(203, 166, 247, 0.15); | |
| } | |
| #clock, #cpu, #memory, #network, #pulseaudio, #battery, #tray { | |
| padding: 0 10px; | |
| color: #cdd6f4; | |
| } | |
| #battery.warning { color: #fab387; } | |
| #battery.critical { color: #f38ba8; } | |
| #window { | |
| padding: 0 10px; | |
| color: #a6adc8; | |
| font-style: italic; | |
| } | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # wofi config | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/wofi/style.css" << 'EOF' | |
| window { | |
| background-color: rgba(30, 30, 46, 0.95); | |
| border-radius: 12px; | |
| border: 2px solid #cba6f7; | |
| } | |
| #input { | |
| background-color: #313244; | |
| color: #cdd6f4; | |
| border: none; | |
| border-radius: 8px; | |
| padding: 8px 12px; | |
| margin: 8px; | |
| font-size: 14px; | |
| } | |
| #inner-box { | |
| background: transparent; | |
| } | |
| #outer-box { | |
| padding: 8px; | |
| } | |
| #entry { | |
| padding: 6px 10px; | |
| border-radius: 6px; | |
| } | |
| #entry:selected { | |
| background-color: #45475a; | |
| } | |
| #text { | |
| color: #cdd6f4; | |
| font-size: 13px; | |
| } | |
| EOF | |
| cat > "$CONFIG/wofi/config" << 'EOF' | |
| width=480 | |
| height=400 | |
| location=center | |
| show=drun | |
| prompt=Search... | |
| filter_rate=100 | |
| allow_markup=true | |
| no_actions=true | |
| halign=fill | |
| orientation=vertical | |
| content_halign=fill | |
| insensitive=true | |
| allow_images=true | |
| image_size=24 | |
| gtk_dark=true | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # mako (notifications) | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/mako/config" << 'EOF' | |
| background-color=#1e1e2e | |
| text-color=#cdd6f4 | |
| border-color=#cba6f7 | |
| border-radius=10 | |
| border-size=2 | |
| padding=12,16 | |
| default-timeout=5000 | |
| max-visible=5 | |
| font=Noto Sans 11 | |
| width=360 | |
| height=120 | |
| anchor=top-right | |
| margin=10 | |
| layer=overlay | |
| EOF | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # kitty (terminal) | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| cat > "$CONFIG/kitty/kitty.conf" << 'EOF' | |
| # Catppuccin Mocha theme to match waybar/wofi | |
| foreground #CDD6F4 | |
| background #1E1E2E | |
| background_opacity 0.92 | |
| # Colors | |
| color0 #45475A | |
| color1 #F38BA8 | |
| color2 #A6E3A1 | |
| color3 #F9E2AF | |
| color4 #89B4FA | |
| color5 #F5C2E7 | |
| color6 #94E2D5 | |
| color7 #BAC2DE | |
| color8 #585B70 | |
| color9 #F38BA8 | |
| color10 #A6E3A1 | |
| color11 #F9E2AF | |
| color12 #89B4FA | |
| color13 #F5C2E7 | |
| color14 #94E2D5 | |
| color15 #A6ADC8 | |
| cursor #F5E0DC | |
| cursor_text_color #1E1E2E | |
| selection_foreground #1E1E2E | |
| selection_background #F5E0DC | |
| font_family monospace | |
| font_size 12.0 | |
| window_padding_width 8 | |
| confirm_os_window_close 0 | |
| EOF | |
| echo "" | |
| echo "╔══════════════════════════════════════════════════════════╗" | |
| echo "║ Hyprland config setup complete! ║" | |
| echo "╠══════════════════════════════════════════════════════════╣" | |
| echo "║ Configs written to: ║" | |
| echo "║ ~/.config/hypr/ (hyprland, hyprpaper, ║" | |
| echo "║ hypridle, hyprlock) ║" | |
| echo "║ ~/.config/waybar/ (config.jsonc, style.css) ║" | |
| echo "║ ~/.config/wofi/ (config, style.css) ║" | |
| echo "║ ~/.config/mako/ (config) ║" | |
| echo "║ ~/.config/kitty/ (kitty.conf) ║" | |
| echo "╠══════════════════════════════════════════════════════════╣" | |
| echo "║ To use: log out → select Hyprland at login screen ║" | |
| echo "║ Key bindings: ║" | |
| echo "║ Super+Return → kitty terminal ║" | |
| echo "║ Super+Space → wofi app launcher ║" | |
| echo "║ Super+Q → close window ║" | |
| echo "║ Super+L → lock screen ║" | |
| echo "║ Super+E → thunar file manager ║" | |
| echo "║ Super+V → clipboard history ║" | |
| echo "║ PrintScr → screenshot (full screen) ║" | |
| echo "║ Shift+Print → screenshot (select region) ║" | |
| echo "╚══════════════════════════════════════════════════════════╝" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment