Technical Documentation: end-4/dots-hyprland
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`.github/README.md`)
[!WARNING]
Hyprland 0.55 update:
If your distro has not shipped Hyprland 0.55 and/or you're not ready for it, you should switch to the Pre-Hyprland Luaification release (or not update yet, if you're going to do that). See the wiki for more info: Install | Update
What this is/isn't
- Technically, configuration files
- Realistically, mostly the custom graphical shell
- NOT a system setup script: no graphic drivers, no zram setup, etc.
Notable features
- Overview: Shows open apps with live previews
- AI: Gemini, Ollama, and more
- QoL: screen translation, anti-flashbang, Google Lens
- Material themes: Choose your wallpaper, done, enjoy
- Transparent installation: Every command is shown before it's run
Installation
- IMPORTANT: Hyprland 0.55 Update: If your distro has not shipped Hyprland 0.55 and/or you're not ready for it, you should switch to the Pre-Hyprland Luaification release. See the wiki for more info
- Just run
bash <(curl -s https://ii.clsty.link/get)- Or, clone this repo and run
./setup install - See the wiki for more details
- Or, clone this repo and run
- Keybinds: Should be somewhat familiar to Windows or GNOME users. Important ones:
Super+/= keybind listSuper+Enter= terminal
Software overview
| Software | Purpose |
|---|---|
| Hyprland | The compositor (manages and renders windows) |
| Quickshell | A QtQuick-based widget system, used for the status bar, sidebars, etc. |
| Others | See deps-info.md |
Discord
[ Server link](https://discord.gg/GtdRBXgMwq) | I hope this provides a friendlier environment for support without needing me to personally accept every friend request/DM. For real issues, prefer GitHubWidget system: Quickshell | Support: Yes
| AI, settings app | Some widgets |
|---|---|
| Window management | wow look its orange |
@clsty for making the dotfiles accessible by taking care of the install script and many other things
@midn8hustlr for greatly improving the color generation system
@outfoxxed for being extremely supportive in my Quickshell journey
Quickshell: Soramane, FridayFaerie, nydragon
AGS: Aylur, kotontrion
EWW: fufexan
I promise not to attempt an +ULTRARICOSHOT irl... Coins can go here: https://github.com/sponsors/end-4
Tentacle cat hub twinkle internet points
- Unsupported!
- Source: illogical-impulse AGS in
ii-agsbranch, others inarchivebranch. - List is in reverse chronological order
illogical-impulse (AGS)
Widget system: AGS | Support: No
| AI | Common widgets |
|---|---|
| Window management | Weeb power |
m3ww
Widget system: EWW | Support: No
NovelKnock
Widget system: EWW | Support: No
Hybrid
Widget system: EWW | Support: No
Windoes
Widget system: EWW | Support: No
- Inspiration: osu!lazer (Hybrid), Windows 11 (Windoes), AvdanOS (NovelKnock), Material Design 3 (m3ww & later)
- Copying: Absolutely, feel free. Just follow the license and it's all good
Overview (`licenses/README.md`)
Licenses
This repository contains code from other repositories. Files containing such code should include a license notice, and a copy should be stored in this folder.
Overview (`sdata/README.md`)
This folder mainly contains data for the script setup.
- TODO: output the logs to a temp file, then show the path of the file so users will be able to read it again or upload it to issue.
- TODO: unify the message output via functions (for example
log_error,log_warning).
Overview (`dots-extra/via-nix/README.md`)
This folder contains tweakd configs when --via-nix is specified.
Overview (`sdata/dist-arch/README.md`)
Install scripts for Arch Linux
- See also Install scripts | illogical-impulse
Old Dependency Installation Method
The old deps install method mainly involved ./sdata/dependencies.conf (which has been removed now).
Current Dependency Installation
Local PKGBUILDs under ./sdata/dist-arch/ are used to install dependencies.
The mechanism is introduced by Makrennel in PR#570.
Why is this awesome?
- It makes it possible to control version since some packages may involve breaking changes from time to time.
- It makes the dependency trackable for package manager, so that you always know why you have installed some package.
- As a result, it enables a workable uninstall process.
The PKGBUILDs contains two forms of dependencies:
- Package name written in dependencies, like a "meta" package.
- Normal PKGBUILD content to build dependencies, e.g. AGS, which is often for version controlling.
Note
pkgver()should be removed fromPKGBUILDcuz it will modify thePKGBUILDwhich is tracked by Git and should not be modified during building.
Overview (`sdata/dist-fedora/README.md`)
Install scripts for Fedora Linux
Note:
- The scripts here are not meant to be executed directly.
- This folder should reflect the equivalents of
/sdata/dist-arch/but under Fedora.- When
/sdata/dist-arch/is newer than this folder, an update on this folder is very likely needed. - Useful link: Commit history on sdata/dist-arch/
- When
- See also Install scripts | illogical-impulse
Contributors
- Author: ririko6z
Tested
- It has been tested on Fedora Everything 44 on the
x86_64platform.
Post installation
- Fix the issue of the right column crashing when clicking the
Detailsbutton in Wi-Fi mode. Edit this file:~/.config/illogical-impulse/config.json - Replace
pacmanwithdnfin update app.
@@ 44,3 44,3 @@
- "apps": {
- "bluetooth": "kcmshell6 kcm_bluetooth",
- "network": "kitty -1 fish -c nmtui",
- "update": "kitty -1 --hold=yes fish -i -c 'pkexec pacman -Syu'",
+ "apps": {
+ "bluetooth": "kcmshell6 kcm_bluetooth",
+ "network": "plasmawindowed org.kde.plasma.networkmanagement",
+ "update": "kitty -1 --hold=yes fish -i -c 'sudo dnf update -y'",Overview (`sdata/dist-gentoo/README.md`)
Install scripts for Gentoo
Note:
- The scripts here are not meant to be executed directly.
- This folder should reflect the equivalents of
/sdata/dist-arch/but under Gentoo.- When
/sdata/dist-arch/is newer than this folder, an update on this folder is very likely needed. - Useful link: Commit history on sdata/dist-arch/
- When
- See also Install scripts | illogical-impulse
Contributors
- Author: jwihardi
This directory contains the Gentoo dependency definitions used by the main
illogical-impulse installer. It mirrors the package groups maintained insdata/dist-arch with Gentoo metapackages and a local Portage
overlay.
The complete package set is currently intended for amd64. Some individual
ebuilds also carry arm64 or x86 keywords, but not every illogical-impulse
metapackage supports those architectures yet.
How installation works
The dependency installer:
- Installs
eselect-repository,rsync, andsmart-live-rebuild. - Enables the GURU repository when necessary.
- Copies
overlay/to/var/db/repos/ii-dotsand installs its
repository configuration. - Generates
/etc/portage/package.accept_keywords/illogical-impulsefor the
current architecture fromkeywords. - Installs
useflagsandadditional-useflags
as/etc/portage/package.use/illogical-impulse. - Syncs configured repositories, updates
@world, and rebuilds
installed live packages. - Emerges every metapackage listed in
metapkgs.sh.
Note: The installer also ensures Python 3.12 is installed.
The ii-dots repository has auto-sync = no. A normal emerge --sync does
not update it; rerun the illogical-impulse installer to copy the current
overlay into Portage.
Repository contents
| Path | Purpose |
|---|---|
overlay/ |
Local ebuild repository containing the II metapackages and packages not provided in the required form elsewhere. |
ii-dots.conf |
Portage repository configuration installed under /etc/portage/repos.conf. |
keywords |
Packages that must accept testing or unkeyworded ebuilds. The installer appends the current testing keyword. |
useflags |
Direct feature requirements for the II package set. |
additional-useflags |
Transitive feature requirements appended to the same Portage package.use file. |
metapkgs.sh |
Package groups installed and removed by the dependency scripts. |
MicroTeX and Material Symbols use live ebuilds. Quickshell keeps the -git
package name for compatibility but is pinned to a tested upstream commit.
Versioned theme and font ebuilds may also use pinned commits as their source.
System requirements
Choose either elogind or systemd globally so all installed packages use
the same session manager. On OpenRC, elogind is recommended and
must be running so the user session receives XDG_RUNTIME_DIR.
Uninstalling
The uninstall path removes the II metapackages, local overlay, repository
configuration, keyword file, and USE file. It does not automatically remove
dependencies that have become unused; review emerge --depclean --pretend
before deciding whether to depclean them.
Overview (`sdata/dist-nix/README.md`)
Install scripts using Nix to achieve cross-distros
- This directory is currently WIP.
- See also Install scripts | illogical-impulse
- See also #1061
NOTE: The dist-nix is not for NixOS but every distro, using Nix and home-manager.
As we all know Nix and Home-manager has two major functionalities:
- Handling dependencies (i.e. package installation)
- Handling dotfiles
They are discussed in following sections.
Handling dependencies
Status
Partially works. See Discussion #2382.
plan
Note that this script must be idempotent.
TODO:
- Fix all TODOs inside
dist-nix. (search online) - Since Nix uses a large number of inodes, need to warn user if inode-limited filesystem (typically ext4) is used.
- Deal with error when running
systemctl --user enable ydotool --now:plainFailed to connect to user scope bus via local transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user) - Handle problem that
pkill qsandpkill hyprlanddoes not work (should be.quickshell-wraand.Hyprland-wrappwhen installed via Nix).
Attentions
PAM
On non-NixOS distros, programs using PAM (typically screen locker) will not work if installed via Nix, so user has to use their own distro's package for the screen lock.
- One problem is that Debian(-based) distros use modified version of PAM which supports
@includedirective in/etc/pam.dconfig files but the PAM from Nix does not support it, see this comment. - Another problem is the location of a suid helper binary that is necessary, see this comment.
As commented by @Cu3PO42 , both the problem could be solved by using the system-provided libpam instead.
See also caelestia-dots/shell#668.
GPU
On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch.
nixGL should be used to address the problem.
Since home-manager 25.11, for non-NixOS just set the following:
targets.genericLinux.enable = true;Then during building, home-manager will show a message to tell you running a command manually to configure GPU, like:
sudo /nix/store/<HASH>-non-nixos-gpu/bin/non-nixos-gpu-setupIt runs a bash script with following content:
#!/nix/store/<HASH>-bash-<VERSION>/bin/bash
set -e
# Install the systemd service file and ensure that the store path won't be
# garbage-collected as long as it's installed.
unit_path=/etc/systemd/system/non-nixos-gpu.service
ln -sf /nix/store/<HASH>-non-nixos-gpu/resources/non-nixos-gpu.service "$unit_path"
ln -sf "$unit_path" "/nix/var/nix"/gcroots/non-nixos-gpu.service
systemctl daemon-reload
systemctl enable non-nixos-gpu.service
systemctl restart non-nixos-gpu.serviceNote: it uses systemctl, maybe won't work for OpenRC...
See gpu-non-nixos.
Handling dot files
Status
Paused, until some suitable method has been confirmed to meet the requirements below.
Requirements
About handling the dotfiles, i.e. dots/, if we are doing this using Nix then the following requirements must be fulfilled.
1. Allow modifications over the existing dotfiles.
Current state of ./setup install:
- After finishing running
./setup install, users can modify any dotfiles in a traditional way, and if they run./setup installagain to update then they need to skip the steps which overwrite the targets that they have modified and later sync the upgrade manually for such targets by themselves.- For Hyprland, specially we have a
customfolder along with~/.config/hypr/hyprland.confwhich will only get overwritten the first time but not the later times running./setup install.
- For Hyprland, specially we have a
- This works but is not elegant. An experimental solution is using yaml config to store the selected behavior for each target, see #2137.
If we use Nix to handle dotfiles, then it must be at least better than the current state described above, mainly in terms of convenience and automation.
2. Allow choosing targets.
This is similar to the above. For example user may want to use their own ~/.config/foot instead of the files under dots/.config/foot entirely.
3. Easy developing dotfiles or at least not worse than current state.
About the current state:
- @clsty: "If I were the one who develops the dotfiles, I will make changes to the local Git repo
dots-hyprlandand rerun./setup install-files -fto apply the changes to observe the outcome." - @end-4 (who develops the dots; see comment): "I modify my local copy of stuff, copy the relevant parts over, optionally selectively pick changes then commit. It's.... the most obvious way but I guess not necessarily the cleanest"
If we use Nix to handle dotfiles, then it must be at least better than the current state described above, mainly in terms of convenience and automation.
4. Others
Find out a good method to avoid what @end-4 mentioned:
About home-manager, from my limited understanding of and experience with it, any change to the config files require a rebuild right? If this is indeed the case, switching entirely to this is not okay. Having to wait 20 seconds for each change is absurd.
Some information may help, e.g. @darsh032 commented:
I mean thats not really needed you can use mkOutOfStoreSymlink or use hjem-impure to change the configs without rebuilding
And also the "hmrice" mentioned by @Markus328 , and the flake.nix (for quickshell only) mentioned by @darsh032 .
Overview (`sdata/uv/README.md`)
Why is this important?
Instead of installing python packages via system package manager, we should install them into virtual environment.
This is important because there has been so many complaints about the failure installing/updating python packages via system package manager, see #1017.
How to add/remove python package?
- Edit
requirements.in. You may refer to PyPI for possible package names.
- If PyPI does not have the needed package, we probably need to build it manually inside the venv. In such case we need to edit the install scripts.
- Run
uv pip compile requirements.in -o requirements.txtin this folder.
Notes:
- For reference see uv doc.
requirements.txtis included in Git. It's for locking package versions to enhance stability and reproducibility.[^1]
[^1]: In fact, including package version lock file in Git is also the most common way for similar situations, for example the package-lock.json of Node.js projects (see also this stackoverflow question). Although there are some situations when it's not suitable to include the lock file, for example the poetry document recommend application developers to include package version lock file in Git, but library developers should consider more, such as not including the lock file or including it but refreshing regularly.
How will the python packages get installed?
For summary:
- They will be installed to the virtual environment
$ILLOGICAL_IMPULSE_VIRTUAL_ENV. - The default value of
$ILLOGICAL_IMPULSE_VIRTUAL_ENVis$XDG_STATE_HOME/quickshell/.venv.- The default value of
$XDG_STATE_HOMEis$HOME/.local/state.
- The default value of
- Currently we use
env = ILLOGICAL_IMPULSE_VIRTUAL_ENV, ~/.local/state/quickshell/.venvin~/.config/hypr/hyprland/env.confto set this environment variable.[^2]
For details: see the function install-python-packages() defined in /sdata/lib/package-installers.sh.
[^2]: Hyprland seems to have weird problem dealing with recursive variable, so we can not use $XDG_STATE_HOME/quickshell/.venv even if we had set $XDG_STATE_HOME to ~/.local/state explicitly, else $XDG_STATE_HOME will possibly not get expanded but get recognised as literally $XDG_STATE_HOME. This problem never happens for some users, but according to some issues when we were using recursive variable setting in the past, it's possible to happen for other users. Reason unknown.
How to use the python packages installed through here?
Basically you'll need to activate the virtual environment first:
source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activateIt will add the python executable located in the venv to $PATH and give it the highest priority.
Run which python and you'll understand.
This python executable will also search and use the python package inside the venv,
which enables running any python script or running command provided via python package using the venv.
After that you probably need to deactivate it:
deactivateSituation 1: As a single command
Description: At someplace which accept a single command,
- run a python script,
- or run a command provided by python package.
Example: In ~/โ.config/quickshell/ii/screenshot.qml:
Process {
id: imageDetectionProcess
command: ["bash", "-c", `${Directories.scriptPath}/images/find_regions.py `
+ `--hyprctl `
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `In this example, python script find_regions.py is called and receives some arguments.
Solution A: shebang
Add the shebang below to the beginning of python script:
#!/usr/bin/env -S\_/bin/sh\_-c\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""And that's it!
Note: This is the simplest solution as it only modifies the shebang of python script.
However:
- It's only for python script, not the command provided by python package.
- It can not deal with complex argument (e.g. filename containing spaces) passed to the python script.
- If we apply this solution to the example above, it may cause problem, considering that
--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}'could be a rather complex argument passed tofind_regions.py.
- If we apply this solution to the example above, it may cause problem, considering that
- This solution rely on shebang to activate the correct python venv, but the shebang will be ignored if the script is directly passed to the interpreter, e.g.
python3 foo.py.
Solution B: bash script as wrapper
First make sure the python script is using the shebang #!/usr/bin/env python3, instead of #!/usr/bin/python3 or something else.
Then write a wrapper script in bash.
Let's continue the screenshot.qml example, in the same directory as find_regions.py, write a find-regions-venv.sh:
#!/usr/bin/env bash
# Specify the path of the python script.
# The example below only applies when `find_regions.py` and this wrapper script are under the same folder.
PY_SCRIPT="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)/find_regions.py"
source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
"$PY_SCRIPT" "$@"
deactivateNot done yet! Do not forget to update the code calling the original python script.
In this example, in ~/โ.config/quickshell/ii/screenshot.qml we should modify find_regions.py to the wrapper script find-regions-venv.sh:
Process {
id: imageDetectionProcess
command: ["bash", "-c", `${Directories.scriptPath}/images/find-regions-venv.sh `
+ `--hyprctl `
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `Situation 2: Inside a bash script
Note: the solutions for Situation 1: As a single command also apply here; but not vice versa.
Description:
Inside a bash script,
- run a python script,
- or run a command provided by python package.
Solution:
- Add "activation command" before the target line,
- Also add "deactivation command" after the target line.
Example:
For running a python script,
take generate_colors_material.py as example:
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"
python3 "$SCRIPT_DIR/generate_colors_material.py" "${generate_colors_material_args[@]}" \
> "$STATE_DIR"/user/generated/material_colors.scss
"$SCRIPT_DIR"/applycolor.shFor running a python script provided by python package,
take kde-material-you-colors as example:
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"
kde-material-you-colors "$mode_flag" --color "$color" -sv "$sv_num"
deactivateOverview (`dots/.config/quickshell/ii/defaults/ai/README.md`)
A note about sources of the prompts
ii-prefixed ones are from illogical impulse- The Acchan one is from Nyarch Assistant (GPLv3). I know there's already the Imouto one but this one's very ๐ญ๐ข
w-prefixed ones... I don't remember what w stands for but these prompts are [cough cough] inspired by certain apps
Overview (`dots/.config/quickshell/ii/modules/waffle/README.md`)
Waffle
A recreation of Windoes. It's WIP!
- If you install illogical-impulse fully, you can press Super+Alt+W to switch to this style.
- If you're just copying the Quickshell config, run the config as usual (
qs -c ii) then runqs -c ii ipc call panelFamily cycle
From EWW version to Quickshell
Just a reflection, in case anyone's interested. My blog is probably a better place for this, but it does not exist. Besides, this is going to change as I do more stuff. Currently there's just the bar.
Improvements
QtQuick's
Buttonhas the{top/bottom/left/right}Insetproperties, so we can have clickable regions expanding beyond the button background for free. With EWW it was annoying to wrap the button content with aneventboxthat has some padding, then somehow use CSS selectors to make sure hovering effects work. I have to admit, (a large) part of that annoyance was with how bad my copy-pasting coding practice was at the time, but still...Fancy effects: Gtk3 CSS does not support transformations. In QtQuick we can smack
rotationandscalealmost everywhere, so it's simple to make bouncy icons and rotating chevronsQuickshell provides a system tray service (EWW does now but didn't at the time I created the EWW Windoes version), so now there's no Waybar needed for the tray.
QtQuick has
Loaders, so we can have this live-switchable from the main style without killing the widget system, moving styles to the correct folder, and relaunching.This time my computer is powerful enough to run a VM, so I don't have to occasionally reboot to take quick screenshots for reference. I try to make everything pixel-perfect so this is necessary. Speaking about pixel-perfectness, in the EWW version I hardcoded sizes, but this time I'm still doing that (lol), BUT that's normal and not a problem because Qt has the
QT_SCALE_FACTORenv var for scaling. (Please feel free to prove me wrong in saying Gtk3 doesn't have that magic)
Challenges
Qt is not Gtk and definitely not React
- We don't get directional border on QtQuick
Rectangles like in CSS. I was able to get around this with manual drawing, but it was a bit more work
- We don't get directional border on QtQuick
Fluent Icons is difficult to use, compared to Material Symbols
- No React, so no clean use via a library.
- If we use the font, there's no proper, searchable codepoint cheatsheet like Nerd Fonts, and there's no ligatures
- I resorted to downloading individual SVGs. Not that nice, but it's better than scanning the whole table of icons every time I want one. For this we have fluenticon.com and fluenticons.co, but icons are awkwardly named and there's no alias. Why is the reload/refresh icon called "arrow-sync"? Well, the name is not misleading, but arguably reload/refresh are more common actions. From Fluent Design's page on Iconography:
Fluent system icons are literal metaphors and are named for the shape or object they represent, not the functionality they provide
"sync" is functionality.
Overview (`dots/.config/quickshell/ii/assets/icons/fluent/README.md`)
The "start-here", "search" and "task view" icons are from here, with modifications
Windows 11 by Joshua Oghenekaro Okwe - Figma
License: CC BY 4.0
--- METRICS ---
- Files Extracted: 12
- Estimated Token Budget: ~7758 tokens
- Canonical Reference: https://codewiki.google/github.com/end-4/dots-hyprland