Installation¶
JuhRadial MX builds from source on every supported distribution. The fastest path is the one-line installer, which detects your distro, pulls the right packages, compiles the Rust daemon, and wires up autostart and device permissions for you. Manual and NixOS paths are documented below for people who prefer to drive each step themselves.
Note
JuhRadial MX targets Wayland first (KDE Plasma 6, GNOME, Hyprland, COSMIC, Sway, niri) and also runs on X11. See Compositor-Support for per-compositor behaviour, and Features for what you get once it is running.
Contents¶
- Quick start: the one-line installer
- What the installer does
- Requirements
- Manual installation per distro
- Fedora
- Ubuntu / Debian
- Arch Linux
- openSUSE Tumbleweed
- NixOS (flake)
- Build from source
- Updating
- After installing
Quick start: the one-line installer¶
The script is interactive: it prints a summary of your system (distro, kernel, session, desktop, whether a Logitech receiver is detected) and asks you to confirm before it changes anything.
Warning
Do not run the installer as root or under sudo. It refuses to run as root and asks for sudo only on the individual steps that need it (package install, copying files into /usr/local and /usr/share, installing udev rules). The systemd service and config live in your user account, so it must run as your normal user.
What the installer does¶
The installer (install.sh) runs as a fresh install or an in-place upgrade, depending on whether /opt/juhradial-mx already exists. A full run has six visible steps plus a preflight phase.
| Phase | What happens |
|---|---|
| Detect | Reads /etc/os-release to resolve a distro family (arch, fedora, debian, opensuse), falling back to ID_LIKE and then to the available package manager (pacman, apt-get, dnf, zypper). Detects Wayland vs X11, the desktop/compositor, an existing install, and whether a Logitech device (USB vendor 046d) is present. |
| 1. Dependencies | Installs the build and runtime packages for your distro family (Rust/Cargo, Python + PyQt6, GTK4/libadwaita, gtk4-layer-shell, HID and evdev dev headers, D-Bus/systemd dev headers, ydotool, git, make). |
| 2. Fetch source | Clones https://github.com/JuhLabs/juhradial-mx into /opt/juhradial-mx (or, on upgrade, git fetch + git reset --hard origin/master + git clean -fd). |
| 3. Build daemon | Ensures a usable Rust toolchain (see the rustup note below), then runs cargo build --release in daemon/. |
| 4. Install files | Copies the daemon binary, overlay scripts, theme/device assets, launcher scripts, desktop entries, icons, the systemd user unit, and udev rules into place (see layout table). |
| 5. Desktop integration | Applies compositor-specific setup (Hyprland window rules, GNOME cursor-helper extension). KDE, Sway, and COSMIC need no extra config. |
| 6. Enable service | Reloads the systemd user manager, enables juhradialmx-daemon, sets up ydotoold autostart, then starts (or restarts) the daemon. |
Install layout¶
| Path | Contents |
|---|---|
/opt/juhradial-mx |
Cloned source tree (used for updates) |
/usr/local/bin/juhradiald |
Compiled Rust daemon |
/usr/local/bin/juhradial-mx, /usr/local/bin/juhradial-settings |
Launcher scripts |
/usr/share/juhradial/ |
Overlay Python, Flow module, locales, theme and device assets |
/usr/share/applications/ |
.desktop entries for the app and settings |
~/.config/systemd/user/juhradialmx-daemon.service |
systemd user service |
~/.config/juhradial/ |
Your config.json (see Configuration) |
udev rules, uinput, and the input group¶
For non-root access to the mouse and for action injection, the installer:
- Installs
99-juhradialmx.rulesinto/etc/udev/rules.d/and removes the older99-logitech-hidpp.rulesif present. - Installs
60-ydotool-uinput.rulesso the logged-in user can open/dev/uinput(used by bothydotooland the daemon's own virtual input device). Stock distros ship/dev/uinputasroot:root 0600. - Loads the
uinputkernel module now (modprobe uinput) and on boot (/etc/modules-load.d/juhradial-uinput.conf). - Reloads rules (
udevadm control --reload-rules+udevadm trigger). - Ensures the
inputgroup exists and adds your user to it (device access via hidraw/evdev comes fromGROUP="input").
Info
If your user was just added to the input group, log out and back in for the new group membership to take effect. Until then the daemon cannot open the device.
ydotoold (Wayland action injection)¶
Keyboard-shortcut button actions and thumb-wheel actions (volume, zoom, horizontal scroll) are injected through the kernel uinput device via ydotool, which needs its background daemon ydotoold running. The installer prefers a packaged ydotool.service / ydotoold.service if your distro ships one; otherwise it writes a minimal ~/.config/systemd/user/ydotoold.service and enables it so it autostarts on login. If ydotoold is missing, shortcut and thumb-wheel actions may not work on Wayland.
The rustup bootstrap¶
The committed Cargo.lock is lockfile format v4 (needs Cargo >= 1.78) and the toml_edit dependency needs rustc >= 1.76. Several distros ship an older toolchain (Ubuntu 24.04 ships Rust 1.75), which cannot build the daemon.
The installer checks the active Cargo version and, if it is older than 1.78 or missing entirely, bootstraps the official toolchain non-interactively:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
. "$HOME/.cargo/env"
Tip
On Ubuntu 24.04 this happens automatically. If you are installing manually there and cargo build fails on the lockfile version, run the two commands above (or rustup update stable) and rebuild.
Requirements¶
- A Wayland compositor (KDE Plasma 6, GNOME, Hyprland, COSMIC, Sway, niri) or X11.
- Rust toolchain (Cargo >= 1.78) to build the daemon. The installer provides this if needed.
- Python 3 with PyQt6 (overlay) and GTK4 + libadwaita via PyGObject (settings UI).
- XWayland, used for overlay window positioning on Wayland.
- A supported mouse (Logitech MX Master 4 / 3S / 3 for full HID++, or any mouse in generic evdev mode). See FAQ for device coverage.
Manual installation per distro¶
Each manual path is: install dependencies, clone, build the daemon, then run. To get autostart, udev rules, the input group, and ydotoold set up exactly as the one-line installer does, prefer the installer or replicate the steps in What the installer does.
Fedora¶
Family also covers RHEL, CentOS Stream, Rocky, AlmaLinux, Nobara, Ultramarine.
sudo dnf install -y \
rust cargo \
python3 python3-pip \
python3-pyqt6 qt6-qtsvg \
python3-gobject gtk4 libadwaita \
gtk4-layer-shell \
python3-cryptography \
dbus-devel systemd-devel \
libevdev-devel hidapi-devel \
ydotool \
git make
Ubuntu / Debian¶
Family also covers Linux Mint, Pop!_OS, elementary, Kali, Zorin, KDE neon, MX Linux.
sudo apt-get update
sudo apt-get install -y \
rustc cargo \
python3 python3-pip python3-venv \
python3-pyqt6 python3-pyqt6.qtsvg \
python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 \
python3-cryptography \
libdbus-1-dev libsystemd-dev \
libevdev-dev libhidapi-dev \
ydotool \
git make build-essential
# Optional: layer-shell support where the package exists
sudo apt-get install -y libgtk4-layer-shell0
Note
On Ubuntu 24.04 the distro Rust (1.75) is too old for the committed lockfile. Bootstrap rustup as shown in The rustup bootstrap before building.
Arch Linux¶
Family also covers Manjaro, EndeavourOS, Garuda, Artix, CachyOS, ArcoLinux, Archcraft.
sudo pacman -S --noconfirm --needed \
rust \
python python-pip \
python-pyqt6 qt6-svg \
python-gobject gtk4 libadwaita \
gtk4-layer-shell \
python-cryptography \
dbus systemd-libs \
libevdev hidapi \
ydotool \
git make base-devel
openSUSE Tumbleweed¶
sudo zypper install -y \
rust cargo \
python3 python3-pip \
python3-PyQt6 \
python3-gobject gtk4 libadwaita-devel \
python3-cryptography \
dbus-1-devel systemd-devel \
libevdev-devel libhidapi-devel \
ydotool \
git make
# layer-shell may not be in your enabled repos; safe to skip if unavailable
sudo zypper install -y gtk4-layer-shell || true
Note
On openSUSE the PyQt6 package is python3-PyQt6 (capital Q), unlike the lowercase python3-pyqt6 used on Fedora and Debian. gtk4-layer-shell is not always present in the default repositories; the app still runs without it (layer-shell is only required for niri-style compositors that lack cursor IPC).
NixOS (flake)¶
The repository ships a flake.nix exposing a package, a NixOS module, and a dev shell.
Try it without installing:
Enable it declaratively in your system flake. Add the input:
Then import the module and enable the service in your host config:
The module installs the package system-wide, applies the bundled 99-juhradialmx.rules udev rules for non-root device access, and ensures the input group exists. Rebuild with sudo nixos-rebuild switch --flake .#<host>.
Contributors can drop into a ready toolchain (Rust, Python with PyQt6 + PyGObject, GTK4/libadwaita, Qt6) with:
Build from source¶
If you want to build and run without a full system install:
git clone https://github.com/JuhLabs/juhradial-mx.git
cd juhradial-mx
# Build the Rust daemon
cd daemon && cargo build --release && cd ..
# Run the overlay + daemon
./scripts/juhradial-mx.sh
The daemon binary lands at daemon/target/release/juhradiald. You still need the runtime dependencies for your distro (PyQt6, GTK4/libadwaita, ydotool) and, for non-root device access, the udev rules and input group membership described above. For a full system install identical to the one-line path, run install.sh from the cloned tree.
To run the daemon directly with verbose logging while debugging, see Troubleshooting:
Updating¶
Re-run the same one-line command. When /opt/juhradial-mx already exists, the installer switches to upgrade mode: it fetches the latest master, hard-resets the source tree, rebuilds the daemon, reinstalls files and udev rules, and restarts the running service.
On NixOS, update the flake input and rebuild:
nix flake update juhradial-mx # in your system flake directory
sudo nixos-rebuild switch --flake .#<host>
For a source checkout, pull and rebuild:
After installing¶
- Launch from your application menu (JuhRadial MX) or run
juhradial-mx. Hold the gesture (thumb) button on your MX Master to open the radial menu. - Open the settings app (
juhradial-settings) to remap buttons, pick a theme, and configure haptics, scroll, Easy-Switch, and Flow. See Configuration and Features. - Check the daemon:
Info
Two cases need a session restart (log out and back in): first time your user is added to the input group, and on GNOME for the cursor-helper Shell extension to load. If the menu appears at the top-left corner on GNOME, this is why.
If the menu does not appear or the mouse is not detected, head to Troubleshooting. For how the daemon, overlay, and settings app fit together, see Architecture. Return to Home for the full page index.