11 Commits

Author SHA1 Message Date
9cfe00c197 fix: pass clang-tidy 2026-01-16 01:03:32 +01:00
5749263605 bodge: shut linter 2026-01-16 00:51:05 +01:00
e5c3c619c3 Merge branch 'master' into support-xorg 2026-01-16 00:44:58 +01:00
64a1368717 feat: xorg sessions work
leaves a few TODOs:
* error handling
* properly passing VT around
* `wait_for_x_ready`
* allow compile-time overriding `DEFAULT_XORG_DISPLAY` and `XORG_COMMAND`
2025-09-03 14:50:39 +02:00
570a68c586 fix: satify all clang code requirements 2025-08-27 22:21:21 +02:00
ff3e58ee5b fix: satify clang nullability requirements 2025-08-27 22:07:04 +02:00
109c9bd0be chore: organize code
add -Wextra by default
pipefd to communicate better with parent and forked process
rustify some stuff
add the desktop parser to the file read
2025-08-27 22:02:14 +02:00
056ec64bcb feat: better spawn error handling 2025-08-27 20:29:16 +02:00
b58bd50e64 perf: some compiler flag optimizations
https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld
2025-08-27 19:54:24 +02:00
6d9107b360 lint: stricter casing rules 2025-08-27 19:47:19 +02:00
b56aa19671 chore: modularize PAM
also helps with sanitizing the code flow when spawning the child, more
code though
2025-08-27 19:31:46 +02:00
86 changed files with 1596 additions and 989 deletions

2
.gitattributes vendored
View File

@@ -1,2 +0,0 @@
*.gif filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text

View File

@@ -65,6 +65,40 @@ jobs:
artifactErrorsFailBuild: true artifactErrorsFailBuild: true
body: Release notes not generated yet. body: Release notes not generated yet.
aur-update:
name: Update AUR pkgs
runs-on: ubuntu-24.04
container: archlinux:latest
permissions: write-all
needs: [ release-checks, release ]
steps:
- run: pacman -Sy --noconfirm git github-cli base-devel pacman-contrib
- uses: actions/checkout@v4
- run: |
chage -E -1 nobody
passwd -u nobody
cd "assets/pkg/aur"
chown nobody:nobody . -R
su - -s /bin/bash nobody -c "$PWD/update-pkgs.sh ${{ needs.release-checks.outputs.VERSION }}"
su - -s /bin/bash nobody -c "$PWD/test-makepkg.sh" # This will also update -git pkgver
chown $UID:$(id -g) . -R
- run: |
BRANCH=actions/update-aur-${{ needs.release-checks.outputs.VERSION }}
git config --global --add safe.directory $GITHUB_WORKSPACE
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout -b $BRANCH
git commit -am "Update AUR pkgs to v${{ needs.release-checks.outputs.VERSION }}"
git push -u origin $BRANCH
gh pr create --head $BRANCH \
--title "[AUR update]: Bump to ${{ needs.release-checks.outputs.VERSION }}" \
--body "*This PR was created automatically*"
env:
GH_TOKEN: ${{ github.token }}
nix-update: nix-update:
name: Update NixOS module name: Update NixOS module
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04

2
.gitignore vendored
View File

@@ -8,3 +8,5 @@ valgrind-out.txt
# nix build result # nix build result
result result
include/version.h

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "themes"]
path = themes
url = https://github.com/javalsai/lidm-themes

View File

@@ -1,19 +0,0 @@
<!-- Unspecified dates shall be in CET/CEST -->
<!-- Add only very relevant changes, bottom to top -->
<!-- By "very relevant" I mean big features or something manual packagers should know, like leftover files -->
<!-- Once a release would be opened, group the last bunch of dangling changes, add release version as header and its date -->
# 2.0.1
- source and header files can be nested in `src/` and `include/`
- lidm now calls bash for logging in and sourcing profile files, other shells can be configured
- a good PATH default is fetched from `confstr`
- debug logs are now unbuffered
# 2.0.0
- Most stuff (most of `/etc` being a notable exception) now installs to `/usr/local` by default, check [`docs/PACKAGERS.md`](./docs/PACKAGERS.md).
- Added a changelog.
- Finally add proper (experimental) xorg support.
- Systemd service install path changed to `/usr/local/lib/systemd`, there could be a leftover file at `/etc/systemd/system/lidm.service`.

146
Makefile
View File

@@ -1,45 +1,53 @@
VERSION := 2.0.1 VERSION = 1.2.3
.DEFAULT_GOAL := lidm .DEFAULT_GOAL := lidm
CDIR = src CDIR=src
LDIR = lib LDIR=lib
IDIR = include IDIR=include
ODIR = dist ODIR=dist
PREFIX = /usr/local PREFIX=/usr
INFO_GIT_REV ?= $(shell git describe --long --tags --always || echo '?') CC?=gcc
INFO_GIT_REV := $(INFO_GIT_REV) CFLAGS?=-O3 -Wall -Wextra -fdata-sections -ffunction-sections
INFO_BUILD_TS ?= $(shell date +%s)
INFO_BUILD_TS := $(INFO_BUILD_TS)
CFLAGS ?= -O3 -Wall -Wextra -fdata-sections -ffunction-sections
# C PreProcessor flags, not C Plus Plus # C PreProcessor flags, not C Plus Plus
CPPFLAGS ?= CPPFLAGS?=
_DFLAGS?= \ ALLFLAGS=$(CFLAGS) $(CPPFLAGS) -I$(IDIR)
-DLIDM_VERSION=\"$(VERSION)\" \ LDFLAGS?=-Wl,--gc-sections
-DLIDM_GIT_REV=\"$(INFO_GIT_REV)\" \
-DLIDM_BUILD_TS=$(INFO_BUILD_TS)
ALLFLAGS = $(_DFLAGS) $(CFLAGS) $(CPPFLAGS) -I$(IDIR)
LDFLAGS ?= -Wl,--gc-sections
LIBS = -lpam LIBS=-lpam
# includes all headers in `$(IDIR)` and compiles everything in `$(CDIR)` _DEPS = version.h log.h util.h ui.h ui_state.h config.h pam.h desktop.h desktop_exec.h auth.h ofield.h efield.h keys.h users.h sessions.h chvt.h macros.h launch_state.h
DEPS = $(wildcard $(IDIR)/*.h $(IDIR)/**/*.h) DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_SOURCES = $(wildcard $(CDIR)/*.c) $(wildcard $(CDIR)/**/*.c)
OBJ = $(patsubst $(CDIR)/%.c,$(ODIR)/%.o,$(_SOURCES)) _OBJ = main.o log.o util.o ui.o ui_state.o config.o pam.o desktop.o desktop_exec.o auth.o ofield.o efield.o users.o sessions.o chvt.o launch_state.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
INFO_GIT_REV?=$$(git describe --long --tags --always || echo '?')
INFO_BUILD_TS?=$$(date +%s)
$(IDIR)/version.h: Makefile
@tmp=$$(mktemp); \
printf '' > $$tmp; \
echo '#define LIDM_VERSION "'$(VERSION)'"' >> $$tmp; \
echo '#define LIDM_GIT_REV "'$(INFO_GIT_REV)'"' >> $$tmp; \
echo '#define LIDM_BUILD_TS '$(INFO_BUILD_TS) >> $$tmp; \
if ! cmp -s $$tmp $@; then \
mv $$tmp $@; \
fi; \
rm -f $$tmp;
$(ODIR)/%.o: $(CDIR)/%.c $(DEPS) $(ODIR)/%.o: $(CDIR)/%.c $(DEPS)
@mkdir -p $(dir $@) @mkdir -p $(ODIR)
$(CC) -c -o $@ $< $(ALLFLAGS) $(CC) -c -o $@ $< $(ALLFLAGS)
lidm: $(OBJ) lidm: $(OBJ)
$(CC) -o $@ $^ $(ALLFLAGS) $(LIBS) $(LDFLAGS) $(CC) -o $@ $^ $(ALLFLAGS) $(LIBS) $(LDFLAGS)
clean: clean:
rm -rf $(ODIR) lidm rm -f $(ODIR)/*.o lidm
# Copy lidm to ${DESTDIR}${PREFIX}/bin (/usr/bin)
install: lidm install: lidm
mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/man/man{1,5} mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/man/man{1,5}
install -Dm755 ./lidm ${DESTDIR}${PREFIX}/bin/ install -Dm755 ./lidm ${DESTDIR}${PREFIX}/bin/
@@ -47,11 +55,83 @@ install: lidm
install -Dm644 ./assets/man/lidm.1 ${DESTDIR}${PREFIX}/share/man/man1/ install -Dm644 ./assets/man/lidm.1 ${DESTDIR}${PREFIX}/share/man/man1/
install -Dm644 ./assets/man/lidm-config.5 ${DESTDIR}${PREFIX}/share/man/man5/ install -Dm644 ./assets/man/lidm-config.5 ${DESTDIR}${PREFIX}/share/man/man5/
uninstall: uninstall-service uninstall:
rm -rf ${DESTDIR}${PREFIX}/bin/lidm ${DESTDIR}/etc/lidm.ini rm -rf ${DESTDIR}${PREFIX}/bin/lidm ${DESTDIR}/etc/lidm.ini
rm -rf ${DESTDIR}${PREFIX}/share/man/man{1/lidm.1,5/lidm-config.5}.gz rm -rf ${DESTDIR}/usr/share/man/man{1/lidm.1,5/lidm-config.5}.gz
rm -rf ${DESTDIR}/usr/local/lib/systemd/system/lidm.service ${DESTDIR}/etc/dinit.d/lidm ${DESTDIR}/etc/runit/sv/lidm
include services.mk install-service:
@if command -v systemctl &> /dev/null; then \
make install-service-systemd; \
elif command -v dinitctl &> /dev/null; then \
make install-service-dinit; \
elif command -v sv &> /dev/null; then \
if [ -d /etc/sv ]; then \
make install-service-runit; \
elif [ -d /etc/runit/sv ]; then \
make install-service-runit-etc; \
else \
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
fi \
elif command -v rc-update &> /dev/null; then \
make install-service-openrc; \
elif command -v s6-service &> /dev/null; then \
if [ -d /etc/sv ]; then \
make install-service-s6; \
elif [ -d /etc/r6nit/sv ]; then \
make install-service-s6-etc; \
else \
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
fi \
else \
printf '\033[1;31m%s\033[0m\n' "Unknown init system, skipping service install..." >&2; \
fi
install-service-systemd:
install -m644 ./assets/services/systemd.service ${DESTDIR}/usr/local/lib/systemd/system/lidm.service
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'systemctl enable lidm'"
install-service-dinit:
install -m644 ./assets/services/dinit ${DESTDIR}/etc/dinit.d/lidm
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'dinitctl enable lidm'"
install-service-runit:
@if [ ! -e /etc/sv ] && [ -d /etc/runit/sv ] && [ -z "$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/runit/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit-etc'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/sv/lidm
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/sv/lidm /var/service' or your distro equivalent"
install-service-runit-etc:
@if [ ! -e /etc/runit/sv ] && [ -d /etc/sv ] && [ -z "$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/runit/sv doesn't exist but /etc/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/runit/sv/lidm
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/runit/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/runit/sv/lidm /run/runit/service' or your distro equivalent"
install-service-openrc:
install -m755 ./assets/services/openrc ${DESTDIR}/etc/init.d/lidm
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'rc-update add lidm'"
install-service-s6:
@if [ ! -e /etc/sv ] && [ -d /etc/s6/sv ] && [ -z "$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/s6/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6-etc'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/sv/lidm
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
install-service-s6-etc:
@if [ ! -e /etc/s6/sv ] && [ -d /etc/sv ] && [ -z "$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/s6/sv doesn't exist but /etc/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/s6/sv/lidm
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/s6/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
pre-commit: pre-commit:
codespell codespell
@@ -67,5 +147,13 @@ print-version:
.PHONY: clean \ .PHONY: clean \
install uninstall \ install uninstall \
install-service \
install-service-s6 \
install-service-s6-etc \
install-service-dinit \
install-service-runit \
install-service-runit-etc \
install-service-openrc \
install-service-systemd \
pre-commit \ pre-commit \
print-version print-version

View File

@@ -15,16 +15,12 @@ LiDM is like any [Display Manager](https://en.wikipedia.org/wiki/X_display_manag
shown as in a featured terminal emulator, actual linux console doesn't support as much color and decorations shown as in a featured terminal emulator, actual linux console doesn't support as much color and decorations
</i></summary> </i></summary>
If you want to add fancy color and font support to your TTYs you can try wrapping lidm in [`kmscon`](https://wiki.archlinux.org/title/KMSCON). (edit appropriate service files). e.g: If you want to add fancy color and font support to your TTYs you can wrap lidm in [`kmscon`](https://wiki.archlinux.org/title/KMSCON). (edit appropriate service files). e.g:
```sh ```sh
kmscon -l --vt /dev/tty7 --font-name "Cascadia Code" -- /usr/bin/lidm kmscon -l --vt /dev/tty7 --font-name "Cascadia Code" -- /usr/bin/lidm
``` ```
Kmscon is NOT officially supported so you are on your own when trying this, [according to the arch wiki](https://wiki.archlinux.org/title/KMSCON#Window_managers_cannot_be_started_from_KMS_console) it's not possible to start window managers if you do this.
But [according to farouk](https://github.com/javalsai/lidm/issues/91#issuecomment-3708503568) you can make it work if you tell kmscon to work in `no-drm` mode. There's still input grabbing issues which cause <kbd><kbd>Ctrl</kbd> + <kbd>C</kbd></kbd> to kill lidm, they are likely fixable though.
</details></blockquote> </details></blockquote>
> _however, all colors and strings are fully customizable_ > _however, all colors and strings are fully customizable_
@@ -33,7 +29,7 @@ But [according to farouk](https://github.com/javalsai/lidm/issues/91#issuecommen
- Simple as C, meant to depend only on standard libc and basic unix system headers. - Simple as C, meant to depend only on standard libc and basic unix system headers.
- Fully customizable: ALL strings, colors (with its ANSI keys) and most behavior. - Fully customizable: ALL strings, colors (with its ANSI keys) and most behavior.
- Experimental Xorg support[\*](https://github.com/javalsai/lidm/pull/80?#issuecomment-3764073217) and wayland sessions, while supporting the default user shell (if enabled in config) - Xorg[\*](https://github.com/javalsai/lidm/issues/79) and wayland sessions, while supporting the default user shell (if enabled in config)
- Init agnostinc (systemd, dinit, runit, openrc and s6). - Init agnostinc (systemd, dinit, runit, openrc and s6).
- Supports [fido yubikeys](./docs/yubikey.md) (via pam_u2f). - Supports [fido yubikeys](./docs/yubikey.md) (via pam_u2f).
@@ -48,7 +44,6 @@ But [according to farouk](https://github.com/javalsai/lidm/issues/91#issuecommen
- [Configuring](#configuring) - [Configuring](#configuring)
- [PAM](#pam) - [PAM](#pam)
- [Contributing](#contributing) - [Contributing](#contributing)
- [License](#license)
- [Inspiration](#inspiration) - [Inspiration](#inspiration)
- [Contributors](#contributors) - [Contributors](#contributors)
@@ -122,10 +117,6 @@ When the env variable is empty it defaults to the `login` PAM service or whateve
If you want to contribute check the [contribution guide](docs/CONTRIBUTING.md). If you want to contribute check the [contribution guide](docs/CONTRIBUTING.md).
# License
This project is licensed under the GNU General Public License v3.0 **only**.
# Inspiration # Inspiration
This project was started after facing some issues building [ly](https://github.com/fairyglade/ly) on an ancient laptop, the UI is heavily inspired by it. This project was started after facing some issues building [ly](https://github.com/fairyglade/ly) on an ancient laptop, the UI is heavily inspired by it.

View File

@@ -104,9 +104,6 @@ Specify the time format string to be displayed. Check \fBstrftime (3)\fP to know
.TP .TP
\fBrefresh_rate\fP \fBrefresh_rate\fP
Rate (in milliseconds) at which the UI should refresh, affects clock and resize behavior. Rate (in milliseconds) at which the UI should refresh, affects clock and resize behavior.
.TP
\fBbypass_shell_login\fP
Type \fBBOOL\fP, lidm logins through a login shell (e.g. `bash`) in login mode (e.g. `arg0` being `-bash`) to load `/etc/profile/, `/etc/profile.d/` and more. If this option is enabled that's bypassed entirely.
.SH "SEE ALSO" .SH "SEE ALSO"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 205 KiB

4
assets/pkg/aur/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*/*
!*/.gitignore
!*/PKGBUILD
!*/.SRCINFO

