diff options
| author | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-07 19:23:44 -0500 |
|---|---|---|
| committer | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-07 19:23:44 -0500 |
| commit | ac363b0b326afc73b7e01d0bed8848ed336e0a39 (patch) | |
| tree | a67d3835a257f16000581271f243c23632c1c6e0 | |
| parent | b59b8b8e5d16af7f0daccb280a4991e3fe428e41 (diff) | |
refactor: share accent color shm header
| -rw-r--r-- | accent.h | 52 | ||||
| -rw-r--r-- | dmenu/config.def.h | 8 | ||||
| -rw-r--r-- | dmenu/dmenu.c | 129 | ||||
| -rw-r--r-- | dwm/config.def.h | 48 | ||||
| -rw-r--r-- | dwm/dwm.c | 179 | ||||
| -rw-r--r-- | tools/Makefile | 16 | ||||
| -rw-r--r-- | tools/exofetch.c | 181 |
7 files changed, 522 insertions, 91 deletions
diff --git a/accent.h b/accent.h new file mode 100644 index 0000000..8c9c6d4 --- /dev/null +++ b/accent.h @@ -0,0 +1,52 @@ +#ifndef ACCENT_H +#define ACCENT_H +#include <stdint.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define SHMNAME "/breathing_color_shm" +#define SHM_MAGIC 0xBEEFCAFEu +#define SHM_VERSION 1u + +typedef struct { + uint32_t magic; + uint32_t version; + volatile uint32_t seq; + char color[8]; +} ColorShm; + +static inline ColorShm * +mapaccent(void) +{ + int fd; + ColorShm *blk; + if ((fd = shm_open(SHMNAME, O_RDONLY, 0)) < 0) + return NULL; + blk = mmap(NULL, sizeof(ColorShm), PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (blk == MAP_FAILED) + return NULL; + if (blk->magic != SHM_MAGIC || blk->version != SHM_VERSION) { + munmap(blk, sizeof(ColorShm)); + return NULL; + } + return blk; +} + +static inline int +readaccent(ColorShm **blk, char out[8]) +{ + uint32_t s1, s2; + if (!*blk && !(*blk = mapaccent())) + return 0; + do { + s1 = (*blk)->seq; + memcpy(out, (*blk)->color, 8); + s2 = (*blk)->seq; + } while (s1 != s2); + return out[0] == '#'; +} + +#endif /* ACCENT_H */ diff --git a/dmenu/config.def.h b/dmenu/config.def.h index 1edb647..bc17068 100644 --- a/dmenu/config.def.h +++ b/dmenu/config.def.h @@ -8,10 +8,10 @@ static const char *fonts[] = { }; static const char *prompt = NULL; /* -p option; prompt to the left of input field */ static const char *colors[SchemeLast][2] = { - /* fg bg */ - [SchemeNorm] = { "#bbbbbb", "#222222" }, - [SchemeSel] = { "#eeeeee", "#005577" }, - [SchemeOut] = { "#000000", "#00ffff" }, + /* fg bg */ + [SchemeNorm] = { "#dddddd", "#000000" }, + [SchemeSel] = { "#ffffff", "#66ccff" }, + [SchemeOut] = { "#000000", "#66ccff" }, }; /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ static unsigned int lines = 0; diff --git a/dmenu/dmenu.c b/dmenu/dmenu.c index fd49549..54a14e2 100644 --- a/dmenu/dmenu.c +++ b/dmenu/dmenu.c @@ -7,6 +7,11 @@ #include <strings.h> #include <time.h> #include <unistd.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/select.h> #include <X11/Xlib.h> #include <X11/Xatom.h> @@ -52,6 +57,15 @@ static XIC xic; static Drw *drw; static Clr *scheme[SchemeLast]; +#include "../accent.h" +static ColorShm *accentshm; +static char accentcol[8] = "#005577"; +static const double opacity = 0.85; + +static void initaccent(void); +static void updateaccent(void); +static void setopacity(Window w, double opacity); + #include "config.h" static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -111,6 +125,18 @@ cleanup(void) XCloseDisplay(dpy); } +static void +updateaccent(void) +{ + if (readaccent(&accentshm, accentcol)) + drw_clr_create(drw, &scheme[SchemeSel][ColBg], accentcol); +} + +static void +initaccent(void) +{ + updateaccent(); +} static char * cistrstr(const char *h, const char *n) { @@ -192,6 +218,15 @@ drawmenu(void) } static void +setopacity(Window w, double op) +{ + unsigned long val = op * 0xffffffff; + XChangeProperty(dpy, w, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False), + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&val, 1); +} + +static void grabfocus(void) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; @@ -575,39 +610,53 @@ readstdin(void) static void run(void) { - XEvent ev; - - while (!XNextEvent(dpy, &ev)) { - if (XFilterEvent(&ev, win)) - continue; - switch(ev.type) { - case DestroyNotify: - if (ev.xdestroywindow.window != win) - break; - cleanup(); - exit(1); - case Expose: - if (ev.xexpose.count == 0) - drw_map(drw, win, 0, 0, mw, mh); - break; - case FocusIn: - /* regrab focus from parent window */ - if (ev.xfocus.window != win) - grabfocus(); - break; - case KeyPress: - keypress(&ev.xkey); - break; - case SelectionNotify: - if (ev.xselection.property == utf8) - paste(); - break; - case VisibilityNotify: - if (ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dpy, win); - break; - } - } + XEvent ev; + int xfd; + fd_set fds; + struct timeval tv; + + xfd = ConnectionNumber(dpy); + for (;;) { + FD_ZERO(&fds); + FD_SET(xfd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 50000; + if (select(xfd + 1, &fds, NULL, NULL, &tv) > 0) { + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + if (XFilterEvent(&ev, win)) + continue; + switch (ev.type) { + case DestroyNotify: + if (ev.xdestroywindow.window != win) + break; + cleanup(); + exit(1); + case Expose: + if (ev.xexpose.count == 0) + drw_map(drw, win, 0, 0, mw, mh); + break; + case FocusIn: + if (ev.xfocus.window != win) + grabfocus(); + break; + case KeyPress: + keypress(&ev.xkey); + break; + case SelectionNotify: + if (ev.xselection.property == utf8) + paste(); + break; + case VisibilityNotify: + if (ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; + } + } + } + updateaccent(); + drawmenu(); + } } static void @@ -696,10 +745,11 @@ setup(void) xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, XNFocusWindow, win, NULL); - XMapRaised(dpy, win); - if (embed) { - XReparentWindow(dpy, win, parentwin, x, y); - XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); + XMapRaised(dpy, win); + setopacity(win, opacity); + if (embed) { + XReparentWindow(dpy, win, parentwin, x, y); + XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { for (i = 0; i < du && dws[i] != win; ++i) XSelectInput(dpy, dws[i], FocusChangeMask); @@ -707,8 +757,9 @@ setup(void) } grabfocus(); } - drw_resize(drw, mw, mh); - drawmenu(); + drw_resize(drw, mw, mh); + initaccent(); + drawmenu(); } static void diff --git a/dwm/config.def.h b/dwm/config.def.h index 81c3fc0..c94f430 100644 --- a/dwm/config.def.h +++ b/dwm/config.def.h @@ -1,17 +1,21 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ -static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int borderpx = 3; /* border pixel of windows */ +static const unsigned int gappx = 3; /* gaps between windows */ static const unsigned int snap = 32; /* snap pixel */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10"; -static const char col_gray1[] = "#222222"; -static const char col_gray2[] = "#444444"; -static const char col_gray3[] = "#bbbbbb"; -static const char col_gray4[] = "#eeeeee"; -static const char col_cyan[] = "#005577"; +static const char col_gray1[] = "#000000"; +static const char col_gray2[] = "#555555"; +static const char col_gray3[] = "#dddddd"; +static const char col_gray4[] = "#ffffff"; +static const char col_cyan[] = "#66ccff"; +#ifndef BAROPACITY +#define BAROPACITY 0.85 +#endif static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, @@ -26,9 +30,9 @@ static const Rule rules[] = { * WM_CLASS(STRING) = instance, class * WM_NAME(STRING) = title */ - /* class instance title tags mask isfloating monitor */ - { "Gimp", NULL, NULL, 0, 1, -1 }, - { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + /* class instance title tags mask isfloating monitor */ + { NULL, NULL, "Picture in picture", 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, }; /* layout(s) */ @@ -46,7 +50,7 @@ static const Layout layouts[] = { }; /* key definitions */ -#define MODKEY Mod1Mask +#define MODKEY Mod4Mask #define TAGKEYS(KEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ @@ -60,12 +64,22 @@ static const Layout layouts[] = { static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; static const char *termcmd[] = { "st", NULL }; +static const char scratchpadname[] = "scratchpad"; +static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; +static const char *browsercmd[] = { "/bin/sh", "-c", "$BROWSER", NULL }; +static const char *screenshotcmd[] = { "flameshot", "gui", NULL }; +static const char *mediaplaypause[] = { "playerctl", "play-pause", NULL }; +static const char *medianext[] = { "playerctl", "next", NULL }; +static const char *mediaprev[] = { "playerctl", "previous", NULL }; static const Key keys[] = { /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, - { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_F1, spawn, {.v = browsercmd } }, + { 0, XK_Print, spawn, {.v = screenshotcmd } }, + { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, @@ -86,7 +100,13 @@ static const Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, - TAGKEYS( XK_1, 0) + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY, XK_KP_End, spawn, {.v = mediaprev } }, + { MODKEY, XK_KP_Down, spawn, {.v = mediaplaypause } }, + { MODKEY, XK_KP_Page_Down, spawn, {.v = medianext } }, + TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) TAGKEYS( XK_4, 3) @@ -30,6 +30,11 @@ #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/select.h> #include <X11/cursorfont.h> #include <X11/keysym.h> #include <X11/Xatom.h> @@ -118,6 +123,7 @@ struct Monitor { int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; @@ -199,9 +205,13 @@ static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); +static void setopacity(Window w, double opacity); static void setup(void); +static void initaccent(void); +static void updateaccent(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); static void spawn(const Arg *arg); @@ -210,6 +220,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); +static void togglescratch(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -270,6 +281,19 @@ static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" +#ifndef BAROPACITY +#define BAROPACITY 1.0 +#endif + +/* tag used for scratchpad clients */ +static const unsigned int scratchtag = 1 << LENGTH(tags); + +#include "../accent.h" + +/* state for the shared accent color */ +static ColorShm *accentshm; +static char accentcol[8] = "#005577"; + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -640,12 +664,29 @@ createmon(void) m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; + m->gappx = gappx; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); return m; } +static void +updateaccent(void) { + if (readaccent(&accentshm, accentcol)) { + drw_clr_create(drw, &scheme[SchemeSel][ColBg], accentcol); + drw_clr_create(drw, &scheme[SchemeSel][ColBorder], accentcol); + for (Monitor *m = mons; m; m = m->next) + if (m->sel) + XSetWindowBorder(dpy, m->sel->win, scheme[SchemeSel][ColBorder].pixel); + } +} + +static void +initaccent(void) { + updateaccent(); +} + void destroynotify(XEvent *e) { @@ -697,7 +738,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; + int x, w, tw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -719,16 +760,18 @@ drawbar(Monitor *m) urg |= c->tags; } x = 0; - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - if (occ & 1 << i) - drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); - x += w; - } + for (i = 0; i < LENGTH(tags); i++) { + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } w = TEXTW(m->ltsymbol); drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); @@ -750,10 +793,11 @@ drawbar(Monitor *m) void drawbars(void) { - Monitor *m; + Monitor *m; - for (m = mons; m; m = m->next) - drawbar(m); + updateaccent(); + for (m = mons; m; m = m->next) + drawbar(m); } void @@ -1060,6 +1104,14 @@ manage(Window w, XWindowAttributes *wa) c->y = MAX(c->y, c->mon->wy); c->bw = borderpx; + selmon->tagset[selmon->seltags] &= ~scratchtag; + if (!strcmp(c->name, scratchpadname)) { + c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag; + c->isfloating = True; + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); @@ -1381,12 +1433,27 @@ restack(Monitor *m) void run(void) { - XEvent ev; - /* main event loop */ - XSync(dpy, False); - while (running && !XNextEvent(dpy, &ev)) - if (handler[ev.type]) - handler[ev.type](&ev); /* call handler */ + XEvent ev; + int xfd; + fd_set fds; + struct timeval tv; + + XSync(dpy, False); + xfd = ConnectionNumber(dpy); + while (running) { + FD_ZERO(&fds); + FD_SET(xfd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 50000; + if (select(xfd + 1, &fds, NULL, NULL, &tv) > 0) { + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ + } + } + drawbars(); + } } void @@ -1507,6 +1574,16 @@ setfullscreen(Client *c, int fullscreen) } void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) @@ -1535,6 +1612,15 @@ setmfact(const Arg *arg) arrange(selmon); } +static void +setopacity(Window w, double opacity) +{ + unsigned long val = opacity * 0xffffffff; + XChangeProperty(dpy, w, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False), + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&val, 1); +} + void setup(void) { @@ -1586,6 +1672,7 @@ setup(void) scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) scheme[i] = drw_scm_create(drw, colors[i], 3); + initaccent(); /* init bars */ updatebars(); updatestatus(); @@ -1650,6 +1737,7 @@ spawn(const Arg *arg) if (arg->v == dmenucmd) dmenumon[0] = '0' + selmon->num; + selmon->tagset[selmon->seltags] &= ~scratchtag; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); @@ -1696,18 +1784,18 @@ tile(Monitor *m) if (n > m->nmaster) mw = m->nmaster ? m->ww * m->mfact : 0; else - mw = m->ww; - for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) - if (i < m->nmaster) { - h = (m->wh - my) / (MIN(n, m->nmaster) - i); - resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - if (my + HEIGHT(c) < m->wh) - my += HEIGHT(c); + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + if (my + HEIGHT(c) + m->gappx < m->wh) + my += HEIGHT(c) + m->gappx; } else { - h = (m->wh - ty) / (n - i); - resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); - if (ty + HEIGHT(c) < m->wh) - ty += HEIGHT(c); + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + if (ty + HEIGHT(c) + m->gappx < m->wh) + ty += HEIGHT(c) + m->gappx; } } @@ -1735,6 +1823,28 @@ togglefloating(const Arg *arg) } void +togglescratch(const Arg *arg) +{ + Client *c; + unsigned int found = 0; + + for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); + if (found) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(c)) { + focus(c); + restack(selmon); + } + } else + spawn(arg); +} + +void toggletag(const Arg *arg) { unsigned int newtags; @@ -1831,9 +1941,10 @@ updatebars(void) CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); - } + XMapRaised(dpy, m->barwin); + setopacity(m->barwin, BAROPACITY); + XSetClassHint(dpy, m->barwin, &ch); + } } void diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..ae33902 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,16 @@ +CC = cc +CFLAGS = -std=c99 -Wall -Wextra -pedantic -Os +LDFLAGS = +PREFIX ?= /usr/local + +all: exofetch + +exofetch: exofetch.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + rm -f exofetch + +install: exofetch + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f exofetch $(DESTDIR)$(PREFIX)/bin diff --git a/tools/exofetch.c b/tools/exofetch.c new file mode 100644 index 0000000..8111274 --- /dev/null +++ b/tools/exofetch.c @@ -0,0 +1,181 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <sys/utsname.h> +#include <sys/sysinfo.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <locale.h> + +#include "../accent.h" + +static ColorShm *accentshm; +static char accentcol[8] = "#005577"; + +static void +updateaccent(void) +{ + if (!readaccent(&accentshm, accentcol)) + memcpy(accentcol, "#005577", 8); +} + +static void +hex2rgb(const char *hex, int *r, int *g, int *b) +{ + unsigned int ri, gi, bi; + if (sscanf(hex + 1, "%02x%02x%02x", &ri, &gi, &bi) != 3) { + *r = 0x00; *g = 0x55; *b = 0x77; + return; + } + *r = ri; *g = gi; *b = bi; +} + +static const char *icon[] = { +" ██████████████ ██████████████ ", +" ██████████████ ██████████████ ", +" ██████▓▓▓█████ █████▓▓▓██████ ", +" █████▓▓▓▓█████ █████▓▓▓▓█████ ", +" █████▓▓▓▓█████ █████▓▓▓▓█████ ", +" █████▓▓▓▓▓████ ████▓▓▓▓▓█████ ", +" █████▓▓▓▓▓████████ █████████████████████ ████████▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓█████ █████████████████████ █████▓▓▓▓▓▓▓██████ ", +"▓▓▓▓▓▓▓▓ ██████▓▓▓▓▓▓▓█████ █████████████████████ █████▓▓▓▓▓▓▓██████ ▓▓▓▓▓▓▓▓", +"▓▓▓▓▓▓▓▓▓ █████▓▓▓▓▓████ ████▓▒▒▒▒▓▓▓▒▒▒▒▓████ ████▓▓▓▓▓█████ ▓▓▓▓▓▓▓▓▓", +"▓▓▓▓▓▓▓▓▓ █████▓▓▓▓▓████ ████▓▒▒▒▒▓▓▓▒▒▒▒▓████ ████▓▓▓▓▓█████ ▓▓▓▓▓▓▓▓▓", +"▓▓▓▓▒░░░▒▓▓▓▓ █████▓▓▓▓▓▓▓▓█████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓█████▓▓▓▓▓▓▓▓█████ ▓▓▓▓▒░░░▒▓▓▓▓", +"▓▓▓▓▒░░░▒▓▓▓▓ █████▓▓▓▓▓▓▓▓█████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓█████▓▓▓▓▓▓▓▓█████ ▓▓▓▓▒░░░░▓▓▓▓", +"▓▓▓▓▒▒▒▒░░░░▒▓▓▓▓ █████████▓▓▓▓▓▒▒▒▓███▓▓▓▓▓▓▓▓█████▓▓▓▓▓▓▓▓███▓▒▒▒▒▓▓▓▓█████████ ▓▓▓▓▒░░░░▒▒▒▒▓▓▓▓", +" ▒▒▒▒▒░░░░▒▓▓▓▓ ██████████▓▓▓▒▒▒▒▓███▓▓▓▓▓███████████▓▓▓▓▓███▓▒▒▒▒▓▓▓▓█████████ ▓▓▓▓▒░░░░▒▒▒▒▒ ", +" ▓▓▓▓▓░░░░▒▒▒▒▓▓▓▓████████████▓▒▒▒▓███████▓▓▓▓█████▓▓▓▓███████▓▒▒▒▒▓████████████▓▓▓▒▒▒▒░░░░▒▓▓▓▓ ", +" ████▓▒░░░░░░▒▒▓▓▓████████████▓▒▒▒▓████████▓▓▓▓▓▓▓▓▓▓▓████████▓▒▒▒▓████████████▓▓▓▓▒░░░░░░░▓████ ", +" ████▓▒▒▒▒░░░░▒▓▓▓▓███████████▓▒▒▒▓▓▓▓████▓▒▒▒▒▒▒▒▒▒▒▒▓████▓▓▓▓▒▒▒▓████████████▓▓▓▒▒░░░▒▒▒▒▓████ ", +" ▓▓▓▓▓▒░░░▒▒▒▒▓▓▓▓▓███████▓▒▒▒▒▒▒▒▓███▒░░░░░░░░░░░▒▓██▓▒▒▒▒▒▒▒▒▓██████▓▓▓▓▓▒▒▒▒░░░▒▓▓▓▓▓ ", +" ▓▓▓▓▓▒░░░▒▒▒▒▒▓▓▓▓███████▓▒▒▒▒▒▒▒▓███▒░░░░░░░░░░░▒▓██▓▒▒▒▒▒▒▒▓▓██████▓▓▓▓▓▒▒▒▒░░░▒▓▓▓▓▓ ", +" ▓▓▓▓▓▒░░░▒▒▒▒▒▒▒▒▓▓▓▓████▓▓▓▒▒░░░▒███▒░░░░░░░░░░░▒▓██▓░░░▒▒▓▓▓████▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▓▓▓▓▓ ", +" ▓▓▓▓▓▒░░░▒▒▒▒▒▒▒▒▓▓▓▓████▓▓▓▒▒░░░▒███▒░░░░░░░░░░░▒▓██▓░░░▒▒▓▓▓████▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▓▓▓▓▓ ", +" ▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓██████▓▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░▒▓██████▓▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓ ", +" ▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓██████▓▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░▒▓██████▓▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓ ", +" ████▓▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓▓████ ", +" ████▓▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓███▓▓▓▓▓▓▓▓▓▓▓▓▓███▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓▓████ ", +" █████▓▓▓▓▓███▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓███▓▓▓▓█████ ", +" █████████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████████████ ", +" █████▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓█████ ", +" ████▓▓▒▒▒▓███████████▓▓▓▓▓▓▓▓▒░░░░░░░░░░░░░░░░░░░▒▒▓▓▓▓▓▓▓███████████▓▒▒▒▒▓████ ", +" ████▓▓▓▓▒▒▒▒▓▓▓▓████████▓▓▓▓▓▓▓▓▒▒▒▒▒░░░░░░░░░░░░▒▒▒▒▓▓▓▓▓▓▓▓█████████▓▓▓▒▒▒▒▓▓▓▓████ ", +" █████▓▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓████████████▓▓▓▓▒░░░░░░░░░░░▒▓▓▓▓████████████▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓█████ ", +" █████▓▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓████████████▓▓▓▓▒░░░░░░░░░░░▒▓▓▓▓████████████▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓█████ ", +" █████▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓███████████████████████████████████████████▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓█████ ", +" █████▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓███████████████████████████████████████████▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓█████ ", +" █████▓▓▓▓▓▓▓▓▓▓▓▓█████████████████████▓▓▓██████▓▓█████████████████████▓▓▓▓▓▓▓▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓▓████████▓▓▓█████████████▓▓▓█████▓▓▓█████████████▓▓▓████████▓▓▓▓▓▓▓▓▓█████ ", +" █████████▓▓▓▓▓████████▓▓▓▓████████████▓▓▓█████▓▓▓▓████████████▓▓▓████████▓▓▓▓▓█████████ ", +" █████▓▓▓▓▓████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████▓▓▓▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓▓████████▓▓▓█████████▓▓▓▓▓▓▓▓▓▓▓█████████▓▓▓████████▓▓▓▓▓▓▓▓██████ ", +" ██████▓▓▓▓▓▓▓▓████████████████████▓▓▓▓▓▓▓▓▓▓▓████████████████████▓▓▓▓▓▓▓▓██████ ", +" ██████████████████████████████████▓▓▓▓▓▓▓▓▓▓▓██████████████████████████████████ ", +" ██████████████████████████████████▓▓▓▓▓▓▓▓▓▓▓██████████████████████████████████ ", +" ██████▓▓▓▓▓▓██████▓▓▓████▓▓▓▓▓████▓▓▓██████▓▓▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓█████▓▓▓████▓▓▓▓▓████▓▓▓██████▓▓▓▓▓▓▓█████ ", +" █████▓▓▓▓▓▓▓▓█████████████████████████████▓▓▓▓▓▓▓▓█████ ", +" █████▓▓▓▓▓▓▓▓█████████▓▓▓█████▓▓▓█████████▓▓▓▓▓▓▓▓█████ ", +" ██████▓▓▓▓▓▓▓█████████▓▓▓▓███▓▓▓▓██████████▓▓▓▓▓▓██████ ", +" ██████████████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██████████████████ ", +" █████████████████████▓▓▓▓▓▓▓▓▓▓▓▓▓█████████████████████ ", +" █████████████████▓▓▓▓▓▓▓▓▓▓▓██████████████████ ", +" ██████████████████████████████████████████████ ", +" █████████████ ", +" █████████████ ", +NULL}; + +int +main(void) +{ + setlocale(LC_ALL, ""); + updateaccent(); + int r, g, b; + hex2rgb(accentcol, &r, &g, &b); + + for (int i = 0; icon[i]; i++) + printf("\x1b[38;2;%d;%d;%dm%s\x1b[0m\n", r, g, b, icon[i]); + + printf("\n"); + + char host[256] = ""; + gethostname(host, sizeof host); + struct utsname uts; + uname(&uts); + struct sysinfo info; + sysinfo(&info); + + char os[128] = "Unknown"; + FILE *fp = fopen("/etc/os-release", "r"); + if (fp) { + char line[256]; + while (fgets(line, sizeof line, fp)) { + if (strncmp(line, "PRETTY_NAME=", 12) == 0) { + char *p = line + 12; + if (*p == '"') p++; + char *e = strchr(p, '"'); + if (e) *e = '\0'; + snprintf(os, sizeof os, "%s", p); + break; + } + } + fclose(fp); + } + + long updays = info.uptime / 86400; + long uphours = (info.uptime / 3600) % 24; + long upmins = (info.uptime / 60) % 60; + + char cpu[128] = "Unknown"; + fp = fopen("/proc/cpuinfo", "r"); + if (fp) { + char line[256]; + while (fgets(line, sizeof line, fp)) { + if (strncmp(line, "model name", 10) == 0) { + char *p = strchr(line, ':'); + if (p) { + p += 2; + p[strcspn(p, "\n")] = '\0'; + snprintf(cpu, sizeof cpu, "%s", p); + } + break; + } + } + fclose(fp); + } + + long totalmem = info.totalram / 1024 / 1024; + long freemem = info.freeram / 1024 / 1024; + long usedmem = totalmem - freemem; + + char shell[64]; + snprintf(shell, sizeof shell, "%s", getenv("SHELL") ? getenv("SHELL") : "Unknown"); + char term[64]; + snprintf(term, sizeof term, "%s", getenv("TERM") ? getenv("TERM") : "Unknown"); + + char packages[32] = "Unknown"; + if ((fp = popen("dpkg-query -f '${binary:Package}\\n' -W 2>/dev/null | wc -l", "r"))) { + if (fgets(packages, sizeof packages, fp)) + packages[strcspn(packages, "\n")] = '\0'; + pclose(fp); + } + + printf("\x1b[38;2;%d;%d;%dmHost:\x1b[0m %s\n", r, g, b, host); + printf("\x1b[38;2;%d;%d;%dmOS:\x1b[0m %s\n", r, g, b, os); + printf("\x1b[38;2;%d;%d;%dmKernel:\x1b[0m %s\n", r, g, b, uts.release); + printf("\x1b[38;2;%d;%d;%dmUptime:\x1b[0m %ldd %ldh %ldm\n", r, g, b, updays, uphours, upmins); + printf("\x1b[38;2;%d;%d;%dmPackages:\x1b[0m %s\n", r, g, b, packages); + printf("\x1b[38;2;%d;%d;%dmShell:\x1b[0m %s\n", r, g, b, shell); + printf("\x1b[38;2;%d;%d;%dmTerminal:\x1b[0m %s\n", r, g, b, term); + printf("\x1b[38;2;%d;%d;%dmCPU:\x1b[0m %s\n", r, g, b, cpu); + printf("\x1b[38;2;%d;%d;%dmMemory:\x1b[0m %ldMiB / %ldMiB\n", r, g, b, usedmem, totalmem); + + return 0; +} |
