From 9e10c2714cd159ce953155225cbe2ecc6810bd7f Mon Sep 17 00:00:00 2001 From: auric <104602845+ihateamongus@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:02:18 -0500 Subject: Add minimal X11 login manager and cleanup --- .gitignore | 13 ++++ Makefile | 11 ++++ dmenu/dmenu | Bin 42736 -> 0 bytes dmenu/dmenu.o | Bin 33792 -> 0 bytes dmenu/dmenu_path | 13 ---- dmenu/dmenu_run | 2 - dmenu/drw.o | Bin 11464 -> 0 bytes dmenu/stest | Bin 16288 -> 0 bytes dmenu/stest.o | Bin 5344 -> 0 bytes dmenu/util.o | Bin 2472 -> 0 bytes dwm/drw.o | Bin 11464 -> 0 bytes dwm/dwm | Bin 76624 -> 0 bytes dwm/dwm.o | Bin 67680 -> 0 bytes dwm/util.o | Bin 2472 -> 0 bytes slogin/Makefile | 16 +++++ slogin/slogin.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/Makefile | 14 +++-- tools/colorstagger.c | 97 ++++++++++++++++++++++++++++++ tools/exofetch | Bin 28736 -> 0 bytes 19 files changed, 312 insertions(+), 20 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile delete mode 100755 dmenu/dmenu delete mode 100644 dmenu/dmenu.o delete mode 100755 dmenu/dmenu_path delete mode 100755 dmenu/dmenu_run delete mode 100644 dmenu/drw.o delete mode 100755 dmenu/stest delete mode 100644 dmenu/stest.o delete mode 100644 dmenu/util.o delete mode 100644 dwm/drw.o delete mode 100755 dwm/dwm delete mode 100644 dwm/dwm.o delete mode 100644 dwm/util.o create mode 100644 slogin/Makefile create mode 100644 slogin/slogin.c create mode 100644 tools/colorstagger.c delete mode 100755 tools/exofetch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f574378 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# build artifacts +*.o +# binaries +/dmenu/dmenu +/dmenu/dmenu_path +/dmenu/dmenu_run +/dmenu/stest +/dwm/dwm +/slock/slock +/st/st +/tools/exofetch +/tools/colorstagger +/slogin/slogin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..18bfc1b --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +SUBDIRS = dmenu dwm slock st tools slogin + +.PHONY: all $(SUBDIRS) clean + +all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +clean: + for d in $(SUBDIRS); do $(MAKE) -C $$d clean; done diff --git a/dmenu/dmenu b/dmenu/dmenu deleted file mode 100755 index e796824..0000000 Binary files a/dmenu/dmenu and /dev/null differ diff --git a/dmenu/dmenu.o b/dmenu/dmenu.o deleted file mode 100644 index e0d9407..0000000 Binary files a/dmenu/dmenu.o and /dev/null differ diff --git a/dmenu/dmenu_path b/dmenu/dmenu_path deleted file mode 100755 index 3a7cda7..0000000 --- a/dmenu/dmenu_path +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}" -cache="$cachedir/dmenu_run" - -[ ! -e "$cachedir" ] && mkdir -p "$cachedir" - -IFS=: -if stest -dqr -n "$cache" $PATH; then - stest -flx $PATH | sort -u | tee "$cache" -else - cat "$cache" -fi diff --git a/dmenu/dmenu_run b/dmenu/dmenu_run deleted file mode 100755 index 834ede5..0000000 --- a/dmenu/dmenu_run +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & diff --git a/dmenu/drw.o b/dmenu/drw.o deleted file mode 100644 index 69dbfa9..0000000 Binary files a/dmenu/drw.o and /dev/null differ diff --git a/dmenu/stest b/dmenu/stest deleted file mode 100755 index 7ba4cf1..0000000 Binary files a/dmenu/stest and /dev/null differ diff --git a/dmenu/stest.o b/dmenu/stest.o deleted file mode 100644 index 3d5045e..0000000 Binary files a/dmenu/stest.o and /dev/null differ diff --git a/dmenu/util.o b/dmenu/util.o deleted file mode 100644 index 5dd48bf..0000000 Binary files a/dmenu/util.o and /dev/null differ diff --git a/dwm/drw.o b/dwm/drw.o deleted file mode 100644 index 69dbfa9..0000000 Binary files a/dwm/drw.o and /dev/null differ diff --git a/dwm/dwm b/dwm/dwm deleted file mode 100755 index 750cdc5..0000000 Binary files a/dwm/dwm and /dev/null differ diff --git a/dwm/dwm.o b/dwm/dwm.o deleted file mode 100644 index efa1a13..0000000 Binary files a/dwm/dwm.o and /dev/null differ diff --git a/dwm/util.o b/dwm/util.o deleted file mode 100644 index 5dd48bf..0000000 Binary files a/dwm/util.o and /dev/null differ diff --git a/slogin/Makefile b/slogin/Makefile new file mode 100644 index 0000000..4d8c919 --- /dev/null +++ b/slogin/Makefile @@ -0,0 +1,16 @@ +CC = cc +CFLAGS = -std=c99 -Wall -Wextra -pedantic -Os +LDFLAGS = -lX11 -lcrypt +PREFIX ?= /usr/local + +all: slogin + +slogin: slogin.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + rm -f slogin + +install: slogin + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f slogin $(DESTDIR)$(PREFIX)/bin diff --git a/slogin/slogin.c b/slogin/slogin.c new file mode 100644 index 0000000..856585b --- /dev/null +++ b/slogin/slogin.c @@ -0,0 +1,166 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#if HAVE_SHADOW_H +#include +#endif +#include +#include +#include +#include +#include +#include "../accent.h" + +#define WIDTH 400 +#define HEIGHT 100 + +static int +auth(const char *user, const char *pass) +{ + struct passwd *pw = getpwnam(user); + const char *hash; + if (!pw) + return 0; +#if HAVE_SHADOW_H + struct spwd *sp = getspnam(user); + hash = sp ? sp->sp_pwdp : pw->pw_passwd; +#else + hash = pw->pw_passwd; +#endif + if (!hash || hash[0] == '!' || hash[0] == '*') + return 0; + return strcmp(crypt(pass, hash), hash) == 0; +} + +static void +draw(Display *dpy, Window win, GC gc, const char *prompt, + const char *input, int hidden) +{ + XClearWindow(dpy, win); + XDrawString(dpy, win, gc, 10, 25, prompt, strlen(prompt)); + if (input && *input) { + char buf[128]; + const char *show = input; + if (hidden) { + size_t n = strlen(input); + if (n >= sizeof buf) + n = sizeof buf - 1; + memset(buf, '*', n); + buf[n] = '\0'; + show = buf; + } + XDrawString(dpy, win, gc, 10, 50, show, strlen(show)); + } + XFlush(dpy); +} + +int +main(void) +{ + Display *dpy; + Window win; + XEvent ev; + GC gc; + XFontStruct *font; + int screen; + Colormap cmap; + XColor xcol; + ColorShm *blk = NULL; + char accent[8] = "#005577"; + + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "slogin: cannot open display\n"); + return 1; + } + readaccent(&blk, accent); + screen = DefaultScreen(dpy); + cmap = DefaultColormap(dpy, screen); + XParseColor(dpy, cmap, accent, &xcol); + XAllocColor(dpy, cmap, &xcol); + win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), + DisplayWidth(dpy, screen)/2 - WIDTH/2, + DisplayHeight(dpy, screen)/2 - HEIGHT/2, + WIDTH, HEIGHT, 2, xcol.pixel, BlackPixel(dpy, screen)); + XStoreName(dpy, win, "slogin"); + XSelectInput(dpy, win, ExposureMask | KeyPressMask); + XMapRaised(dpy, win); + gc = XCreateGC(dpy, win, 0, NULL); + XSetForeground(dpy, gc, xcol.pixel); + font = XLoadQueryFont(dpy, "fixed"); + if (font) + XSetFont(dpy, gc, font->fid); + + char user[64] = ""; + char pass[64] = ""; + int stage = 0; + draw(dpy, win, gc, "user:", user, 0); + + for (;;) { + if (XPending(dpy)) { + XNextEvent(dpy, &ev); + if (ev.type == Expose) { + draw(dpy, win, gc, stage ? "pass:" : "user:", + stage ? pass : user, stage); + } else if (ev.type == KeyPress) { + char buf[32]; + KeySym ksym; + int len = XLookupString(&ev.xkey, buf, sizeof buf, &ksym, NULL); + if (ksym == XK_Return) { + if (stage == 0) { + stage = 1; + draw(dpy, win, gc, "pass:", pass, 1); + } else { + if (auth(user, pass)) { + struct passwd *pw = getpwnam(user); + if (!pw) + exit(1); + chdir(pw->pw_dir); + setenv("HOME", pw->pw_dir, 1); + setenv("SHELL", pw->pw_shell, 1); + setenv("USER", pw->pw_name, 1); + setenv("LOGNAME", pw->pw_name, 1); + initgroups(pw->pw_name, pw->pw_gid); + setgid(pw->pw_gid); + setuid(pw->pw_uid); + execlp(pw->pw_shell, pw->pw_shell, "-l", NULL); + perror("execlp"); + exit(1); + } else { + user[0] = pass[0] = '\0'; + stage = 0; + draw(dpy, win, gc, "user:", user, 0); + } + } + } else if (ksym == XK_BackSpace) { + if (stage == 0) { + size_t n = strlen(user); + if (n) user[n-1] = '\0'; + draw(dpy, win, gc, "user:", user, 0); + } else { + size_t n = strlen(pass); + if (n) pass[n-1] = '\0'; + draw(dpy, win, gc, "pass:", pass, 1); + } + } else if (len && !iscntrl((unsigned char)buf[0])) { + if (stage == 0 && strlen(user) + len < sizeof user - 1) { + strncat(user, buf, len); + draw(dpy, win, gc, "user:", user, 0); + } else if (stage == 1 && strlen(pass) + len < sizeof pass - 1) { + strncat(pass, buf, len); + draw(dpy, win, gc, "pass:", pass, 1); + } + } + } + } + if (readaccent(&blk, accent)) { + XParseColor(dpy, cmap, accent, &xcol); + XAllocColor(dpy, cmap, &xcol); + XSetForeground(dpy, gc, xcol.pixel); + XSetWindowBorder(dpy, win, xcol.pixel); + } + usleep(20000); + } +} diff --git a/tools/Makefile b/tools/Makefile index ae33902..e42f8bf 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,16 +1,20 @@ +.RECIPEPREFIX = > CC = cc CFLAGS = -std=c99 -Wall -Wextra -pedantic -Os LDFLAGS = PREFIX ?= /usr/local -all: exofetch +all: exofetch colorstagger exofetch: exofetch.c - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) +>$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +colorstagger: colorstagger.c +>$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -lX11 clean: - rm -f exofetch +>rm -f exofetch colorstagger install: exofetch - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp -f exofetch $(DESTDIR)$(PREFIX)/bin +>mkdir -p $(DESTDIR)$(PREFIX)/bin +>cp -f exofetch $(DESTDIR)$(PREFIX)/bin diff --git a/tools/colorstagger.c b/tools/colorstagger.c new file mode 100644 index 0000000..3e68faf --- /dev/null +++ b/tools/colorstagger.c @@ -0,0 +1,97 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include + +typedef struct { unsigned char r, g, b; } Color; + +static Color +parse(const char *hex) +{ + Color c = {0}; + if (hex[0] == '#') + hex++; + if (strlen(hex) >= 6) { + char buf[3] = {0}; + buf[0] = hex[0]; buf[1] = hex[1]; c.r = strtol(buf, NULL, 16); + buf[0] = hex[2]; buf[1] = hex[3]; c.g = strtol(buf, NULL, 16); + buf[0] = hex[4]; buf[1] = hex[5]; c.b = strtol(buf, NULL, 16); + } + return c; +} + +static unsigned long +pack(Color c) +{ + return ((unsigned long)c.r << 16) | + ((unsigned long)c.g << 8) | + ((unsigned long)c.b); +} + +static Color +mix(Color a, Color b, double t) +{ + Color c; + c.r = a.r + (b.r - a.r) * t; + c.g = a.g + (b.g - a.g) * t; + c.b = a.b + (b.b - a.b) * t; + return c; +} + +int +main(void) +{ + char *colors[] = {"#ff5555", "#f1fa8c", "#50fa7b", "#8be9fd", "#bd93f9"}; + const int ncolors = sizeof(colors) / sizeof(colors[0]); + + Display *d = XOpenDisplay(NULL); + if (!d) { + fprintf(stderr, "cannot open display\n"); + return 1; + } + int s = DefaultScreen(d); + int width = 600, height = 100; + Window w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, width, height, + 1, BlackPixel(d, s), WhitePixel(d, s)); + XSelectInput(d, w, KeyPressMask); + XMapWindow(d, w); + GC gc = XCreateGC(d, w, 0, NULL); + + int grad = 60, solid = 60; + int running = 1; + while (running) { + while (XPending(d)) { + XEvent e; + XNextEvent(d, &e); + if (e.type == KeyPress) + running = 0; + } + + int x = 0; + for (int i = 0; i < ncolors; i++) { + Color a = parse(colors[i]); + Color b = parse(colors[(i + 1) % ncolors]); + for (int k = 0; k < grad; k++) { + double t = k / (double)(grad - 1); + Color c = mix(a, b, t); + XSetForeground(d, gc, pack(c)); + XDrawLine(d, w, gc, x + k, 0, x + k, height); + } + x += grad; + XSetForeground(d, gc, pack(b)); + XFillRectangle(d, w, gc, x, 0, solid, height); + x += solid; + } + XFlush(d); + usleep(500000); + char *tmp = colors[0]; + memmove(colors, colors + 1, (ncolors - 1) * sizeof(char *)); + colors[ncolors - 1] = tmp; + XClearWindow(d, w); + } + + XCloseDisplay(d); + return 0; +} diff --git a/tools/exofetch b/tools/exofetch deleted file mode 100755 index 425ffa4..0000000 Binary files a/tools/exofetch and /dev/null differ -- cgit v1.2.3