12
assets/pkg/aur/README.md Normal file
View File

@@ -0,0 +1,12 @@
# AUR Packages
These files are just for reference, I'll manually edit and publish them, at least until I automate it with github actions (like updating version automatically on a release).
There are three packages that follow standard conventions:
- [`lidm`](https://aur.archlinux.org/packages/lidm): Builds latest release (manually updated per release basis)
- [`lidm-bin`](https://aur.archlinux.org/packages/lidm-bin): Fetches latest release binary (compiled by GitHub Actions, also updated per release)
- [`lidm-git`](https://aur.archlinux.org/packages/lidm-git): Fetches latest commit and builds it (should be updated automatically)
> \[!IMPORTANT]
> None of those packages include the service files. [You have to do this yourself](../../services/README.md).

View File

@@ -0,0 +1,32 @@
pkgbase = lidm-bin
pkgdesc = A fully colorful customizable TUI display manager made in C. (release binary)
pkgver = 1.2.3
pkgrel = 3
url = https://github.com/javalsai/lidm
arch = x86_64
arch = i686
arch = aarch64
arch = armv7h
arch = riscv64
license = GPL
depends = libpam.so
provides = lidm
conflicts = lidm
source = lidm-default-theme-1.2.3.ini::https://raw.githubusercontent.com/javalsai/lidm/v1.2.3/themes/default.ini
source = lidm-1.2.3.1::https://raw.githubusercontent.com/javalsai/lidm/v1.2.3/assets/man/lidm.1
source = lidm-config-1.2.3.5::https://raw.githubusercontent.com/javalsai/lidm/v1.2.3/assets/man/lidm-config.5
sha256sums = ffaa5fe2cf5011bf53c90f81bfec8585158d35f72c0666db0bd4d3866ae041ca
sha256sums = 7f2fb91f55088be1a9b1c93ecf5d6c1e437f369b56df2eacc9d10b00c93c39f8
sha256sums = 0aa5755bdcc60ea80cd9ee0f89233ffaf22c6cee9db9da277274a62c6ed477d9
source_x86_64 = lidm-1.2.3-x86_64::https://github.com/javalsai/lidm/releases/download/v1.2.3/lidm-amd64
sha256sums_x86_64 = a533b5aee3ffe04268f8d3ff8d7eb87f09d31fbe25e1b8b1ed29c42ef465bd4b
source_i686 = lidm-1.2.3-i686::https://github.com/javalsai/lidm/releases/download/v1.2.3/lidm-i386
sha256sums_i686 = 75018578e68bffda9807de8a65e16eaed8a16c6cf2417a0b58c5d5bcfa603e45
source_aarch64 = lidm-1.2.3-aarch64::https://github.com/javalsai/lidm/releases/download/v1.2.3/lidm-aarch64
sha256sums_aarch64 = 1b81a1537a1e31ca1902cbc3b60add4ac712aa64fd4d266685f53372cc365882
source_armv7h = lidm-1.2.3-armv7h::https://github.com/javalsai/lidm/releases/download/v1.2.3/lidm-armv7
sha256sums_armv7h = e86f59509fe2366d6312b9bc9e8d89c14e9c049fd713a04c41dab49a848b1ada
source_riscv64 = lidm-1.2.3-riscv64::https://github.com/javalsai/lidm/releases/download/v1.2.3/lidm-riscv64
sha256sums_riscv64 = 3f0eb0315c523d367bac332641e5cd3c86cfd9aa4e7c14b2efc036937b97a598
pkgname = lidm-bin

3
assets/pkg/aur/lidm-bin/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
!PKGBUILD
!.SRCINFO

View File

@@ -0,0 +1,39 @@
# shellcheck disable=SC2034,SC2154,SC2164
# Maintainer: javalsai <javalsai@proton.me>
pkgname=lidm-bin
pkgver=1.2.3
pkgrel=3
depends=('libpam.so')
pkgdesc="A fully colorful customizable TUI display manager made in C. (release binary)"
arch=('x86_64' 'i686' 'aarch64' 'armv7h' 'riscv64')
url="https://github.com/javalsai/lidm"
license=('GPL')
provides=('lidm')
conflicts=('lidm')
source=(
"lidm-default-theme-${pkgver}.ini::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/themes/default.ini"
"lidm-${pkgver}.1::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/assets/man/lidm.1"
"lidm-config-${pkgver}.5::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/assets/man/lidm-config.5"
)
source_x86_64=("lidm-${pkgver}-x86_64::$url/releases/download/v$pkgver/lidm-amd64")
source_i686=("lidm-${pkgver}-i686::$url/releases/download/v$pkgver/lidm-i386")
source_aarch64=("lidm-${pkgver}-aarch64::$url/releases/download/v$pkgver/lidm-aarch64")
source_armv7h=("lidm-${pkgver}-armv7h::$url/releases/download/v$pkgver/lidm-armv7")
source_riscv64=("lidm-${pkgver}-riscv64::$url/releases/download/v$pkgver/lidm-riscv64")
sha256sums=('ffaa5fe2cf5011bf53c90f81bfec8585158d35f72c0666db0bd4d3866ae041ca'
'7f2fb91f55088be1a9b1c93ecf5d6c1e437f369b56df2eacc9d10b00c93c39f8'
'0aa5755bdcc60ea80cd9ee0f89233ffaf22c6cee9db9da277274a62c6ed477d9')
sha256sums_x86_64=('a533b5aee3ffe04268f8d3ff8d7eb87f09d31fbe25e1b8b1ed29c42ef465bd4b')
sha256sums_i686=('75018578e68bffda9807de8a65e16eaed8a16c6cf2417a0b58c5d5bcfa603e45')
sha256sums_aarch64=('1b81a1537a1e31ca1902cbc3b60add4ac712aa64fd4d266685f53372cc365882')
sha256sums_armv7h=('e86f59509fe2366d6312b9bc9e8d89c14e9c049fd713a04c41dab49a848b1ada')
sha256sums_riscv64=('3f0eb0315c523d367bac332641e5cd3c86cfd9aa4e7c14b2efc036937b97a598')
package() {
cd "$srcdir"
install -Dm755 "lidm-${pkgver}-$CARCH" "${pkgdir}/usr/bin/lidm"
install -Dm644 "lidm-default-theme-${pkgver}.ini" "${pkgdir}/etc/lidm.ini"
install -Dm644 "lidm-${pkgver}.1" "${pkgdir}/usr/share/man/man1/lidm.1"
install -Dm644 "lidm-config-${pkgver}.5" "${pkgdir}/usr/share/man/man5/lidm-config.5"
}

View File

@@ -0,0 +1,15 @@
pkgbase = lidm-git
pkgdesc = A fully colorful customizable TUI display manager made in C. (last git commit)
pkgver = 1.2.3.r3.g363deea
pkgrel = 3
url = https://github.com/javalsai/lidm
arch = any
license = GPL
makedepends = git
depends = pam
provides = lidm
conflicts = lidm
source = lidm::git+https://github.com/javalsai/lidm
sha256sums = SKIP
pkgname = lidm-git

3
assets/pkg/aur/lidm-git/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
!PKGBUILD
!.SRCINFO

View File

@@ -0,0 +1,31 @@
# shellcheck disable=SC2034,SC2154,SC2164
# Maintainer: javalsai <javalsai@proton.me>
pkgname=lidm-git
pkgver=1.2.3.r3.g363deea
pkgrel=3
depends=('pam')
makedepends=('git')
pkgdesc="A fully colorful customizable TUI display manager made in C. (last git commit)"
arch=('any')
url="https://github.com/javalsai/lidm"
license=('GPL')
provides=('lidm')
conflicts=('lidm')
source=("lidm::git+https://github.com/javalsai/lidm")
sha256sums=('SKIP')
pkgver() {
cd "$srcdir/lidm"
git describe --long --abbrev=7 --tags | \
sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
build() {
cd "$srcdir/lidm"
make
}
package() {
cd "$srcdir/lidm"
make DESTDIR="${pkgdir}" install
}

View File

@@ -0,0 +1,12 @@
pkgbase = lidm
pkgdesc = A fully colorful customizable TUI display manager made in C. (build latest tag)
pkgver = 1.2.3
pkgrel = 3
url = https://github.com/javalsai/lidm
arch = any
license = GPL
depends = pam
source = lidm-1.2.3.tar.gz::https://github.com/javalsai/lidm/archive/refs/tags/v1.2.3.tar.gz
sha256sums = 1ce414b510c5bbc3e32ea882f915b4d3958cb82eb1fbb5cf33e62f69c844bf93
pkgname = lidm

3
assets/pkg/aur/lidm/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
!PKGBUILD
!.SRCINFO

View File

@@ -0,0 +1,21 @@
# shellcheck disable=SC2034,SC2154,SC2164
# Maintainer: javalsai <javalsai@proton.me>
pkgname=lidm
pkgver=1.2.3
pkgrel=3
depends=('pam')
makedepends=()
pkgdesc="A fully colorful customizable TUI display manager made in C. (build latest tag)"
arch=('any')
url="https://github.com/javalsai/lidm"
license=('GPL')
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/javalsai/lidm/archive/refs/tags/v$pkgver.tar.gz")
sha256sums=('1ce414b510c5bbc3e32ea882f915b4d3958cb82eb1fbb5cf33e62f69c844bf93')
build() {
make -C "$srcdir/lidm-$pkgver"
}
package() {
make -C "$srcdir/lidm-$pkgver" DESTDIR="$pkgdir" install
}

12
assets/pkg/aur/make-srcinfo.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
for pkg in "$MYDIR"/*/; do
cd "$pkg"
printf "\x1b[1mEntering '%s'\x1b[0m\n" "$pkg"
makepkg --printsrcinfo | tee .SRCINFO
echo
done

22
assets/pkg/aur/makepkg-clean.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
cd "$MYDIR"
typeset -a pkgs=(lidm{,-git,-bin})
for pkg in "${pkgs[@]}"; do
printf "\x1b[mEntering '%s'\x1b[0m\n" "$pkg"
cd "$pkg"
# shellcheck disable=SC1091
source PKGBUILD
# shellcheck disable=SC2154
for f in "${source[@]}"; do
echo "$f"
awk -F:: '{print $1}' <<<"$f" | xargs rm -rf
done
cd ..
echo
done

22
assets/pkg/aur/test-makepkg.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
cd "$MYDIR"
typeset -a pkgs=(lidm{,-git,-bin})
for pkg in "${pkgs[@]}"; do
printf "\x1b[mEntering '%s'\x1b[0m\n" "$pkg"
cd "$pkg"
makepkg -Cf
cd ..
echo
done
if [[ -n "${PRINT_TREE:-}" ]]; then
for pkg in "${pkgs[@]}"; do
eza --tree "$pkg/pkg/"*
done
fi

23
assets/pkg/aur/update-pkgs.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
if [ -z "$1" ]; then
printf "\x1b[1;31mERR: No version to update provided\x1b[0m\n" >&2
exit 1;
fi
version="$1"
printf "\x1b[34mINF: Using '%s' version\x1b[0m\n" "$version"
for pkg in "$MYDIR"/lidm{,-bin}/; do
cd "$pkg"
printf "\x1b[1mEntering '%s'\x1b[0m\n" "$pkg"
sed -i "s/pkgver=.*/pkgver=$1/" PKGBUILD
sed -i "s/pkgrel=.*/pkgrel=1/" PKGBUILD
updpkgsums
makepkg --printsrcinfo | tee .SRCINFO
echo
done

View File

@@ -11,7 +11,7 @@ let
dmcfg = config.services.displayManager; dmcfg = config.services.displayManager;
desktops = dmcfg.sessionData.desktops; desktops = dmcfg.sessionData.desktops;
version = "2.0.0"; version = "1.2.3";
lidmPkg = pkgs.callPackage ./lidm.nix { lidmPkg = pkgs.callPackage ./lidm.nix {
inherit pkgs; inherit pkgs;
config = { config = {
@@ -21,7 +21,7 @@ let
owner = "javalsai"; owner = "javalsai";
repo = "lidm"; repo = "lidm";
rev = "v${version}"; rev = "v${version}";
sha256 = "sha256-dI1OGndbT6wFAhuGmsPZPqLFvtPREfO/3HqhmlSMpN4="; sha256 = "sha256-eKgBoh+bRcl2Y7oOxW77Kjtb9Ws2Xln1SenknIsGxD4=";
}; };
xsessions = "${desktops}/share/xsessions"; xsessions = "${desktops}/share/xsessions";

View File

@@ -2,17 +2,18 @@
This folder contains the files necessary to set up lidm on start up for the supported init systems, all of them are configured for tty7. This folder contains the files necessary to set up lidm on start up for the supported init systems, all of them are configured for tty7.
If you're using lidm from a packaged source, this should be included with the package. Only read this for manual installations, if you are packaging or if your package exceptionally doesn't include them.
If you don't know what a init system is, you're certainly using `systemd`. If you don't know what a init system is, you're certainly using `systemd`.
There's make scripts to automatically copy the service files to the proper locations, you just have to run `make install-service-$INIT` (or `make install-service-$INIT-etc`). `make install-service` will attempt to detect the init system in use and install for it. There's make scripts to automatically copy the service files to the proper locations, you just have to run `make install-service-$INIT` (or `make install-service-$INIT-etc`). `make install-service` will attempt to detect the init system in use and install for it.
The manual steps for installation are: The manual steps for installation are:
> [!IMPORTANT]
> If you think this should be packaged too, there's [a discussion](https://github.com/javalsai/lidm/discussions/39) to talk about this.
## Systemd ## Systemd
- Copy `systemd.service` to `/usr/local/lib/systemd/system/lidm.service` (if the directory doesn't exist, create it first) or `/usr/lib/systemd/system/lidm.service` (if you wish to install along your system files). - Copy `systemd.service` to `/usr/local/lib/systemd/system/lidm.service` (if the directory doesn't exist, create it first)
- To enable it you can run `systemctl enable lidm` - To enable it you can run `systemctl enable lidm`
## Dinit ## Dinit
@@ -22,10 +23,8 @@ The manual steps for installation are:
## Runit ## Runit
Your runit service path can be either `/etc/runit/sv` or `/etc/sv`. - Copy `runit/` to `/etc/runit/sv/lidm/`
- Add the service with `ln -s /etc/runit/sv/lidm /run/runit/service`
- Copy `runit/` to `runit-path/lidm/`
- Add the service with `ln -s runit-path/lidm /run/runit/service`
- And to enable it `sv enable lidm` - And to enable it `sv enable lidm`
## OpenRC ## OpenRC
@@ -35,9 +34,7 @@ Your runit service path can be either `/etc/runit/sv` or `/etc/sv`.
## S6 ## S6
Your S6 service path can be either `/etc/s6/sv` or `/etc/sv`. - Copy `s6/` to `/etc/s6/sv/lidm/`
- Copy `s6/` to `s6-path/lidm/`
- Add the service with `s6-service add default lidm` - Add the service with `s6-service add default lidm`
- Reload the database with `s6-db-reload` (you might have to run this every time the service file changes) - Reload the database with `s6-db-reload` (you might have to run this every time the service file changes)

View File

@@ -11,7 +11,6 @@ StandardError=tty
TTYPath=/dev/tty7 TTYPath=/dev/tty7
TTYReset=yes TTYReset=yes
TTYVHangup=yes TTYVHangup=yes
Restart=always
[Install] [Install]
Alias=display-manager.service Alias=display-manager.service

View File

@@ -1,9 +0,0 @@
type = process
command = /bin/sh -c "LIDM_LOG=/tmp/lidm.debug /sbin/agetty tty8 linux-c -n -l /usr/local/bin/lidm -o 8"
restart = true
depends-on = login.target
termsignal = HUP
smooth-recovery = true
inittab-id = 8
inittab-line = tty8
log-type = buffer

View File

@@ -1,72 +1,63 @@
# Table of Contents # Table of Contents
- [Packages](#packages)
- [Void Linux](#void-linux)
- [Fedora](#fedora)
- [AUR](#aur)
- [Nix Flake](#nix-flake)
- [Nix Module](#nix-module)
- [Installing from Source](#installing-from-source) - [Installing from Source](#installing-from-source)
- [AUR](#aur)
- [Nix Flake](#nix-flake)
- [Nix Module](#nix-module)
# Packages > [!CAUTION]
> I encourage you to read the manual installation steps to understand what will get installed in your computer by this package.
Lidm relies on its community to package lidm for distributions and make the installation easier for everyone. Please raise any issues on the packages themselves and not the source repository. # Installing from Source
If you packaged lidm for any distribution not listed here or keep your own version of an inactive package, feel free to contact me to be added here. (could be a GitHub discussion or an email if you don't use GitHub) Firstly, you'll need to build the package, this also includes man pages, default config, themes and other files you might need.
These packages just install lidm, once installed you have to enable it. It depends on your init system, but if you're using systemd (most likely), first find your currently active display manager (if any, examples are `sddm`, `gdm`, `ly`) and disable it: To build it you only need to have some basic packages (should come pre-installed in almost all distros): `make`, `gcc` or another `gcc`ish compiler, and libpam headers. If it builds, it surely works anyways.
```sh ```sh
systemctl disable <display manager name here> git clone https://github.com/javalsai/lidm.git
cd lidm
make # 👍
``` ```
And then enable lidm: > [!NOTE]
> There's pre-built binaries on the [releases tab](https://github.com/javalsai/lidm/releases) too.
Then you can install the files onto your filesystem with:
```sh ```sh
systemctl enable lidm make install
``` ```
Lidm now should show on the next boot! And additionally, to install service files (start-up behavior). <sup>[more docs](../assets/services/README.md)</sup>
If you are on a TTY and don't wish to reboot, you should be able to use `--now` with both commands. It's likely to kill your current desktop environment if it was launched from it.
## Void Linux
Lidm can be installed from the official Void Linux packages:
```sh ```sh
xbps-install lidm # automatically detects your init system
# and install service file (for tty7)
make install-service
# or if you don't like autodetection
make install-service-systemd # systemd
make install-service-dinit # dinit
make install-service-runit # runit (/etc/sv)
make install-service-runit-etc # runit (/etc/runit/sv)
make install-service-openrc # openrc
make install-service-s6 # s6 (/etc/sv)
make install-service-s6-etc # s6 (/etc/s6/sv)
# For runit and s6, some distros (e.g. Artix) like to put it in /etc/<init>/sv
# to better isolate their packages while other distros (e.g. Void) just put it
# in /etc/sv
``` ```
To enable the service that starts on boot: # AUR
```sh [AUR packages](https://aur.archlinux.org/packages?K=lidm&SeB=n) will automatically install most files.
ln -s /etc/sv/lidm /var/service/
```
It is recommended to disable any other display managers that are still enabled: > [!CAUTION]
> [service files](../assets/pkg/aur#services) have to be manually installed by now.
```sh # Nix Flake
touch /etc/sv/lightdm/down # replace lightdm with your previous display manager (e.g., sddm, gdm)
```
## Fedora
Thanks to @KernelFreeze there's a COPR repo available at <https://copr.fedorainfracloud.org/coprs/celestelove/lidm/> to install lidm. (<https://github.com/javalsai/lidm/discussions/92>)
## AUR
There are several [AUR packages](https://aur.archlinux.org/packages?K=lidm&SeB=n) for most things. You only need to install one of the following:
- `lidm`
- `lidm-bin`
- `lidm-git`
Each of those depend on `lidm-service` which is provided by `lidm-systemd` and `lidm-dinit` (you'll have to pick one). I maintain both but I'm open to anyone that actually uses systemd to take the first one.
There's packagers needed for openrc, s6 and runit. If you know how to make AUR packages, feel free to take any of those if you use each init system.
## Nix Flake
You can install by doing You can install by doing
@@ -80,7 +71,10 @@ or try it out without installing by:
nix run github:javalsai/lidm nix run github:javalsai/lidm
``` ```
## Nix Module > [!CAUTION]
> This doesn't include [service files](../assets/pkg/aur#services) neither
# Nix Module
<details> <details>
<summary>Sidenote</summary> <summary>Sidenote</summary>
@@ -130,46 +124,5 @@ with config.lidm.keysEnum; {
> _it's not necessary to cover all keys and anything can be put there, even if it's not valid config_ > _it's not necessary to cover all keys and anything can be put there, even if it's not valid config_
# Installing from Source
Firstly, you'll need to build the package, this also includes man pages, default config, themes and other files you might need.
To build it you only need to have some basic packages (should come pre-installed in almost all distros): `make`, `gcc` or another `gcc`ish compiler, and libpam headers. If it builds, it surely works anyways.
```sh
git clone https://github.com/javalsai/lidm.git
cd lidm
make # 👍
```
> [!NOTE] > [!NOTE]
> There are pre-built binaries on the [releases tab](https://github.com/javalsai/lidm/releases) too. > [service files](../assets/pkg/aur#services) **are** included and enabled
Then you can install the files onto your filesystem with:
```sh
make install
```
This will install mostly into `/usr/local` by default, this path is mostly unused nowadays (systemd can load services from it but man usually doesn't find manual pages in there) and could feel like lidm didn't install at all. You can add `PREFIX=/usr` to install along the rest of your system packages if you wish.
And additionally, to install service files (start-up behavior). <sup>[more docs](../assets/services/README.md)</sup>
```sh
# automatically detects your init system
# and install service file (for tty7)
make install-service
# or if you don't like autodetection
make install-service-systemd # systemd
make install-service-dinit # dinit
make install-service-runit # runit (/etc/sv)
make install-service-runit-etc # runit (/etc/runit/sv)
make install-service-openrc # openrc
make install-service-s6 # s6 (/etc/sv)
make install-service-s6-etc # s6 (/etc/s6/sv)
# For runit and s6, some distros (e.g. Artix) like to put it in /etc/<init>/sv
# to better isolate their packages while other distros (e.g. Void) just put it
# in /etc/sv
```

View File

@@ -22,14 +22,11 @@ make \
The list of possible `#define`s is: The list of possible `#define`s is:
| Name | Default | Description | Env Override? | | Name | Default | Description | Env Override? |
| -------------------------- | ------------------------------------- | -------------------------------------------------------------------------- | ------------------------ | | ---------------------- | ------------------------------- | -------------------------------------------------------------------------- | ------------------------ |
| `PAM_SERVICE_FALLBACK` | `"login"` | Name of the default PAM module to use. Defaults to the distro's `"login"`. | Yes (`LIDM_PAM_SERVICE`) | | `PAM_SERVICE_FALLBACK` | `"login"` | Name of the default PAM module to use. Defaults to the distro's `"login"`. | Yes (`LIDM_PAM_SERVICE`) |
| `SESSIONS_XSESSIONS` | `"/usr/share/xsessions"` | | No | | `SESSIONS_XSESSIONS` | `"/usr/share/xsessions"` | | No |
| `SESSIONS_XSESSIONS_LOCAL` | `"/usr/local/share/xsessions"` | | No |
| `SESSIONS_WAYLAND` | `"/usr/share/wayland-sessions"` | | No | | `SESSIONS_WAYLAND` | `"/usr/share/wayland-sessions"` | | No |
| `SESSIONS_WAYLAND_LOCAL` | `"/usr/local/share/wayland-sessions"` | | No |
| `LIDM_CONF_PATH` | `"/etc/lidm.ini"` | Path of the default configuration. | Yes (`LIDM_CONF`) | | `LIDM_CONF_PATH` | `"/etc/lidm.ini"` | Path of the default configuration. | Yes (`LIDM_CONF`) |
| `LOGIN_SHELL` | `"bash"` | Login shell name. | No |
# Other Build Settings # Other Build Settings
@@ -54,9 +51,7 @@ But this can be changed by just passing those env variables, for example, in the
## Target Directory ## Target Directory
`DESTDIR` can be used to for installation recipes to install on alternative root directories. Along with `PREFIX` (defaults to `/usr/local`, packaging this you'll probably want to make it `/usr`) for systems which don't use the common `/usr` structure. e.g. `make install DESTDIR=$out PREFIX=` `DESTDIR` can be used to for installation recipes to install on alternative root directories. Along with `PREFIX` (defaults to `/usr`) for systems which don't use the common `/usr` structure. e.g. `make install DESTDIR=$out PREFIX=`
`/etc` is sometimes in that `PREFIX` and sometimes not, be careful.
```txt ```txt
$ fd -t f . --base-directory $out $ fd -t f . --base-directory $out
@@ -72,7 +67,7 @@ To ease most of the installation process there's several `make` recipes to insta
- `make` / `make lidm`: Builds the app binary. - `make` / `make lidm`: Builds the app binary.
- `make install`: Attempts to install the binary, place a default config file in `/etc/lidm.ini` and install the man pages. - `make install`: Attempts to install the binary, place a default config file in `/etc/lidm.ini` and install the man pages.
- `make install-service-(systemd|dinit|runit|openrc|s6)(|-etc)`: Just check the source, service files for different init systems and `-etc` variants for alternative paths. You might need `FORCE=1` in the environment if you are packaging for other init system or scripting. - `make install-service-(systemd|dinit|runit|openrc|s6)(|-etc)`: Just check the source, service files for different init systems and `-etc` variants for alternative paths.
- `make print-version`: Outputs the current version in the `Makefile` for scripts that might want to extract that info. - `make print-version`: Outputs the current version in the `Makefile` for scripts that might want to extract that info.
You can choose to use these packages or create your own service files / etc. There's are merely suggestions on what to use. You can choose to use these packages or create your own service files / etc. There's are merely suggestions on what to use.

View File

@@ -6,7 +6,7 @@
#include "keys.h" #include "keys.h"
#include "macros.h" #include "macros.h"
#include "util/vec.h" #include "util.h"
enum IntrospectionType { enum IntrospectionType {
STRING, STRING,
@@ -122,8 +122,7 @@ BUILD(strings, STRINGS, TABLE_STRINGS);
F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \ F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \
F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name) \ F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name) \
F(char* NNULLABLE, timefmt, STRING, "%X %x", name) \ F(char* NNULLABLE, timefmt, STRING, "%X %x", name) \
F(long long, refresh_rate, NUMBER, 100, name) \ F(long long, refresh_rate, NUMBER, 100, name)
F(bool, bypass_shell_login, BOOL, false, name)
BUILD(behavior, BEHAVIOR, TABLE_BEHAVIOR); BUILD(behavior, BEHAVIOR, TABLE_BEHAVIOR);

View File

@@ -6,7 +6,7 @@
#include "macros.h" #include "macros.h"
char* NULLABLE desktop_as_cmdline(char** args); int execvpe_desktop(char** args, char* NNULLABLE* NNULLABLE envlist);
int parse_exec_string(const char* exec_s, int* arg_count, char*** args); int parse_exec_string(const char* exec_s, int* arg_count, char*** args);
void free_parsed_args(int arg_count, char** args); void free_parsed_args(int arg_count, char** args);

View File

@@ -2,17 +2,16 @@
#define EFIELDH_ #define EFIELDH_
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
// holds also the max string buffer in itself, not dynamic // holds also the max string buffer in itself, not dynamic
struct editable_field { struct editable_field {
uint8_t pos; u_char pos;
char content[255]; char content[255];
}; };
struct editable_field efield_new(char* content); struct editable_field efield_new(char* content);
void efield_trim(struct editable_field* self, uint8_t pos); void efield_trim(struct editable_field* self, u_char pos);
void efield_update(struct editable_field* self, char* update); void efield_update(struct editable_field* self, char* update);
bool efield_seek(struct editable_field* self, char seek); bool efield_seek(struct editable_field* self, char seek);

View File

@@ -1,10 +1,7 @@
#ifndef KEYSH_ #ifndef KEYSH_
#define KEYSH_ #define KEYSH_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
enum Keys { enum Keys {
ESC, ESC,
@@ -106,15 +103,4 @@ static const struct key_mapping KEY_MAPPINGS[] = {
{PAGE_DOWN, {"\x1b[6~", NULL}}, {PAGE_DOWN, {"\x1b[6~", NULL}},
}; };
struct option_keys {
bool is_some;
enum Keys key;
};
int find_keyname(enum Keys* at, const char* name);
struct option_keys find_ansi(const char* seq);
void read_press(uint8_t* length, char* out);
// non blocking, waits up to tv or interrupt, returns true if actually read
bool read_press_nb(uint8_t* length, char* out, struct timeval* tv);
#endif #endif

View File

@@ -18,6 +18,6 @@ void ofield_kbd_type(struct opts_field* self, char* typed, char* empty_default);
bool ofield_opts_seek(struct opts_field* self, char seek); bool ofield_opts_seek(struct opts_field* self, char seek);
bool ofield_seek(struct opts_field* self, char seek); bool ofield_seek(struct opts_field* self, char seek);
uint8_t ofield_display_cursor_col(struct opts_field* self, uint8_t maxlen); u_char ofield_display_cursor_col(struct opts_field* self, u_char maxlen);
#endif #endif

View File

@@ -4,8 +4,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "desktop_exec.h"
#include "macros.h" #include "macros.h"
#include "util/vec.h" #include "util.h"
enum SessionType { enum SessionType {
XORG, XORG,
@@ -50,6 +51,18 @@ static inline struct session_exec session_exec_desktop(
}; };
} }
static inline int session_exec_exec(struct session_exec* NNULLABLE exec,
char* NULLABLE* NNULLABLE envlist) {
switch (exec->typ) {
case EXEC_SHELL:
return execle(exec->shell, exec->shell, NULL, envlist);
case EXEC_DESKTOP:
return execvpe_desktop(exec->desktop.args, envlist);
default:
__builtin_unreachable();
}
}
struct session { struct session {
char* NNULLABLE name; char* NNULLABLE name;
struct session_exec exec; struct session_exec exec;
@@ -57,9 +70,5 @@ struct session {
}; };
struct Vector get_avaliable_sessions(); struct Vector get_avaliable_sessions();
int session_exec_exec(struct session_exec* NNULLABLE exec,
char* NULLABLE* NNULLABLE envp);
int session_exec_login_through_shell(struct session_exec* NNULLABLE exec,
char* NULLABLE* NNULLABLE envp);
#endif #endif

View File

@@ -1,8 +0,0 @@
#ifndef SIGNALHANDLERH_
#define SIGNALHANDLERH_
// handle SIGTERM by sending SIGTERM to all children, resulting
// in a graceful graphical shutdown
void setup_sigterm();
#endif /* SIGNALHANDLERH_ */

View File

@@ -3,7 +3,7 @@
#include "config.h" #include "config.h"
#include "ofield.h" #include "ofield.h"
#include "util/vec.h" #include "util.h"
// [box_start] // [box_start]
// ↓ // ↓
@@ -40,7 +40,7 @@
#define VALUE_MAXLEN (BOX_WIDTH - VALUES_COL + 1 - BOX_HMARGIN - 2) #define VALUE_MAXLEN (BOX_WIDTH - VALUES_COL + 1 - BOX_HMARGIN - 2)
enum Input { SESSION, USER, PASSWD }; enum Input { SESSION, USER, PASSWD };
extern const uint8_t INPUTS_N; extern const u_char INPUTS_N;
void setup(struct config* config); void setup(struct config* config);
int load(struct Vector* users, struct Vector* sessions); int load(struct Vector* users, struct Vector* sessions);

View File

@@ -3,7 +3,7 @@
#include <sys/types.h> #include <sys/types.h>
#include "util/vec.h" #include "util.h"
struct user { struct user {
char* shell; char* shell;

54
include/util.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef UTILH_
#define UTILH_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include "keys.h"
int find_keyname(enum Keys* at, const char* name);
struct option_keys {
bool is_some;
enum Keys key;
};
struct option_keys find_ansi(const char* seq);
void read_press(u_char* length, char* out);
// non blocking, waits up to tv or interrupt, returns true if actually read
bool read_press_nb(u_char* length, char* out, struct timeval* tv);
// UTF8
//
bool utf8_iscont(char byte);
size_t utf8len(const char* str);
size_t utf8len_until(const char* str, const char* until);
size_t utf8trunc(char* str, size_t n);
const char* utf8back(const char* str);
const char* utf8seek(const char* str);
const char* utf8seekn(const char* str, size_t n);
// Vector
//
struct Vector {
uint32_t length;
uint32_t capacity;
void** pages;
};
struct Vector vec_from_raw(void** raw);
void** vec_as_raw(struct Vector self);
extern const struct Vector VEC_NEW;
int vec_resize(struct Vector* self, size_t size);
int vec_reserve(struct Vector* self, size_t size);
int vec_reserve_exact(struct Vector* self, size_t size);
int vec_push(struct Vector* self, void* item);
void vec_free(struct Vector* self);
void vec_clear(struct Vector* self);
void vec_reset(struct Vector* self);
void* vec_pop(struct Vector* self); // won't free it, nor shrink vec list space
void* vec_get(struct Vector* self, size_t index);
#endif

View File

@@ -1,10 +0,0 @@
#ifndef UTIL_PATH_H
#define UTIL_PATH_H
#include "macros.h"
char* NULLABLE search_path(const char* NNULLABLE for_binary);
int execvpe(const char* NNULLABLE file, char* NULLABLE const argv[NNULLABLE],
char* NULLABLE const envp[NNULLABLE]);
#endif /* UTIL_PATH_H */

View File

@@ -1,15 +0,0 @@
#ifndef UTIL_UTF8_H
#define UTIL_UTF8_H
#include <stdbool.h>
#include <stddef.h>
bool utf8_iscont(char byte);
size_t utf8len(const char* str);
size_t utf8len_until(const char* str, const char* until);
size_t utf8trunc(char* str, size_t n);
const char* utf8back(const char* str);
const char* utf8seek(const char* str);
const char* utf8seekn(const char* str, size_t n);
#endif /* UTIL_UTF8_H */

View File

@@ -1,26 +0,0 @@
#ifndef UTIL_VEC_H
#define UTIL_VEC_H
#include <stddef.h>
#include <stdint.h>
struct Vector {
uint32_t length;
uint32_t capacity;
void** pages;
};
struct Vector vec_from_raw(void** raw);
void** vec_as_raw(struct Vector self);
extern const struct Vector VEC_NEW;
int vec_resize(struct Vector* self, size_t size);
int vec_reserve(struct Vector* self, size_t size);
int vec_reserve_exact(struct Vector* self, size_t size);
int vec_push(struct Vector* self, void* item);
void vec_free(struct Vector* self);
void vec_clear(struct Vector* self);
void vec_reset(struct Vector* self);
void* vec_pop(struct Vector* self); // won't free it, nor shrink vec list space
void* vec_get(struct Vector* self, size_t index);
#endif /* UTIL_VEC_H */

View File

@@ -1,91 +0,0 @@
install-service:
@if command -v systemctl &> /dev/null; then \
make install-service-systemd; \
elif command -v dinitctl &> /dev/null; then \
make install-service-dinit; \
elif command -v sv &> /dev/null; then \
if [ -d /etc/sv ]; then \
make install-service-runit; \
elif [ -d /etc/runit/sv ]; then \
make install-service-runit-etc; \
else \
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
fi \
elif command -v rc-update &> /dev/null; then \
make install-service-openrc; \
elif command -v s6-service &> /dev/null; then \
if [ -d /etc/sv ]; then \
make install-service-s6; \
elif [ -d /etc/r6nit/sv ]; then \
make install-service-s6-etc; \
else \
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
fi \
else \
printf '\033[1;31m%s\033[0m\n' "Unknown init system, skipping service install..." >&2; \
fi
install-service-systemd:
@sed -e 's|ExecStart=/usr/bin/lidm|ExecStart=${DESTDIR}${PREFIX}/bin/lidm|' ./assets/services/systemd.service > ./dist/lidm.service
install -Dm644 ./dist/lidm.service ${DESTDIR}${PREFIX}/lib/systemd/system/lidm.service
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'systemctl enable lidm'"
install-service-dinit:
install -m644 ./assets/services/dinit ${DESTDIR}/etc/dinit.d/lidm
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'dinitctl enable lidm'"
install-service-runit:
@if [ ! -e /etc/sv ] && [ -d /etc/runit/sv ] && [ -z "$$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/runit/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit-etc'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/sv/lidm
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/sv/lidm /var/service' or your distro equivalent"
install-service-runit-etc:
@if [ ! -e /etc/runit/sv ] && [ -d /etc/sv ] && [ -z "$$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/runit/sv doesn't exist but /etc/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/runit/sv/lidm
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/runit/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/runit/sv/lidm /run/runit/service' or your distro equivalent"
install-service-openrc:
install -m755 ./assets/services/openrc ${DESTDIR}/etc/init.d/lidm
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'rc-update add lidm'"
install-service-s6:
@if [ ! -e /etc/sv ] && [ -d /etc/s6/sv ] && [ -z "$$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/s6/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6-etc'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/sv/lidm
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
install-service-s6-etc:
@if [ ! -e /etc/s6/sv ] && [ -d /etc/sv ] && [ -z "$$FORCE" ]; then \
printf '\033[31m%s\033[0m\n' "/etc/s6/sv doesn't exist but /etc/sv does" >&2; \
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6'" >&2; \
exit 1; \
fi
mkdir -p ${DESTDIR}/etc/s6/sv/lidm
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/s6/sv/lidm/
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
uninstall-service:
rm -rf \
${DESTDIR}${PREFIX}/lib/systemd/system/lidm.service \
${DESTDIR}/etc/dinit.d/lidm \
${DESTDIR}/etc/sv/lidm \
${DESTDIR}/etc/runit/sv/lidm \
${DESTDIR}/etc/init.d/lidm \
${DESTDIR}/etc/s6/sv/lidm
.PHONY: install-service uninstall-service \
install-service-s6 \
install-service-s6-etc \
install-service-dinit \
install-service-runit \
install-service-runit-etc \
install-service-openrc \
install-service-systemd

View File

@@ -1,11 +1,10 @@
// TODO: handle `fork() == -1` // TODO: handle `fork() == -1`// TODO: handle `fork() == -1`s
#include <errno.h> #include <errno.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <security/pam_misc.h> #include <security/pam_misc.h>
#include <signal.h> #include <signal.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -22,10 +21,11 @@
#include "pam.h" #include "pam.h"
#include "sessions.h" #include "sessions.h"
#include "ui.h" #include "ui.h"
#include "util/path.h" #include "util.h"
#include "util/vec.h"
#define XORG_MESSAGE_LENGTH 16 #define DEFAULT_XORG_DISPLAY 0
// no PATH search for now
#define XORG_COMMAND "/usr/bin/X"
static void try_source_file(struct Vector* NNULLABLE vec_envlist, static void try_source_file(struct Vector* NNULLABLE vec_envlist,
char* NNULLABLE filepath) { char* NNULLABLE filepath) {
@@ -82,151 +82,103 @@ static void source_paths(struct Vector* NNULLABLE vec_envlist,
} }
} }
/*char *buf;*/
/*size_t bsize = snprintf(NULL, 0, "/run/user/%d", pw->pw_uid) + 1;*/
/*buf = malloc(bsize);*/
/*snprintf(buf, bsize, "/run/user/%d", pw->pw_uid);*/
/*setenv("XDG_RUNTIME_DIR", buf, true);*/
/*setenv("XDG_SESSION_CLASS", "user", true);*/
/*setenv("XDG_SESSION_ID", "1", true);*/
/*setenv("XDG_SESSION_DESKTOP", , true);*/
/*setenv("XDG_SEAT", "seat0", true);*/
struct child_msg { struct child_msg {
char* msg; char* msg;
int _errno; int _errno;
bool err; bool err;
}; };
/// block until X returns the display number or an error occurs // TODO: OR check if xorg_pid fail exited
static bool x_get_display(const int xorg_pipefd[2], int* display) { static int wait_for_x_ready(const int xorg_pipefd[1], __pid_t xorg_pid) {
char buffer[XORG_MESSAGE_LENGTH]; // TODO
bool status; UNUSED(xorg_pipefd);
UNUSED(xorg_pid);
close(xorg_pipefd[1]); sleep(2);
ssize_t bytes_read = read(xorg_pipefd[0], buffer, sizeof(buffer) - 1); return 0;
buffer[bytes_read] = '\0';
if (bytes_read > 0) {
char* endptr;
int val = (int)strtol(buffer, &endptr, 10);
if (endptr == buffer) {
(void)fputs("failed to parse Xorg display response\n", stderr);
status = false;
} else {
*display = val;
status = true;
}
} else if (bytes_read == 0) {
(void)fputs("Xorg pipe closed\n", stderr);
status = false;
} else {
perror("read");
status = false;
}
close(xorg_pipefd[0]);
return status;
}
/// small helper to push dyn arr
static void push_dyn_arr(void*** arr, void* item) {
struct Vector vec = vec_from_raw(*arr);
vec_push(&vec, item);
*arr = vec_as_raw(vec);
} }
// TODO: properly pass this down // TODO: properly pass this down
extern int vt; extern int vt;
// TODO: add error msgs
static void start_xorg_server(struct passwd* pw, char** NNULLABLE envlist, static void launch_with_xorg_server(struct session_exec* NNULLABLE exec,
int xorg_pipefd[2]) { struct passwd* pw,
close(xorg_pipefd[0]); char** NNULLABLE envlist) {
int xorg_pipefd[2];
pipe(xorg_pipefd);
(void)fflush(NULL);
__pid_t xorg_pid = fork();
if (xorg_pid == 0) {
if (!pw->pw_dir) _exit(EXIT_FAILURE); if (!pw->pw_dir) _exit(EXIT_FAILURE);
// !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but // !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but
// for now I can't so be careful // for now I can't so be careful
if (vt == -1) _exit(EXIT_FAILURE); if (vt == -1) _exit(EXIT_FAILURE);
// pass the pipe so Xorg can write the DISPLAY value in there char* display_thing;
char* fd_str; asprintf(&display_thing, ":%d", DEFAULT_XORG_DISPLAY);
asprintf(&fd_str, "%d", xorg_pipefd[1]); if (!display_thing) _exit(EXIT_FAILURE);
if (!fd_str) _exit(EXIT_FAILURE);
char* vt_path; char* vt_path;
asprintf(&vt_path, "vt%d", vt); asprintf(&vt_path, "vt%d", vt);
if (!vt_path) { if (!vt_path) {
free(fd_str); free(display_thing);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
char* xorg_path = search_path("Xorg"); // dup2(xorg_pipefd[1], STDERR_FILENO);
if (!xorg_path) { // dup2(xorg_pipefd[1], STDOUT_FILENO);
(void)fputs("couldn't find Xorg binary in PATH, sure it's installed?\n", // close(xorg_pipefd[0]);
stderr); // close(xorg_pipefd[1]);
_exit(EXIT_FAILURE);
}
int exit = execle(xorg_path, xorg_path, "-displayfd", fd_str, vt_path, NULL, int exit = execle(XORG_COMMAND, XORG_COMMAND, display_thing, vt_path, NULL,
envlist); envlist);
perror("exec"); perror("exec");
// execle("X", "X", display_thing, vt_path, "-auth", xauth_path,
// "-nolisten", "tcp", "-background", "none", NULL, envlist);
printf("wtf3\n");
(void)fflush(stdout);
free(vt_path); free(vt_path);
free(fd_str); free(display_thing);
free(xorg_path);
_exit(exit); _exit(exit);
}
// TODO: add error msgs
/// returns on completion
static void launch_with_xorg_server(struct config* config,
struct session_exec* NNULLABLE exec,
struct passwd* pw,
char** NNULLABLE envlist) {
int xorg_pipefd[2];
if (pipe(xorg_pipefd) == -1) _exit(EXIT_FAILURE);
(void)fflush(NULL);
pid_t xorg_pid = fork();
if (xorg_pid == 0) {
start_xorg_server(pw, envlist, xorg_pipefd);
} }
int display = 0; wait_for_x_ready(xorg_pipefd, xorg_pid);
if (!x_get_display(xorg_pipefd, &display)) {
(void)fputs("failed to get X display, aborting\n", stderr);
int status;
waitpid(xorg_pid, &status, 0);
_exit(EXIT_FAILURE);
}
char* display_env; __pid_t xorg_session_pid = fork();
asprintf(&display_env, "DISPLAY=:%d", display);
if (!display_env) {
(void)fputs("failure allocating memory for DISPLAY string\n", stderr);
_exit(EXIT_FAILURE);
}
// convert back for convenient push-ing
push_dyn_arr((void***)&envlist, display_env);
if (!envlist) {
(void)fputs("failure allocating memory for DISPLAY env\n", stderr);
_exit(EXIT_FAILURE);
}
(void)fflush(NULL);
pid_t xorg_session_pid = fork();
if (xorg_session_pid == 0) { if (xorg_session_pid == 0) {
if (config->behavior.bypass_shell_login) int exit = session_exec_exec(exec, envlist);
session_exec_exec(exec, envlist); perror("exec error");
else
session_exec_login_through_shell(exec, envlist);
perror("session exec error");
(void)fputs("failure calling session\n", stderr); (void)fputs("failure calling session\n", stderr);
_exit(EXIT_FAILURE); _exit(exit);
} }
// looks weird, waiting on -1 should wait on any child and then just check if // looks weird, waiting on -1 should wait on any child and then just check if
// its xorg server or the session and kill the other waiting on it // its xorg server or the session and kill the other waiting on it
pid_t pid; __pid_t pid;
int status; // not even read for now int status; // not even read for now
while ((pid = waitpid(-1, &status, 0)) > 0) { while ((pid = waitpid(-1, &status, 0)) > 0) {
if (pid == xorg_pid || pid == xorg_session_pid) { if (pid == xorg_pid || pid == xorg_session_pid) {
pid_t pid_to_kill = pid ^ xorg_pid ^ xorg_session_pid; __pid_t pid_to_kill = pid ^ xorg_pid ^ xorg_session_pid;
if (pid == xorg_pid) printf("Xorg server died\n"); if (pid == xorg_pid) printf("Xorg server died\n");
if (pid == xorg_session_pid) printf("Xorg session died\n"); if (pid == xorg_session_pid) printf("Xorg session died\n");
kill(pid_to_kill, SIGTERM); kill(pid_to_kill, SIGTERM);
waitpid(pid_to_kill, &status, 0); waitpid(pid_to_kill, &status, 0);
printf("wtf %d, x%d s%d - k%d\n", status, xorg_pid, xorg_session_pid,
pid_to_kill);
(void)fflush(stdout);
sleep(10);
break; break;
} }
@@ -251,8 +203,8 @@ static void launch_with_xorg_server(struct config* config,
char _dummy; \ char _dummy; \
read(pipefd[0], &_dummy, sizeof(_dummy)); \ read(pipefd[0], &_dummy, sizeof(_dummy)); \
} }
inline static void forked(struct config* config, int pipefd[2], inline static void forked(int pipefd[2], struct passwd* pw,
struct passwd* pw, char* NNULLABLE user, char* NNULLABLE user,
struct session* NNULLABLE session, struct session* NNULLABLE session,
char** NNULLABLE envlist) { char** NNULLABLE envlist) {
if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir"); if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir");
@@ -264,26 +216,13 @@ inline static void forked(struct config* config, int pipefd[2],
DUMMY_READ(); DUMMY_READ();
close(pipefd[0]); close(pipefd[0]);
if (!getenv("PATH")) {
size_t path_size = confstr(_CS_PATH, NULL, 0);
char* path_env = malloc(path_size);
confstr(_CS_PATH, path_env, path_size);
setenv("PATH", path_env, 1);
free(path_env);
}
log_printf(" [I] using shell login?: %s",
config->behavior.bypass_shell_login ? "true" : "false");
if (session->type == XORG) { if (session->type == XORG) {
launch_with_xorg_server(config, &session->exec, pw, envlist); launch_with_xorg_server(&session->exec, pw, envlist);
_exit(EXIT_SUCCESS);
} else { } else {
if (config->behavior.bypass_shell_login) int exit = session_exec_exec(&session->exec, envlist);
session_exec_exec(&session->exec, envlist); perror("exec error");
else (void)fputs("failure calling session\n", stderr);
session_exec_login_through_shell(&session->exec, envlist); _exit(exit);
perror("session exec error");
_exit(EXIT_FAILURE);
} }
} }
#undef SEND_MSG #undef SEND_MSG
@@ -321,6 +260,16 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist); struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist);
if (session.type == XORG) {
char* display_env;
asprintf(&display_env, "DISPLAY=:%d", DEFAULT_XORG_DISPLAY);
if (!display_env) {
print_err("alloc error");
return false;
}
vec_push(&envlist_vec, display_env);
}
source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir, source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir,
&config->behavior.user_source); &config->behavior.user_source);
char** envlist = (char**)vec_as_raw(envlist_vec); char** envlist = (char**)vec_as_raw(envlist_vec);
@@ -334,7 +283,7 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
uint pid = fork(); uint pid = fork();
if (pid == 0) if (pid == 0)
forked(config, pipefd, pw, user, &session, envlist); forked(pipefd, pw, user, &session, envlist);
else { else {
struct child_msg msg; struct child_msg msg;
read(pipefd[0], &msg, sizeof(struct child_msg)); read(pipefd[0], &msg, sizeof(struct child_msg));

View File

@@ -11,15 +11,14 @@
#include "config.h" #include "config.h"
#include "desktop.h" #include "desktop.h"
#include "keys.h"
#include "log.h" #include "log.h"
#include "macros.h" #include "macros.h"
#include "util/vec.h" #include "util.h"
#define UPPER_HALF_BYTE 4 #define UPPER_HALF_BYTE 4
int parse_hex(char* _at, char x1, char x2) { int parse_hex(char* _at, char x1, char x2) {
// make linter happy // make linter happy
uint8_t* at = (uint8_t*)_at; u_char* at = (u_char*)_at;
*at = 0; *at = 0;

View File

@@ -9,39 +9,54 @@
#include "desktop_exec.h" #include "desktop_exec.h"
#include "macros.h" #include "macros.h"
#include "util/path.h"
// constants for exec string parsing // constants for exec string parsing
#define MAX_ARGS 100 #define MAX_ARGS 100
// ARG_LENGTH is the initial length of a parsed argument // ARG_LENGTH is the initial length of a parsed argument
#define ARG_LENGTH 64 #define ARG_LENGTH 64
char* NULLABLE desktop_as_cmdline(char** args) { // returns NULL on any error
if (args[0] == NULL) return NULL; // otherwise it returns the absolute path of the program that MUST BE FREED
size_t fmtd_len = 0; static char* NULLABLE search_path(const char* NNULLABLE for_binary) {
char* path_env = getenv("PATH");
if (!path_env) return NULL;
char* path = strdup(path_env);
if (!path) return NULL;
char** ptr = args; char* tok = strtok(path, ":");
while (*ptr) { while (tok) {
fmtd_len += strlen(*ptr) + 1; char* bin_path;
ptr++; asprintf(&bin_path, "%s/%s", tok, for_binary);
if (!bin_path) {
free(path);
return NULL;
} }
fmtd_len -= 1;
char* fmt_cmdline = malloc(fmtd_len + 1); struct stat stat_buf;
if (!fmt_cmdline) return NULL; if (stat(bin_path, &stat_buf) == 0) {
// TODO: check exec bit ig
size_t fmting_len = 0; // if(stat_buf.) {}
ptr = args; free(path);
while (*ptr) { return bin_path;
char* nbyte = stpcpy(&fmt_cmdline[fmting_len], *ptr);
*nbyte = ' ';
fmting_len += nbyte - &fmt_cmdline[fmting_len] + 1;
ptr++;
} }
fmt_cmdline[fmting_len - 1] = '\0';
return fmt_cmdline; free(bin_path);
tok = strtok(NULL, ":");
}
free(path);
return NULL;
}
// returns -1 on exec failure and -2 on search failure
int execvpe_desktop(char** args, char* NNULLABLE* NNULLABLE envlist) {
char* new_arg = search_path(args[0]);
if (!new_arg) return -2;
free(args[0]);
args[0] = new_arg;
return execve(args[0], args, envlist);
} }
// parse Exec=/bin/prog arg1 arg2\ with\ spaces // parse Exec=/bin/prog arg1 arg2\ with\ spaces

View File

@@ -2,7 +2,7 @@
#include "efield.h" #include "efield.h"
#include "ui.h" #include "ui.h"
#include "util/utf8.h" #include "util.h"
struct editable_field efield_new(char* content) { struct editable_field efield_new(char* content) {
struct editable_field efield; struct editable_field efield;
@@ -16,14 +16,14 @@ struct editable_field efield_new(char* content) {
return efield; return efield;
} }
void efield_trim(struct editable_field* self, uint8_t pos) { void efield_trim(struct editable_field* self, u_char pos) {
self->pos = pos; self->pos = pos;
self->content[pos + 1] = '\0'; self->content[pos + 1] = '\0';
} }
#define BACKSPACE_CODE 127 #define BACKSPACE_CODE 127
void efield_update(struct editable_field* self, char* update) { void efield_update(struct editable_field* self, char* update) {
uint8_t insert_len = strlen(update); u_char insert_len = strlen(update);
if (insert_len == 0) return; if (insert_len == 0) return;
if (self->pos > strlen(self->content)) if (self->pos > strlen(self->content))
@@ -61,7 +61,7 @@ bool efield_seek(struct editable_field* self, char seek) {
if (*self->content == '\0') return false; if (*self->content == '\0') return false;
if (seek == 0) return false; if (seek == 0) return false;
uint8_t count = seek < 0 ? -seek : seek; u_char count = seek < 0 ? -seek : seek;
char* ptr = &self->content[self->pos]; char* ptr = &self->content[self->pos];
char* start = ptr; char* start = ptr;
@@ -75,6 +75,6 @@ bool efield_seek(struct editable_field* self, char seek) {
} }
} }
self->pos = (uint8_t)(ptr - self->content); self->pos = (u_char)(ptr - self->content);
return ptr != start; return ptr != start;
} }

View File

@@ -1,77 +0,0 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "keys.h"
#include "macros.h"
#include "ui.h"
static int selret_magic();
int find_keyname(enum Keys* at, const char* name) {
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
if (strcmp(KEY_NAMES[i], name) == 0) {
*at = (enum Keys)i;
return 0;
}
}
return -1;
}
struct option_keys find_ansi(const char* seq) {
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
struct key_mapping mapping = KEY_MAPPINGS[i];
for (size_t j = 0; mapping.sequences[j] != NULL; j++) {
if (strcmp(mapping.sequences[j], seq) == 0) {
return (struct option_keys){
.is_some = true,
.key = (enum Keys)i,
};
}
}
}
return (struct option_keys){.is_some = false};
}
void read_press(uint8_t* length, char* out) {
*length = 0;
while (true) {
if (read(STDIN_FILENO, &out[(*length)++], 1) != 1) {
print_errno("read error");
sleep(3);
exit(1);
}
int selret = selret_magic();
if (selret == -1) {
print_errno("selret error");
} else if (selret != 1) {
out[*length] = '\0';
return;
}
}
}
bool read_press_nb(uint8_t* length, char* out, struct timeval* tv) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
errno = 0;
int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv);
if (errno || ret <= 0) return false;
read_press(length, out);
return true;
}
// https://stackoverflow.com/a/48040042
static int selret_magic() {
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return select(1, &set, NULL, NULL, &timeout);
}

View File

@@ -21,17 +21,19 @@ int read_launch_state(struct LaunchState* NNULLABLE state) {
}; };
size_t num = 0; size_t num = 0;
ssize_t chars = getline(&state->username, &num, state_fd); if (getline(&state->username, &num, state_fd) < 0) goto fail;
if (chars < 0) goto fail; // not sure I can actually prove it but ughh, getline < 0 will ensure there's
if (state->username[chars] == '\n') state->username[chars] = 0; // something in the string and then I think strcspn is bounded to the final
// null byte, so it shouldn't go over
// NOLINTNEXTLINE(clang-analyzer-security.ArrayBound)
state->username[strcspn(state->username, "\n")] = 0;
num = 0; num = 0;
chars = getline(&state->session_opt, &num, state_fd); if (getline(&state->session_opt, &num, state_fd) < 0) {
if (chars < 0) {
free(state->session_opt); free(state->session_opt);
goto fail; goto fail;
} }
if (state->session_opt[chars] == '\n') state->session_opt[chars] = 0; state->session_opt[strcspn(state->session_opt, "\n")] = 0;
(void)fclose(state_fd); (void)fclose(state_fd);
return 0; return 0;

View File

@@ -8,7 +8,6 @@ static FILE* logger_out = NULL;
void log_init(FILE* fd) { void log_init(FILE* fd) {
if (logger_out) (void)fclose(logger_out); if (logger_out) (void)fclose(logger_out);
(void)setvbuf(fd, NULL, _IONBF, 0);
logger_out = fd; logger_out = fd;
} }

View File

@@ -12,13 +12,12 @@
#include "log.h" #include "log.h"
#include "macros.h" #include "macros.h"
#include "sessions.h" #include "sessions.h"
#include "signal_handler.h"
#include "ui.h" #include "ui.h"
#include "users.h" #include "users.h"
#include "util/vec.h" #include "util.h"
#include "version.h"
#define DATESTR_MAXBUFSIZE 0x20 #define DATESTR_MAXBUFSIZE 0x20
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Logger // Logger
char* log_output = getenv("LIDM_LOG"); char* log_output = getenv("LIDM_LOG");
@@ -31,7 +30,6 @@ int main(int argc, char* argv[]) {
} }
log_init(log_fd); log_init(log_fd);
log_puts("Starting log:");
} }
if (argc == 2) { if (argc == 2) {
@@ -87,8 +85,6 @@ int main(int argc, char* argv[]) {
struct Vector users = get_human_users(); struct Vector users = get_human_users();
struct Vector sessions = get_avaliable_sessions(); struct Vector sessions = get_avaliable_sessions();
setup_sigterm();
int ret = load(&users, &sessions); int ret = load(&users, &sessions);
if (ret == 0) execl(argv[0], argv[0], NULL); if (ret == 0) execl(argv[0], argv[0], NULL);
} }

View File

@@ -1,9 +1,10 @@
#include <stddef.h> #include <stddef.h>
#include "config.h"
#include "efield.h" #include "efield.h"
#include "ofield.h" #include "ofield.h"
#include "ui.h" #include "ui.h"
#include "util/utf8.h" #include "util.h"
struct opts_field ofield_new(size_t opts) { struct opts_field ofield_new(size_t opts) {
if (opts == 0) { if (opts == 0) {
@@ -54,10 +55,10 @@ bool ofield_seek(struct opts_field* self, char seek) {
return true; return true;
} }
uint8_t ofield_display_cursor_col(struct opts_field* self, uint8_t maxlen) { u_char ofield_display_cursor_col(struct opts_field* self, u_char maxlen) {
if (self->current_opt == 0) { if (self->current_opt == 0) {
uint8_t display_len = utf8len(self->efield.content); u_char display_len = utf8len(self->efield.content);
uint8_t pos = utf8len_until(self->efield.content, u_char pos = utf8len_until(self->efield.content,
&self->efield.content[self->efield.pos]); &self->efield.content[self->efield.pos]);
if (display_len > maxlen) { if (display_len > maxlen) {

View File

@@ -6,7 +6,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "log.h"
#include "macros.h" #include "macros.h"
#include "pam.h" #include "pam.h"
#include "sessions.h" #include "sessions.h"
@@ -93,10 +92,6 @@ struct pamh_getenv_status pamh_get_complete_env(pam_handle_t* handle,
char** raw_envlist = pam_getenvlist(handle); char** raw_envlist = pam_getenvlist(handle);
if (!raw_envlist) FAIL(PAMH_ERR_ERRNO, "pam_getenvlist"); if (!raw_envlist) FAIL(PAMH_ERR_ERRNO, "pam_getenvlist");
char** ptr = raw_envlist;
while (*ptr)
log_printf("[I] got pam env %s\n", *(ptr++));
struct envpair extra_env[] = { struct envpair extra_env[] = {
{"TERM", getenv("TERM")}, {"TERM", getenv("TERM")},
{"PATH", getenv("PATH")}, {"PATH", getenv("PATH")},

View File

@@ -1,4 +1,3 @@
#include <errno.h>
#include <ftw.h> #include <ftw.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
@@ -7,16 +6,13 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include "config.h"
#include "desktop.h" #include "desktop.h"
#include "desktop_exec.h" #include "desktop_exec.h"
#include "log.h" #include "log.h"
#include "macros.h" #include "macros.h"
#include "sessions.h" #include "sessions.h"
#include "util/path.h" #include "util.h"
#include "util/vec.h"
struct source_dir { struct source_dir {
enum SessionType type; enum SessionType type;
@@ -26,19 +22,13 @@ struct source_dir {
#ifndef SESSIONS_XSESSIONS #ifndef SESSIONS_XSESSIONS
#define SESSIONS_XSESSIONS "/usr/share/xsessions" #define SESSIONS_XSESSIONS "/usr/share/xsessions"
#endif #endif
#ifndef SESSIONS_XSESSIONS_LOCAL
#define SESSIONS_XSESSIONS_LOCAL "/usr/local/share/xsessions"
#endif
#ifndef SESSIONS_WAYLAND #ifndef SESSIONS_WAYLAND
#define SESSIONS_WAYLAND "/usr/share/wayland-sessions" #define SESSIONS_WAYLAND "/usr/share/wayland-sessions"
#endif #endif
#ifndef SESSIONS_WAYLAND_LOCAL static const struct source_dir SOURCES[] = {
#define SESSIONS_WAYLAND_LOCAL "/usr/local/share/wayland-sessions" {XORG, SESSIONS_XSESSIONS},
#endif
static const struct source_dir SOURCES[] = {{XORG, SESSIONS_XSESSIONS},
{XORG, SESSIONS_XSESSIONS_LOCAL},
{WAYLAND, SESSIONS_WAYLAND}, {WAYLAND, SESSIONS_WAYLAND},
{WAYLAND, SESSIONS_WAYLAND_LOCAL}}; };
static struct Vector* cb_sessions = NULL; static struct Vector* cb_sessions = NULL;
@@ -167,54 +157,3 @@ struct Vector get_avaliable_sessions() {
return sessions; return sessions;
} }
int session_exec_exec(struct session_exec* NNULLABLE exec,
char* NULLABLE* NNULLABLE envp) {
switch (exec->typ) {
case EXEC_SHELL: {
char* argv[] = {exec->shell, NULL};
return execvpe(exec->shell, argv, envp);
}
case EXEC_DESKTOP:
return execvpe(exec->desktop.args[0], exec->desktop.args, envp);
default:
__builtin_unreachable();
}
}
/// So the reason this doesn't use the user shell is because that can really be
/// anything, also assuming it were fish for example, it can't execute posix
/// shell files and that leaves it out of most `/etc/profile.d/` scripts.
///
/// I'll just default to bash for now as it's able to source almost everything
/// and takes most flags. Maybe will try to make this more sophisticated in the
/// future.
///
/// This respects errno. Even also works as any exec family function.
#ifndef LOGIN_SHELL
#define LOGIN_SHELL "bash"
#endif
// This triggers login behavior
#define LOGIN_SHELL_ARG0 "-" LOGIN_SHELL
int session_exec_login_through_shell(struct session_exec* NNULLABLE exec,
char* NULLABLE* NNULLABLE envp) {
switch (exec->typ) {
case EXEC_SHELL: {
char* argv[] = {LOGIN_SHELL_ARG0, "-c", exec->shell, NULL};
return execvpe(LOGIN_SHELL, argv, envp);
}
case EXEC_DESKTOP: {
char* name = desktop_as_cmdline(exec->desktop.args);
if (!name) {
errno = EINVAL;
return -1;
}
char* argv[] = {LOGIN_SHELL_ARG0, "-c", name, NULL};
int ret = execvpe(LOGIN_SHELL, argv, envp);
free(name);
return ret;
}
default:
__builtin_unreachable();
}
}

View File

@@ -1,29 +0,0 @@
#include <errno.h>
#include <stddef.h>
#include <sys/wait.h>
#include <unistd.h>
#include "signal_handler.h"
static void handle_sigterm(int sig) {
(void)sig;
(void)signal(SIGTERM, SIG_IGN);
kill(-getpgrp(), SIGTERM);
int status;
while (waitpid(-1, &status, 0) > 0 || errno == EINTR) {
}
_exit(0);
}
void setup_sigterm() {
setpgid(0, 0);
struct sigaction sa;
sa.sa_handler = handle_sigterm;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
}

View File

@@ -32,9 +32,9 @@
#include "ui.h" #include "ui.h"
#include "ui_state.h" #include "ui_state.h"
#include "users.h" #include "users.h"
#include "util/utf8.h" #include "util.h"
const uint8_t INPUTS_N = 3; const u_char INPUTS_N = 3;
struct uint_point { struct uint_point {
uint x; uint x;
@@ -67,11 +67,6 @@ static void process_sigwinch(int signal) {
need_resize = 1; need_resize = 1;
} }
static inline void draw_bg() {
// apply bg color to all screen
printf("\x1b[%sm\x1b[2J", g_config->colors.bg);
}
void setup(struct config* config) { void setup(struct config* config) {
g_config = config; g_config = config;
@@ -81,9 +76,10 @@ void setup(struct config* config) {
term.c_lflag &= ~(ICANON | ECHO); term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDOUT_FILENO, TCSANOW, &term); tcsetattr(STDOUT_FILENO, TCSANOW, &term);
// save cursor pos, save screen // save cursor pos, save screen, set color and reset screen
printf("\x1b[s\x1b[?47h"); // (applying color to all screen)
draw_bg(); printf("\x1b[s\x1b[?47h\x1b[%s;%sm\x1b[2J", g_config->colors.bg,
g_config->colors.fg);
(void)atexit(restore_all); (void)atexit(restore_all);
(void)signal(SIGINT, signal_handler); (void)signal(SIGINT, signal_handler);
@@ -135,11 +131,11 @@ char* trunc_gethostname(size_t maxlen, const char* const ELLIPSIS) {
} }
void ui_update_cursor_focus() { void ui_update_cursor_focus() {
uint8_t line = box_start.y; u_char line = box_start.y;
uint8_t col = box_start.x + VALUES_COL; u_char col = box_start.x + VALUES_COL;
struct opts_field* ofield = get_opts_ffield(); struct opts_field* ofield = get_opts_ffield();
uint8_t maxlen = VALUE_MAXLEN; u_char maxlen = VALUE_MAXLEN;
if (ofield->opts > 1) { if (ofield->opts > 1) {
maxlen -= utf8len(g_config->strings.opts_pre) + maxlen -= utf8len(g_config->strings.opts_pre) +
utf8len(g_config->strings.opts_post); utf8len(g_config->strings.opts_post);
@@ -190,7 +186,6 @@ void ui_update_ofield(struct opts_field* NNULLABLE self) {
ui_update_field(input); ui_update_field(input);
} }
/// draw everything
void scratch_print_ui() { void scratch_print_ui() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
box_start = (struct uint_point){ box_start = (struct uint_point){
@@ -206,8 +201,7 @@ void scratch_print_ui() {
return; return;
} }
printf("\033[2J\033[H\033c"); // Clear screen printf("\033[2J\033[H"); // Clear screen
draw_bg();
/// PRINTING /// PRINTING
// printf box // printf box
@@ -269,7 +263,7 @@ int load(struct Vector* users, struct Vector* sessions) {
scratch_print_ui(); scratch_print_ui();
/// INTERACTIVE /// INTERACTIVE
uint8_t len; u_char len;
char seq[0xff]; char seq[0xff];
uint esc = 0; uint esc = 0;
while (true) { while (true) {
@@ -319,8 +313,6 @@ int load(struct Vector* users, struct Vector* sessions) {
&restore_all, g_config)) { &restore_all, g_config)) {
print_passwd(utf8len(of_passwd.efield.content), true); print_passwd(utf8len(of_passwd.efield.content), true);
ui_update_cursor_focus(); ui_update_cursor_focus();
} else {
scratch_print_ui();
} }
} else if (ansi_key == A_UP || ansi_key == A_DOWN) { } else if (ansi_key == A_UP || ansi_key == A_DOWN) {
st_ch_focus(ansi_key == A_DOWN ? 1 : -1); st_ch_focus(ansi_key == A_DOWN ? 1 : -1);
@@ -344,8 +336,6 @@ int load(struct Vector* users, struct Vector* sessions) {
&restore_all, g_config)) { &restore_all, g_config)) {
print_passwd(utf8len(of_passwd.efield.content), true); print_passwd(utf8len(of_passwd.efield.content), true);
ui_update_cursor_focus(); ui_update_cursor_focus();
} else {
scratch_print_ui();
} }
} else } else
st_kbd_type(seq, g_config->behavior.include_defshell); st_kbd_type(seq, g_config->behavior.include_defshell);
@@ -362,10 +352,10 @@ void clean_line(struct uint_point origin, uint line) {
printf("\x1b[%d;%dH%s", origin.y + line, origin.x + 1, line_cleaner); printf("\x1b[%d;%dH%s", origin.y + line, origin.x + 1, line_cleaner);
} }
uint8_t get_render_pos_offset(struct opts_field* self, uint8_t maxlen) { u_char get_render_pos_offset(struct opts_field* self, u_char maxlen) {
if (self->current_opt != 0) return 0; if (self->current_opt != 0) return 0;
uint8_t pos = utf8len_until(self->efield.content, u_char pos = utf8len_until(self->efield.content,
&self->efield.content[self->efield.pos]); &self->efield.content[self->efield.pos]);
return pos - ofield_display_cursor_col(self, maxlen); return pos - ofield_display_cursor_col(self, maxlen);
} }
@@ -439,7 +429,7 @@ void print_session(struct session session, bool multiple) {
char* toprint = session.name; char* toprint = session.name;
if (multiple) { if (multiple) {
uint8_t maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) - u_char maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
utf8len(g_config->strings.opts_post); utf8len(g_config->strings.opts_post);
toprint += get_render_pos_offset(&of_session, maxlen); toprint += get_render_pos_offset(&of_session, maxlen);
size_t printlen = utf8seekn(toprint, maxlen) - toprint; size_t printlen = utf8seekn(toprint, maxlen) - toprint;
@@ -467,14 +457,13 @@ void print_user(struct user user, bool multiple) {
char* toprint = user.display_name; char* toprint = user.display_name;
if (multiple) { if (multiple) {
uint8_t maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) - u_char maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
utf8len(g_config->strings.opts_post); utf8len(g_config->strings.opts_post);
toprint += get_render_pos_offset(&of_session, maxlen); toprint += get_render_pos_offset(&of_session, maxlen);
size_t printlen = utf8seekn(toprint, maxlen) - toprint; size_t printlen = utf8seekn(toprint, maxlen) - toprint;
printf("\r\x1b[%dC%s\x1b[%sm%.*s\x1b[%sm%s", box_start.x + VALUES_COL - 1, printf("\r\x1b[%dC< \x1b[%sm%.*s\x1b[%sm >", box_start.x + VALUES_COL - 1,
g_config->strings.opts_pre, user_color, (int)printlen, toprint, user_color, (int)printlen, toprint, g_config->colors.fg);
g_config->colors.fg, g_config->strings.opts_post);
} else { } else {
toprint += get_render_pos_offset(&of_user, VALUE_MAXLEN); toprint += get_render_pos_offset(&of_user, VALUE_MAXLEN);
size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint; size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint;

View File

@@ -7,7 +7,7 @@
#include "log.h" #include "log.h"
#include "macros.h" #include "macros.h"
#include "users.h" #include "users.h"
#include "util/vec.h" #include "util.h"
// NOLINTNEXTLINE(readability-identifier-length) // NOLINTNEXTLINE(readability-identifier-length)
int build_user(struct user* NNULLABLE user, struct passwd* p) { int build_user(struct user* NNULLABLE user, struct passwd* p) {

238
src/util.c Normal file
View File

@@ -0,0 +1,238 @@
#include <asm-generic/errno-base.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "keys.h"
#include "ui.h"
#include "util.h"
static int selret_magic();
int find_keyname(enum Keys* at, const char* name) {
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
if (strcmp(KEY_NAMES[i], name) == 0) {
*at = (enum Keys)i;
return 0;
}
}
return -1;
}
struct option_keys find_ansi(const char* seq) {
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
struct key_mapping mapping = KEY_MAPPINGS[i];
for (size_t j = 0; mapping.sequences[j] != NULL; j++) {
if (strcmp(mapping.sequences[j], seq) == 0) {
return (struct option_keys){
.is_some = true,
.key = (enum Keys)i,
};
}
}
}
return (struct option_keys){.is_some = false};
}
void read_press(u_char* length, char* out) {
*length = 0;
while (true) {
if (read(STDIN_FILENO, &out[(*length)++], 1) != 1) {
print_errno("read error");
sleep(3);
exit(1);
}
int selret = selret_magic();
if (selret == -1) {
print_errno("selret error");
} else if (selret != 1) {
out[*length] = '\0';
return;
}
}
}
bool read_press_nb(u_char* length, char* out, struct timeval* tv) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
errno = 0;
int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv);
if (errno || ret <= 0) return false;
read_press(length, out);
return true;
}
// https://stackoverflow.com/a/48040042
static int selret_magic() {
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return select(1, &set, NULL, NULL, &timeout);
}
// UTF-8 shii
#define UTF8_CONT_MSK 0b11000000
#define UTF8_CONT_VAL 0b10000000
bool utf8_iscont(char byte) {
return (byte & UTF8_CONT_MSK) == UTF8_CONT_VAL;
}
size_t utf8len(const char* str) {
size_t len = 0;
while (*str != '\0') {
if (!utf8_iscont(*(str++))) len++;
}
return len;
}
size_t utf8len_until(const char* str, const char* until) {
size_t len = 0;
while (str < until) {
if (!utf8_iscont(*(str++))) len++;
}
return len;
}
size_t utf8trunc(char* str, size_t n) {
size_t bytes = 0;
while (true) {
if (str[bytes] == '\0') break;
if (utf8_iscont(str[bytes])) {
bytes++;
continue;
}
if (n == 0) {
str[bytes] = '\0';
break;
}
bytes++;
n--;
}
return bytes;
}
const char* utf8back(const char* str) {
while (utf8_iscont(*(--str))) {
}
return str;
}
const char* utf8seek(const char* str) {
while (utf8_iscont(*(++str))) {
}
return str;
}
const char* utf8seekn(const char* str, size_t n) {
while (n > 0 && *str != '\0') {
str = utf8seek(str);
n--;
}
return str;
}
// Vector shii
const struct Vector VEC_NEW = {
.length = 0,
.capacity = 0,
.pages = NULL,
};
struct Vector vec_from_raw(void** raw) {
size_t len = 0;
while (raw[len])
len++;
return (struct Vector){
.length = len,
.capacity = len,
.pages = raw,
};
}
void** vec_as_raw(struct Vector self) {
if (vec_push(&self, NULL) != 0) return NULL;
return self.pages;
}
int vec_resize(struct Vector* self, size_t size) {
void** new_location =
(void**)realloc((void*)self->pages, size * sizeof(void*));
if (new_location != NULL) {
if (self->length > size) self->length = size;
self->capacity = size;
self->pages = new_location;
} else {
return -1;
}
return 0;
}
int vec_reserve(struct Vector* self, size_t size) {
uint32_t new_capacity = self->capacity;
while (self->length + size > new_capacity) {
new_capacity = new_capacity + (new_capacity >> 1) +
1; // cap * 1.5 + 1; 0 1 2 4 7 11...
}
return vec_resize(self, new_capacity);
}
int vec_reserve_exact(struct Vector* self, size_t size) {
uint32_t needed_capacity = self->length + size;
if (self->capacity < needed_capacity) {
return vec_resize(self, needed_capacity);
}
return 0;
}
int vec_push(struct Vector* self, void* item) {
int res_ret = vec_reserve(self, 1);
if (res_ret != 0) return res_ret;
self->pages[self->length++] = item;
return 0;
}
void vec_free(struct Vector* self) {
while (self->length > 0)
free(self->pages[--self->length]);
vec_clear(self);
}
void vec_clear(struct Vector* self) {
free((void*)self->pages);
vec_reset(self);
}
void vec_reset(struct Vector* self) {
*self = (struct Vector){
.length = 0,
.capacity = 0,
.pages = NULL,
};
}
void* vec_pop(struct Vector* self) {
if (self->length == 0) return NULL;
return self->pages[--self->length];
}
void* vec_get(struct Vector* self, size_t index) {
if (index >= self->length) return NULL;
return self->pages[index];
}

View File

@@ -1,64 +0,0 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "util/path.h"
// returns NULL on any error
// otherwise it returns the absolute path of the program that MUST BE FREED
//
// Should be almost completely posix compliant, except it won't resolve empty
// PATH entries relative to the cwd
char* NULLABLE search_path(const char* NNULLABLE for_binary) {
if (strchr(for_binary, '/') != NULL) {
// skip absolute paths
return strdup(for_binary);
}
char* path_env = getenv("PATH");
if (!path_env) return NULL;
char* path = strdup(path_env);
if (!path) return NULL;
char* tok = strtok(path, ":");
while (tok) {
char* bin_path;
asprintf(&bin_path, "%s/%s", tok, for_binary);
if (!bin_path) {
free(path);
return NULL;
}
struct stat stat_buf;
if (stat(bin_path, &stat_buf) == 0 && access(bin_path, X_OK) == 0) {
free(path);
return bin_path;
}
free(bin_path);
tok = strtok(NULL, ":");
}
free(path);
return NULL;
}
// This is present in glibc ONLY with GNU extensions, this aims to provide a
// musl compatible variant.
//
// Respects errno of exec functions family.
int execvpe(const char* NNULLABLE file, char* NULLABLE const argv[NNULLABLE],
char* NULLABLE const envp[NNULLABLE]) {
char* path = search_path(file);
if (!path) {
errno = ENOENT;
return -1;
}
int ret = execve(path, argv, envp);
free(path);
return ret;
}

View File

@@ -1,62 +0,0 @@
#include "util/utf8.h"
#define UTF8_CONT_MSK 0b11000000
#define UTF8_CONT_VAL 0b10000000
bool utf8_iscont(char byte) {
return (byte & UTF8_CONT_MSK) == UTF8_CONT_VAL;
}
size_t utf8len(const char* str) {
size_t len = 0;
while (*str != '\0') {
if (!utf8_iscont(*(str++))) len++;
}
return len;
}
size_t utf8len_until(const char* str, const char* until) {
size_t len = 0;
while (str < until) {
if (!utf8_iscont(*(str++))) len++;
}
return len;
}
size_t utf8trunc(char* str, size_t n) {
size_t bytes = 0;
while (true) {
if (str[bytes] == '\0') break;
if (utf8_iscont(str[bytes])) {
bytes++;
continue;
}
if (n == 0) {
str[bytes] = '\0';
break;
}
bytes++;
n--;
}
return bytes;
}
const char* utf8back(const char* str) {
while (utf8_iscont(*(--str))) {
}
return str;
}
const char* utf8seek(const char* str) {
while (utf8_iscont(*(++str))) {
}
return str;
}
const char* utf8seekn(const char* str, size_t n) {
while (n > 0 && *str != '\0') {
str = utf8seek(str);
n--;
}
return str;
}

View File

@@ -1,96 +0,0 @@
#include <stdlib.h>
#include "util/vec.h"
const struct Vector VEC_NEW = {
.length = 0,
.capacity = 0,
.pages = NULL,
};
struct Vector vec_from_raw(void** raw) {
size_t len = 0;
while (raw[len])
len++;
return (struct Vector){
.length = len,
.capacity = len,
.pages = raw,
};
}
void** vec_as_raw(struct Vector self) {
if (vec_push(&self, NULL) != 0) return NULL;
return self.pages;
}
int vec_resize(struct Vector* self, size_t size) {
void** new_location =
(void**)realloc((void*)self->pages, size * sizeof(void*));
if (new_location != NULL) {
if (self->length > size) self->length = size;
self->capacity = size;
self->pages = new_location;
} else {
return -1;
}
return 0;
}
int vec_reserve(struct Vector* self, size_t size) {
uint32_t new_capacity = self->capacity;
while (self->length + size > new_capacity) {
new_capacity = new_capacity + (new_capacity >> 1) +
1; // cap * 1.5 + 1; 0 1 2 4 7 11...
}
return vec_resize(self, new_capacity);
}
int vec_reserve_exact(struct Vector* self, size_t size) {
uint32_t needed_capacity = self->length + size;
if (self->capacity < needed_capacity) {
return vec_resize(self, needed_capacity);
}
return 0;
}
int vec_push(struct Vector* self, void* item) {
int res_ret = vec_reserve(self, 1);
if (res_ret != 0) return res_ret;
self->pages[self->length++] = item;
return 0;
}
void vec_free(struct Vector* self) {
while (self->length > 0)
free(self->pages[--self->length]);
vec_clear(self);
}
void vec_clear(struct Vector* self) {
free((void*)self->pages);
vec_reset(self);
}
void vec_reset(struct Vector* self) {
*self = (struct Vector){
.length = 0,
.capacity = 0,
.pages = NULL,
};
}
void* vec_pop(struct Vector* self) {
if (self->length == 0) return NULL;
return self->pages[--self->length];
}
void* vec_get(struct Vector* self, size_t index) {
if (index >= self->length) return NULL;
return self->pages[index];
}

1
themes

Submodule themes deleted from 44681317ef

45
themes/README.md Normal file
View File

@@ -0,0 +1,45 @@
# Themes
## cherry.ini
![cherry.ini theme](./screenshots/cherry.png)
## default.ini
![default.ini theme](./screenshots/default.png)
## kanagawa-dragon.ini
![kanagawa-dragon.ini theme](./screenshots/kanagawa-dragon.png)
## kanagawa-wave.ini
![kanagawa-wave.ini theme](./screenshots/kanagawa-wave.png)
## minimal.ini
![minimal.ini theme](./screenshots/minimal.png)
> [!WARNING]
> This theme **heavily** relies on terminal rendering. It's just to show
> customizability, a TTY won't render this properly
## nature.ini
![nature.ini theme](./screenshots/nature.png)
## nord.ini
![nord.ini theme](./screenshots/nord.png)
## old-blue.ini
![old-blue.ini theme](./screenshots/old-blue.png)
## nothing.ini
![nothing.ini theme](./screenshots/nothing.png)
## tasteless.ini
![tasteless.ini theme](./screenshots/tasteless.png)

49
themes/cherry.ini Normal file
View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;77;33;55"
fg = "22;3;24;38;2;245;245;245"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
s_shell = "32"
e_hostname = "1;23;38;5;197"
e_date = "31"
e_box = "31"
e_header = "1;4;38;5;204"
e_user = "38;5;51"
e_passwd = "4;2;38;5;203"
e_badpasswd = "4;31"
e_key = "1;23;38;5;197"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
# timefmt = "%X %x"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

51
themes/default.ini Normal file
View File

@@ -0,0 +1,51 @@
[colors]
# bg = "48;2;38;28;28"
# fg = "22;24;38;2;245;245;245"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
# s_shell = "38;2;34;140;34"
# e_hostname = "38;2;255;64;64"
# e_date = "38;2;144;144;144"
# e_box = "38;2;122;122;122"
# e_header = "4;38;2;0;255;0"
# e_user = "36"
# e_passwd = "4;38;2;245;245;205"
# e_badpasswd = "3;4;31"
# e_key = "38;2;255;174;66"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# fido = NONE
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_fido = "fido"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
# timefmt = "%X %x"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;24;22;22"
fg = "22;24;38;2;185;185;185"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
# s_shell = "38;2;34;140;34"
e_hostname = "38;2;208;189;156"
e_date = "38;2;144;144;144"
# e_box = "38;2;122;122;122"
e_header = "4;38;2;126;146;178"
e_user = "38;2;148;89;84"
# e_passwd = "4;38;2;245;245;205"
# e_badpasswd = "3;4;31"
# e_key = "38;2;255;174;66"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

49
themes/kanagawa-wave.ini Normal file
View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;28;28;36"
fg = "22;24;38;2;168;168;168"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
# s_shell = "38;2;34;140;34"
e_hostname = "38;2;196;165;112"
e_date = "38;2;144;144;144"
# e_box = "38;2;122;122;122"
e_header = "4;38;2;114;133;162"
e_user = "38;2;211;137;88"
# e_passwd = "4;38;2;245;245;205"
# e_badpasswd = "3;4;31"
# e_key = "38;2;255;174;66"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

50
themes/minimal.ini Normal file
View File

@@ -0,0 +1,50 @@
[colors]
# bg = "48;2;38;28;28"
# fg = "22;24;38;2;245;245;245"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
# s_shell = "38;2;34;140;34"
# e_hostname = "38;2;255;64;64"
# e_date = "38;2;144;144;144"
# e_box = "38;2;122;122;122"
e_header = "38;2;0;255;0"
# e_user = "36"
# e_passwd = "4;38;2;245;245;205"
# e_badpasswd = "3;4;31"
# e_key = "38;2;255;174;66"
[chars]
hb = " "
vb = " "
ctl = " "
ctr = " "
cbl = " "
cbr = " "
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
# EXCLUSIVE TO NERD FONTS
[strings]
f_poweroff = "\xef\x80\x91 "
f_reboot = "\xee\xab\x92 "
f_refresh = "\xf3\xb0\x91\x93 "
e_user = "\xee\xb4\xb5"
e_passwd = "\xef\x80\xa3"
s_wayland = "W"
s_xorg = "X"
s_shell = "$"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "\xef\x80\x97 %X \xef\x84\xb3 %x"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

49
themes/nature.ini Normal file
View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;15;22;15"
fg = "22;23;24;38;2;245;245;245"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
s_shell = "32"
e_hostname = "38;5;28"
e_date = "32"
e_box = "32"
e_header = "1;4;32"
e_user = "38;5;51"
e_passwd = "4;2;38;5;83"
e_badpasswd = "3;4;31"
e_key = "32"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

49
themes/nord.ini Normal file
View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;19;19;22"
fg = "22;24;38;2;245;245;245"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
s_shell = "32"
e_hostname = "34"
e_date = "38;2;66;66;88"
# e_box = "38;2;122;122;122"
e_header = "1;4;36"
e_user = "38;5;51"
e_passwd = "4;2;38;5;80"
# e_badpasswd = "3;4;31"
e_key = "34"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
# e_user = "user"
# e_passwd = "password"
# s_wayland = "wayland"
# s_xorg = "xorg"
# s_shell = "shell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

51
themes/nothing.ini Normal file
View File

@@ -0,0 +1,51 @@
[colors]
# the '-' makes '\x1b[-m' which usually does nothing
bg = "-"
# you can even break out of the '\x1b...m' context like do, I wouldn't though
fg = "24;39m\x1b[?25l\x1b[-"
err = "-"
s_wayland = "-"
s_xorg = "-"
s_shell = "-"
e_hostname = "-"
e_date = "30"
e_box = "-"
e_header = "30"
e_user = "-"
e_passwd = "24;30"
e_badpasswd = "-"
e_key = "-"
[chars]
hb = " "
vb = " "
ctl = " "
ctr = " "
cbl = " "
cbr = " "
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
# f_poweroff = "poweroff"
# f_reboot = "reboot"
# f_refresh = "refresh"
e_user = ""
e_passwd = ""
s_wayland = ""
s_xorg = ""
s_shell = ""
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = " "
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

49
themes/old-blue.ini Normal file
View File

@@ -0,0 +1,49 @@
[colors]
bg = "48;2;0;0;255"
fg = "22;24;39;48;2;0;0;255"
# err = "1;31"
# s_wayland = "38;2;255;174;66"
# s_xorg = "38;2;37;175;255"
# s_shell = "38;2;34;140;34"
# e_hostname = "38;2;255;64;64"
e_date = "38;2;144;144;144"
e_box = "34"
e_header = "4;38;2;0;255;0"
e_user = "36"
e_passwd = "4;38;2;245;245;205"
# e_badpasswd = "3;4;31"
e_key = "1;31;48;2;255;174;66"
[chars]
hb = "█"
vb = "█"
ctl = "█"
ctr = "█"
cbl = "█"
cbr = "█"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
f_poweroff = "powewoff"
f_reboot = "rewoot"
f_refresh = "rewresh"
e_user = "wuser"
e_passwd = "passwd"
s_wayland = "waywand"
s_xorg = "xworg"
s_shell = "swell"
# opts_pre = "< "
# opts_post = " >"
# ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
themes/screenshots/nord.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

81
themes/take-screenshots.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
COLS=60
ROWS=35
if [[ -z "$IM_FLOATING" ]]; then
if [[ -z "$LIDM_SESSIONS_N" ]]; then
echo "Please set LIDM_SESSIONS_N" >&2;
exit 1;
fi
# 12 pts ≈ 16 px
exec hyprctl dispatch exec \
"[float; size $((COLS*16)) $((ROWS*16))]" \
"kitty --override font_size=12.0 --override background_opacity=1 --override cursor_trail=0 --override cursor_shape=beam --override cursor_blink_interval=0 bash -c 'cd \"$PWD\" && IM_FLOATING=1 LIDM_PATH=\"$LIDM_PATH\" LIDM_SCR_TTY=\"$(tty)\" LIDM_SESSIONS_N=\"$LIDM_SESSIONS_N\" \"$MYSELF\"'"
fi
LIDM_PATH=${LIDM_PATH:-$(command which lidm)}
echo "Using '$LIDM_PATH'"
[[ -e "$LIDM_PATH" ]] || {
echo "'$LIDM_PATH' is not executable" >&2;
sleep 2;
exit 1;
}
notify-send "also make sure this is not in the way either"
echo "Press enter when the window is clearly visible and nothing in the way"
echo "ONLY use this script if you are on hyprland and a \"normal\" kitty config"
echo "AND make sure you have rg, jq, grim, gifski and maybe a few more"
exec 2>"$LIDM_SCR_TTY"
echo "This should show on the original terminal" > "$LIDM_SCR_TTY"
echo "And this too" >&2
read -r
BG=$(rg '^background ' ~/.config/kitty/kitty.conf | cut -d'#' -f2)
printf '\033]4;0;rgb:%s\007' "${BG:0:2}/${BG:2:2}/${BG:4:2}"
PRAD=$(hyprctl getoption decoration:rounding | rg int | cut -d' ' -f2)
hyprctl keyword decoration:rounding 0
tty=$(tty)
for theme in "$MYDIR"/*.ini; do
LIDM_CONF="$theme" "$LIDM_PATH" <"$tty" &
LIDM_PID=$!
sleep .2
for n in $(seq "$LIDM_SESSIONS_N"); do
GEOMETRY=$(
hyprctl -j activewindow | \
jq -r '(.at[0]|tostring) + "," + (.at[1]|tostring) + " " + (.size[0]|tostring) + "x" + (.size[1]|tostring)'
)
grim -g "$GEOMETRY" - > "$MYDIR/screenshots/$(basename "$theme" | cut -d. -f1)-$n.png"
notify-send "$n taken"
wtype -k right
sleep .5
done
kill -15 $LIDM_PID
sleep .5
done
gifski \
-Q 95 --fps 4 \
-W $((COLS*32)) \
-o "$MYDIR/../assets/media/lidm.gif" \
"$MYDIR"/screenshots/*.png &> "$LIDM_SCR_TTY"
for screenshot in "$MYDIR"/screenshots/*"-1.png"; do
# shellcheck disable=SC2001
mv "$screenshot" "$(sed 's/-[0-9]\.png/.png/' <<<"$screenshot")"
done
rm "$MYDIR"/screenshots/*"-"[0-9].png
printf '\033]104\007'
hyprctl keyword decoration:rounding "$PRAD"

50
themes/tasteless.ini Normal file
View File

@@ -0,0 +1,50 @@
[colors]
# the '-' makes '\x1b[-m' which usually does nothing
bg = "-"
fg = "24"
err = "-"
s_wayland = "-"
s_xorg = "-"
s_shell = "-"
e_hostname = "-"
e_date = "-"
e_box = "-"
e_header = "-"
e_user = "-"
e_passwd = "-"
e_badpasswd = "-"
e_key = "-"
[chars]
# hb = "─"
# vb = "│"
# ctl = "┌"
# ctr = "┐"
# cbl = "└"
# cbr = "┘"
[functions]
# poweroff = F1
# reboot = F2
# refresh = F5
[strings]
f_poweroff = "off"
f_reboot = "reb"
f_refresh = "ref"
e_user = "user"
e_passwd = "pass"
s_wayland = "wayl"
s_xorg = "xorg"
s_shell = "sh"
opts_pre = "· "
opts_post = " "
ellipsis = "…"
[behavior]
# include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env"
source = "/etc/locale.conf"
user_source = ".lidm.env"

18
themes/view.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
MYSELF=$(realpath "$0")
MYDIR=$(dirname "$MYSELF")
LIDM_PATH=${LIDM_PATH:-$(command which lidm)}
echo "Using '$LIDM_PATH'"
[[ -e "$LIDM_PATH" ]] || { echo "'$LIDM_PATH' is not executable" >&2; exit 1; }
echo "Press \`Ctrl + C\` once you are done viewing the theme"
sleep 3
for theme in "$MYDIR/"*.ini; do
LIDM_CONF="$theme" "$LIDM_PATH" || :
echo "That was '$(basename "$theme")'"
sleep 2 || :
done