summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorauric <104602845+ihateamongus@users.noreply.github.com>2025-09-08 21:02:18 -0500
committerauric <104602845+ihateamongus@users.noreply.github.com>2025-09-08 21:02:18 -0500
commit9e10c2714cd159ce953155225cbe2ecc6810bd7f (patch)
tree39cf7b7d40d3e9808e436cfa208bccd9a8c43208
parentd11aec86841f77edd6eba3e07aa1e7e591e9da2a (diff)
Add minimal X11 login manager and cleanup
-rw-r--r--.gitignore13
-rw-r--r--Makefile11
-rwxr-xr-xdmenu/dmenubin42736 -> 0 bytes
-rw-r--r--dmenu/dmenu.obin33792 -> 0 bytes
-rwxr-xr-xdmenu/dmenu_path13
-rwxr-xr-xdmenu/dmenu_run2
-rw-r--r--dmenu/drw.obin11464 -> 0 bytes
-rwxr-xr-xdmenu/stestbin16288 -> 0 bytes
-rw-r--r--dmenu/stest.obin5344 -> 0 bytes
-rw-r--r--dmenu/util.obin2472 -> 0 bytes
-rw-r--r--dwm/drw.obin11464 -> 0 bytes
-rwxr-xr-xdwm/dwmbin76624 -> 0 bytes
-rw-r--r--dwm/dwm.obin67680 -> 0 bytes
-rw-r--r--dwm/util.obin2472 -> 0 bytes
-rw-r--r--slogin/Makefile16
-rw-r--r--slogin/slogin.c166
-rw-r--r--tools/Makefile14
-rw-r--r--tools/colorstagger.c97
-rwxr-xr-xtools/exofetchbin28736 -> 0 bytes
19 files changed, 312 insertions, 20 deletions
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
--- a/dmenu/dmenu
+++ /dev/null
Binary files differ
diff --git a/dmenu/dmenu.o b/dmenu/dmenu.o
deleted file mode 100644
index e0d9407..0000000
--- a/dmenu/dmenu.o
+++ /dev/null
Binary files 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
--- a/dmenu/drw.o
+++ /dev/null
Binary files differ
diff --git a/dmenu/stest b/dmenu/stest
deleted file mode 100755
index 7ba4cf1..0000000
--- a/dmenu/stest
+++ /dev/null
Binary files differ
diff --git a/dmenu/stest.o b/dmenu/stest.o
deleted file mode 100644
index 3d5045e..0000000
--- a/dmenu/stest.o
+++ /dev/null
Binary files differ
diff --git a/dmenu/util.o b/dmenu/util.o
deleted file mode 100644
index 5dd48bf..0000000
--- a/dmenu/util.o
+++ /dev/null
Binary files differ
diff --git a/dwm/drw.o b/dwm/drw.o
deleted file mode 100644
index 69dbfa9..0000000
--- a/dwm/drw.o
+++ /dev/null
Binary files differ
diff --git a/dwm/dwm b/dwm/dwm
deleted file mode 100755
index 750cdc5..0000000
--- a/dwm/dwm
+++ /dev/null
Binary files differ
diff --git a/dwm/dwm.o b/dwm/dwm.o
deleted file mode 100644
index efa1a13..0000000
--- a/dwm/dwm.o
+++ /dev/null
Binary files differ
diff --git a/dwm/util.o b/dwm/util.o
deleted file mode 100644
index 5dd48bf..0000000
--- a/dwm/util.o
+++ /dev/null
Binary files 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 <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#if HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <crypt.h>
+#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 <X11/Xlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+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
--- a/tools/exofetch
+++ /dev/null
Binary files differ