commit 1faf698ab8bffdc8c5f6b852ac0347a0f72839a5 Author: MeexReay Date: Fri Jul 18 05:20:16 2025 +0300 init commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e8964a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dmenu/dmenu diff --git a/README.md b/README.md new file mode 100644 index 0000000..49cf381 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# My config files + +I dont use any program for "dotfiles generating", maybe in another life + +## About + +### Summary + +![](screenshot.png) + +Void Linux + Sway + +## How to install + +```bash +./install.sh # install packages and configs +``` + +### About applying + +My username is `user`, so if you want to use my configs with another username, you need to change it from `user` to yours here: +``` +lightdm/lightdm-mini-greeter.conf (line: 7) +``` + +Also if you need to use touchpad, edit identifier of it in sway's config (you can find identifier of your touchpad in `swaymsg -t get_inputs`): +``` +sway/config (line: 52) +``` + +Shortcut to change keyboard layout is located here (default: alt + capslock): +``` +sway/config (line: 64) +``` diff --git a/aliases b/aliases new file mode 100755 index 0000000..83679a9 --- /dev/null +++ b/aliases @@ -0,0 +1,7 @@ +# alias vim="hx" +# alias vi="hx" +alias xi="sudo xbps-install" +alias xr="sudo xbps-remove" +alias xq="sudo xbps-query" +alias xs="sudo xbps-query -Rs" +alias ssh="TERM=xterm-256color ssh" diff --git a/dmenu/LICENSE b/dmenu/LICENSE new file mode 100644 index 0000000..2a64b28 --- /dev/null +++ b/dmenu/LICENSE @@ -0,0 +1,30 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe +© 2006-2008 Sander van Dijk +© 2006-2007 Michał Janeczek +© 2007 Kris Maglione +© 2009 Gottox +© 2009 Markus Schnalke +© 2009 Evan Gates +© 2010-2012 Connor Lane Smith +© 2014-2022 Hiltjo Posthuma +© 2015-2019 Quentin Rameau + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/dmenu/Makefile b/dmenu/Makefile new file mode 100644 index 0000000..458c524 --- /dev/null +++ b/dmenu/Makefile @@ -0,0 +1,58 @@ +# dmenu - dynamic menu +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dmenu.c stest.c util.c +OBJ = $(SRC:.c=.o) + +all: dmenu stest + +.c.o: + $(CC) -c $(CFLAGS) $< + +config.h: + cp config.def.h $@ + +$(OBJ): arg.h config.h config.mk drw.h + +dmenu: dmenu.o drw.o util.o + $(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS) + +stest: stest.o + $(CC) -o $@ stest.o $(LDFLAGS) + +clean: + rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz + +dist: clean + mkdir -p dmenu-$(VERSION) + cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\ + drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\ + dmenu-$(VERSION) + tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION) + gzip dmenu-$(VERSION).tar + rm -rf dmenu-$(VERSION) + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run + chmod 755 $(DESTDIR)$(PREFIX)/bin/stest + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1 + sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1 + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\ + $(DESTDIR)$(PREFIX)/bin/dmenu_path\ + $(DESTDIR)$(PREFIX)/bin/dmenu_run\ + $(DESTDIR)$(PREFIX)/bin/stest\ + $(DESTDIR)$(MANPREFIX)/man1/dmenu.1\ + $(DESTDIR)$(MANPREFIX)/man1/stest.1 + +.PHONY: all clean dist install uninstall diff --git a/dmenu/README b/dmenu/README new file mode 100644 index 0000000..a8fcdfe --- /dev/null +++ b/dmenu/README @@ -0,0 +1,24 @@ +dmenu - dynamic menu +==================== +dmenu is an efficient dynamic menu for X. + + +Requirements +------------ +In order to build dmenu you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (dmenu is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install dmenu +(if necessary as root): + + make clean install + + +Running dmenu +------------- +See the man page for details. diff --git a/dmenu/arg.h b/dmenu/arg.h new file mode 100644 index 0000000..e94e02b --- /dev/null +++ b/dmenu/arg.h @@ -0,0 +1,49 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/dmenu/config.def.h b/dmenu/config.def.h new file mode 100644 index 0000000..4394dec --- /dev/null +++ b/dmenu/config.def.h @@ -0,0 +1,26 @@ +/* See LICENSE file for copyright and license details. */ +/* Default settings; can be overriden by command line. */ + +static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +/* -fn option overrides fonts[0]; default X11 font or font set */ +static const char *fonts[] = { + "monospace:size=10" +}; +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" }, +}; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 0; +/* -h option; minimum height of a menu line */ +static unsigned int lineheight = 0; +static unsigned int min_lineheight = 8; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; diff --git a/dmenu/config.h b/dmenu/config.h new file mode 100644 index 0000000..120af96 --- /dev/null +++ b/dmenu/config.h @@ -0,0 +1,26 @@ +/* See LICENSE file for copyright and license details. */ +/* Default settings; can be overriden by command line. */ + +static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +/* -fn option overrides fonts[0]; default X11 font or font set */ +static const char *fonts[] = { + "UbuntuMono Nerd Font:size=12" +}; +static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#eeeeee", "#2d2d2f" }, + [SchemeSel] = { "#ffffff", "#285577" }, + [SchemeOut] = { "#000000", "#00ffff" }, +}; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 0; +/* -h option; minimum height of a menu line */ +static unsigned int lineheight = 23; +static unsigned int min_lineheight = 8; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; diff --git a/dmenu/config.mk b/dmenu/config.mk new file mode 100644 index 0000000..137f7c8 --- /dev/null +++ b/dmenu/config.mk @@ -0,0 +1,32 @@ +# dmenu version +VERSION = 5.3 + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = $(X11INC)/freetype2 +#MANPREFIX = ${PREFIX}/man + +# includes and libs +INCS = -I$(X11INC) -I$(FREETYPEINC) +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) +LDFLAGS = $(LIBS) + +# compiler and linker +CC = cc diff --git a/dmenu/dmenu-lineheight.diff b/dmenu/dmenu-lineheight.diff new file mode 100644 index 0000000..a5e8468 --- /dev/null +++ b/dmenu/dmenu-lineheight.diff @@ -0,0 +1,106 @@ +From ba103e38ea4ab07f9a3ee90627714b9bea17c329 Mon Sep 17 00:00:00 2001 +From: pskry +Date: Sun, 8 Nov 2020 22:04:22 +0100 +Subject: [PATCH] Add an option which defines the lineheight + +Despite both the panel and dmenu using the same font (a Terminus 12), +dmenu is shorter and the panel is visible from under the dmenu bar. +The appearance can be even more distracting when using similar colors +for background and selections. With the option added by this patch, +dmenu can be launched with a '-h 24', thus completely covering the panel. +--- + config.def.h | 3 +++ + dmenu.1 | 5 +++++ + dmenu.c | 11 ++++++++--- + 3 files changed, 16 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1edb647..4394dec 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,9 @@ static const char *colors[SchemeLast][2] = { + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; ++/* -h option; minimum height of a menu line */ ++static unsigned int lineheight = 0; ++static unsigned int min_lineheight = 8; + + /* + * Characters not considered part of a word while deleting words +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..f2a82b4 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -6,6 +6,8 @@ dmenu \- dynamic menu + .RB [ \-bfiv ] + .RB [ \-l + .IR lines ] ++.RB [ \-h ++.IR height ] + .RB [ \-m + .IR monitor ] + .RB [ \-p +@@ -50,6 +52,9 @@ dmenu matches menu items case insensitively. + .BI \-l " lines" + dmenu lists items vertically, with the given number of lines. + .TP ++.BI \-h " height" ++dmenu uses a menu line of at least 'height' pixels tall, but no less than 8. ++.TP + .BI \-m " monitor" + dmenu is displayed on the monitor number supplied. Monitor numbers are starting + from 0. +diff --git a/dmenu.c b/dmenu.c +index e7be8af..82b204b 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -148,7 +148,7 @@ drawmenu(void) + { + unsigned int curpos; + struct item *item; +- int x = 0, y = 0, w; ++ int x = 0, y = 0, fh = drw->fonts->h, w; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); +@@ -165,7 +165,7 @@ drawmenu(void) + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { + drw_setscheme(drw, scheme[SchemeNorm]); +- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); ++ drw_rect(drw, x + curpos, 2 + (bh - fh) / 2, 2, fh - 4, 1, 0); + } + + if (lines > 0) { +@@ -630,6 +630,7 @@ setup(void) + + /* calculate menu geometry */ + bh = drw->fonts->h + 2; ++ bh = MAX(bh,lineheight); /* make a menu line AT LEAST 'lineheight' tall */ + lines = MAX(lines, 0); + mh = (lines + 1) * bh; + #ifdef XINERAMA +@@ -710,7 +711,7 @@ setup(void) + static void + usage(void) + { +- die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++ die("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); + } + +@@ -737,6 +738,10 @@ main(int argc, char *argv[]) + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); ++ else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ ++ lineheight = atoi(argv[++i]); ++ lineheight = MAX(lineheight, min_lineheight); ++ } + else if (!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); + else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ +-- +2.38.1 + diff --git a/dmenu/dmenu.1 b/dmenu/dmenu.1 new file mode 100644 index 0000000..f2a82b4 --- /dev/null +++ b/dmenu/dmenu.1 @@ -0,0 +1,199 @@ +.TH DMENU 1 dmenu\-VERSION +.SH NAME +dmenu \- dynamic menu +.SH SYNOPSIS +.B dmenu +.RB [ \-bfiv ] +.RB [ \-l +.IR lines ] +.RB [ \-h +.IR height ] +.RB [ \-m +.IR monitor ] +.RB [ \-p +.IR prompt ] +.RB [ \-fn +.IR font ] +.RB [ \-nb +.IR color ] +.RB [ \-nf +.IR color ] +.RB [ \-sb +.IR color ] +.RB [ \-sf +.IR color ] +.RB [ \-w +.IR windowid ] +.P +.BR dmenu_run " ..." +.SH DESCRIPTION +.B dmenu +is a dynamic menu for X, which reads a list of newline\-separated items from +stdin. When the user selects an item and presses Return, their choice is printed +to stdout and dmenu terminates. Entering text will narrow the items to those +matching the tokens in the input. +.P +.B dmenu_run +is a script used by +.IR dwm (1) +which lists programs in the user's $PATH and runs the result in their $SHELL. +.SH OPTIONS +.TP +.B \-b +dmenu appears at the bottom of the screen. +.TP +.B \-f +dmenu grabs the keyboard before reading stdin if not reading from a tty. This +is faster, but will lock up X until stdin reaches end\-of\-file. +.TP +.B \-i +dmenu matches menu items case insensitively. +.TP +.BI \-l " lines" +dmenu lists items vertically, with the given number of lines. +.TP +.BI \-h " height" +dmenu uses a menu line of at least 'height' pixels tall, but no less than 8. +.TP +.BI \-m " monitor" +dmenu is displayed on the monitor number supplied. Monitor numbers are starting +from 0. +.TP +.BI \-p " prompt" +defines the prompt to be displayed to the left of the input field. +.TP +.BI \-fn " font" +defines the font or font set used. +.TP +.BI \-nb " color" +defines the normal background color. +.IR #RGB , +.IR #RRGGBB , +and X color names are supported. +.TP +.BI \-nf " color" +defines the normal foreground color. +.TP +.BI \-sb " color" +defines the selected background color. +.TP +.BI \-sf " color" +defines the selected foreground color. +.TP +.B \-v +prints version information to stdout, then exits. +.TP +.BI \-w " windowid" +embed into windowid. +.SH USAGE +dmenu is completely controlled by the keyboard. Items are selected using the +arrow keys, page up, page down, home, and end. +.TP +.B Tab +Copy the selected item to the input field. +.TP +.B Return +Confirm selection. Prints the selected item to stdout and exits, returning +success. +.TP +.B Ctrl-Return +Confirm selection. Prints the selected item to stdout and continues. +.TP +.B Shift\-Return +Confirm input. Prints the input text to stdout and exits, returning success. +.TP +.B Escape +Exit without selecting an item, returning failure. +.TP +.B Ctrl-Left +Move cursor to the start of the current word +.TP +.B Ctrl-Right +Move cursor to the end of the current word +.TP +.B C\-a +Home +.TP +.B C\-b +Left +.TP +.B C\-c +Escape +.TP +.B C\-d +Delete +.TP +.B C\-e +End +.TP +.B C\-f +Right +.TP +.B C\-g +Escape +.TP +.B C\-h +Backspace +.TP +.B C\-i +Tab +.TP +.B C\-j +Return +.TP +.B C\-J +Shift-Return +.TP +.B C\-k +Delete line right +.TP +.B C\-m +Return +.TP +.B C\-M +Shift-Return +.TP +.B C\-n +Down +.TP +.B C\-p +Up +.TP +.B C\-u +Delete line left +.TP +.B C\-w +Delete word left +.TP +.B C\-y +Paste from primary X selection +.TP +.B C\-Y +Paste from X clipboard +.TP +.B M\-b +Move cursor to the start of the current word +.TP +.B M\-f +Move cursor to the end of the current word +.TP +.B M\-g +Home +.TP +.B M\-G +End +.TP +.B M\-h +Up +.TP +.B M\-j +Page down +.TP +.B M\-k +Page up +.TP +.B M\-l +Down +.SH SEE ALSO +.IR dwm (1), +.IR stest (1) diff --git a/dmenu/dmenu.c b/dmenu/dmenu.c new file mode 100644 index 0000000..fcb8dcf --- /dev/null +++ b/dmenu/dmenu.c @@ -0,0 +1,806 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef XINERAMA +#include +#endif +// #include +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ + * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +/* enums */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ + +struct item { + char *text; + struct item *left, *right; + int out; +}; + +static char text[BUFSIZ] = ""; +static char *embed; +static int bh, mw, mh; +static int inputw = 0, promptw; +static int lrpad; /* sum of left and right padding */ +static size_t cursor; +static struct item *items = NULL; +static struct item *matches, *matchend; +static struct item *prev, *curr, *next, *sel; +static int mon = -1, screen; + +static Atom clip, utf8; +static Display *dpy; +static Window root, parentwin, win; +static XIC xic; + +static Drw *drw; +static Clr *scheme[SchemeLast]; + +#include "config.h" + +static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +static char *(*fstrstr)(const char *, const char *) = strstr; + +static unsigned int +textw_clamp(const char *str, unsigned int n) +{ + unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad; + return MIN(w, n); +} + +static void +appenditem(struct item *item, struct item **list, struct item **last) +{ + if (*last) + (*last)->right = item; + else + *list = item; + + item->left = *last; + item->right = NULL; + *last = item; +} + +static void +calcoffsets(void) +{ + int i, n; + + if (lines > 0) + n = lines * bh; + else + n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); + /* calculate which items will begin the next page and previous page */ + for (i = 0, next = curr; next; next = next->right) + if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n) + break; + for (i = 0, prev = curr; prev && prev->left; prev = prev->left) + if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n) + break; +} + +static void +cleanup(void) +{ + size_t i; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < SchemeLast; i++) + free(scheme[i]); + for (i = 0; items && items[i].text; ++i) + free(items[i].text); + free(items); + drw_free(drw); + XSync(dpy, False); + XCloseDisplay(dpy); +} + +static char * +cistrstr(const char *h, const char *n) +{ + size_t i; + + if (!n[0]) + return (char *)h; + + for (; *h; ++h) { + for (i = 0; n[i] && tolower((unsigned char)n[i]) == + tolower((unsigned char)h[i]); ++i) + ; + if (n[i] == '\0') + return (char *)h; + } + return NULL; +} + +static int +drawitem(struct item *item, int x, int y, int w) +{ + if (item == sel) { + drw_rect(drw, x, y, w, 3, 1, 1, 0); + drw_setscheme(drw, scheme[SchemeSel]); + } else if (item->out) + drw_setscheme(drw, scheme[SchemeOut]); + else + drw_setscheme(drw, scheme[SchemeNorm]); + + return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); +} + +static void +drawmenu(void) +{ + unsigned int curpos; + struct item *item; + int x = 0, y = 0, fh = drw->fonts->h, w; + + + //home scheme[SchemeNorm]->pixel = 0x80808080; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1, (unsigned short) (0xFFFF * 0.75)); + + if (prompt && *prompt) { + printf("sdfsf"); + drw_setscheme(drw, scheme[SchemeSel]); + x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); + } + /* draw input field */ + w = (lines > 0 || !matches) ? mw - x : inputw; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { + //scheme[SchemeNorm]->pixel = 0x80808080; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x + curpos, 2 + (bh - fh) / 2, 2, fh - 4, 1, 0, (unsigned short) (0xFFFF * 0.75)); + } + + if (lines > 0) { + /* draw vertical list */ + for (item = curr; item != next; item = item->right) + drawitem(item, x, y += bh, mw - x); + } else if (matches) { + /* draw horizontal list */ + x += inputw; + w = TEXTW("..."); + if (curr->left) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, "...", 0); + } + x += w; + for (item = curr; item != next; item = item->right) + x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW("..."))); + if (next) { + w = TEXTW("..."); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, mw - w, 0, w, bh, lrpad / 2, "...", 0); + } + } + drw_map(drw, win, 0, 0, mw, mh); +} + +static void +grabfocus(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + Window focuswin; + int i, revertwin; + + for (i = 0; i < 100; ++i) { + XGetInputFocus(dpy, &focuswin, &revertwin); + if (focuswin == win) + return; + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + nanosleep(&ts, NULL); + } + die("cannot grab focus"); +} + +static void +grabkeyboard(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; + int i; + + if (embed) + return; + /* try to grab keyboard, we may have to wait for another process to ungrab */ + for (i = 0; i < 1000; i++) { + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, + GrabModeAsync, CurrentTime) == GrabSuccess) + return; + nanosleep(&ts, NULL); + } + die("cannot grab keyboard"); +} + +static void +match(void) +{ + static char **tokv = NULL; + static int tokn = 0; + + char buf[sizeof text], *s; + int i, tokc = 0; + size_t len, textsize; + struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; + + strcpy(buf, text); + /* separate input text into tokens to be matched individually */ + for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) + if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) + die("cannot realloc %zu bytes:", tokn * sizeof *tokv); + len = tokc ? strlen(tokv[0]) : 0; + + matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; + textsize = strlen(text) + 1; + for (item = items; item && item->text; item++) { + for (i = 0; i < tokc; i++) + if (!fstrstr(item->text, tokv[i])) + break; + if (i != tokc) /* not all tokens match */ + continue; + /* exact matches go first, then prefixes, then substrings */ + if (!tokc || !fstrncmp(text, item->text, textsize)) + appenditem(item, &matches, &matchend); + else if (!fstrncmp(tokv[0], item->text, len)) + appenditem(item, &lprefix, &prefixend); + else + appenditem(item, &lsubstr, &substrend); + } + if (lprefix) { + if (matches) { + matchend->right = lprefix; + lprefix->left = matchend; + } else + matches = lprefix; + matchend = prefixend; + } + if (lsubstr) { + if (matches) { + matchend->right = lsubstr; + lsubstr->left = matchend; + } else + matches = lsubstr; + matchend = substrend; + } + curr = sel = matches; + calcoffsets(); +} + +static void +insert(const char *str, ssize_t n) +{ + if (strlen(text) + n > sizeof text - 1) + return; + /* move existing text out of the way, insert new text, and update cursor */ + memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); + if (n > 0) + memcpy(&text[cursor], str, n); + cursor += n; + match(); +} + +static size_t +nextrune(int inc) +{ + ssize_t n; + + /* return location of next utf8 rune in the given direction (+1 or -1) */ + for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc) + ; + return n; +} + +static void +movewordedge(int dir) +{ + if (dir < 0) { /* move cursor to the start of the word*/ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + } else { /* move cursor to the end of the word */ + while (text[cursor] && strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + while (text[cursor] && !strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + } +} + +static void +keypress(XKeyEvent *ev) +{ + char buf[64]; + int len; + KeySym ksym = NoSymbol; + Status status; + + len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); + switch (status) { + default: /* XLookupNone, XBufferOverflow */ + return; + case XLookupChars: /* composed string from input method */ + goto insert; + case XLookupKeySym: + case XLookupBoth: /* a KeySym and a string are returned: use keysym */ + break; + } + + if (ev->state & ControlMask) { + switch(ksym) { + case XK_a: ksym = XK_Home; break; + case XK_b: ksym = XK_Left; break; + case XK_c: ksym = XK_Escape; break; + case XK_d: ksym = XK_Delete; break; + case XK_e: ksym = XK_End; break; + case XK_f: ksym = XK_Right; break; + case XK_g: ksym = XK_Escape; break; + case XK_h: ksym = XK_BackSpace; break; + case XK_i: ksym = XK_Tab; break; + case XK_j: /* fallthrough */ + case XK_J: /* fallthrough */ + case XK_m: /* fallthrough */ + case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break; + case XK_n: ksym = XK_Down; break; + case XK_p: ksym = XK_Up; break; + + case XK_k: /* delete right */ + text[cursor] = '\0'; + match(); + break; + case XK_u: /* delete left */ + insert(NULL, 0 - cursor); + break; + case XK_w: /* delete word */ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + break; + case XK_y: /* paste selection */ + case XK_Y: + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + return; + case XK_Left: + case XK_KP_Left: + movewordedge(-1); + goto draw; + case XK_Right: + case XK_KP_Right: + movewordedge(+1); + goto draw; + case XK_Return: + case XK_KP_Enter: + break; + case XK_bracketleft: + cleanup(); + exit(1); + default: + return; + } + } else if (ev->state & Mod1Mask) { + switch(ksym) { + case XK_b: + movewordedge(-1); + goto draw; + case XK_f: + movewordedge(+1); + goto draw; + case XK_g: ksym = XK_Home; break; + case XK_G: ksym = XK_End; break; + case XK_h: ksym = XK_Up; break; + case XK_j: ksym = XK_Next; break; + case XK_k: ksym = XK_Prior; break; + case XK_l: ksym = XK_Down; break; + default: + return; + } + } + + switch(ksym) { + default: +insert: + if (!iscntrl((unsigned char)*buf)) + insert(buf, len); + break; + case XK_Delete: + case XK_KP_Delete: + if (text[cursor] == '\0') + return; + cursor = nextrune(+1); + /* fallthrough */ + case XK_BackSpace: + if (cursor == 0) + return; + insert(NULL, nextrune(-1) - cursor); + break; + case XK_End: + case XK_KP_End: + if (text[cursor] != '\0') { + cursor = strlen(text); + break; + } + if (next) { + /* jump to end of list and position items in reverse */ + curr = matchend; + calcoffsets(); + curr = prev; + calcoffsets(); + while (next && (curr = curr->right)) + calcoffsets(); + } + sel = matchend; + break; + case XK_Escape: + cleanup(); + exit(1); + case XK_Home: + case XK_KP_Home: + if (sel == matches) { + cursor = 0; + break; + } + sel = curr = matches; + calcoffsets(); + break; + case XK_Left: + case XK_KP_Left: + if (cursor > 0 && (!sel || !sel->left || lines > 0)) { + cursor = nextrune(-1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Up: + case XK_KP_Up: + if (sel && sel->left && (sel = sel->left)->right == curr) { + curr = prev; + calcoffsets(); + } + break; + case XK_Next: + case XK_KP_Next: + if (!next) + return; + sel = curr = next; + calcoffsets(); + break; + case XK_Prior: + case XK_KP_Prior: + if (!prev) + return; + sel = curr = prev; + calcoffsets(); + break; + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (!(ev->state & ControlMask)) { + cleanup(); + exit(0); + } + if (sel) + sel->out = 1; + break; + case XK_Right: + case XK_KP_Right: + if (text[cursor] != '\0') { + cursor = nextrune(+1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Down: + case XK_KP_Down: + if (sel && sel->right && (sel = sel->right) == next) { + curr = next; + calcoffsets(); + } + break; + case XK_Tab: + if (!sel) + return; + cursor = strnlen(sel->text, sizeof text - 1); + memcpy(text, sel->text, cursor); + text[cursor] = '\0'; + match(); + break; + } + +draw: + drawmenu(); +} + +static void +paste(void) +{ + char *p, *q; + int di; + unsigned long dl; + Atom da; + + /* we have been given the current selection, now insert it into input */ + if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, + utf8, &da, &di, &dl, &dl, (unsigned char **)&p) + == Success && p) { + insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); + XFree(p); + } + drawmenu(); +} + +static void +readstdin(void) +{ + char *line = NULL; + size_t i, itemsiz = 0, linesiz = 0; + ssize_t len; + + /* read each line from stdin and add it to the item list */ + for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) { + if (i + 1 >= itemsiz) { + itemsiz += 256; + if (!(items = realloc(items, itemsiz * sizeof(*items)))) + die("cannot realloc %zu bytes:", itemsiz * sizeof(*items)); + } + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + if (!(items[i].text = strdup(line))) + die("strdup:"); + + items[i].out = 0; + } + free(line); + if (items) + items[i].text = NULL; + lines = MIN(lines, i); +} + +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; + } + } +} + +static void +setup(void) +{ + int x, y, i, j; + unsigned int du; + XSetWindowAttributes swa; + XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; + XClassHint ch = {"dmenu", "dmenu"}; +#ifdef XINERAMA + XineramaScreenInfo *info; + Window pw; + int a, di, n, area = 0; +#endif + /* init appearance */ + for (j = 0; j < SchemeLast; j++) + scheme[j] = drw_scm_create(drw, colors[j], 2); + + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); + + /* calculate menu geometry */ + bh = drw->fonts->h + 2; + bh = MAX(bh,lineheight); /* make a menu line AT LEAST 'lineheight' tall */ + lines = MAX(lines, 0); + mh = (lines + 1) * bh; +#ifdef XINERAMA + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); + if (mon >= 0 && mon < n) + i = mon; + else if (w != root && w != PointerRoot && w != None) { + /* find top-level window containing current input focus */ + do { + if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) + XFree(dws); + } while (w != root && w != pw); + /* find xinerama screen with which the window intersects most */ + if (XGetWindowAttributes(dpy, pw, &wa)) + for (j = 0; j < n; j++) + if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { + area = a; + i = j; + } + } + /* no focused window is on screen, so use pointer location instead */ + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + for (i = 0; i < n; i++) + if (INTERSECT(x, y, 1, 1, info[i]) != 0) + break; + + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; + XFree(info); + } else +#endif + { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + x = 0; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; + } + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + inputw = mw / 3; /* input width: ~33% of monitor width */ + match(); + + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = 0x80808080; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dpy, root, x, y, mw, mh, 0, + CopyFromParent, CopyFromParent, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + XSetClassHint(dpy, win, &ch); + + /* input methods */ + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed: could not open input device"); + + 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); + if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { + for (i = 0; i < du && dws[i] != win; ++i) + XSelectInput(dpy, dws[i], FocusChangeMask); + XFree(dws); + } + grabfocus(); + } + drw_resize(drw, mw, mh); + drawmenu(); +} + +static void +usage(void) +{ + die("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); +} + +int +main(int argc, char *argv[]) +{ + XWindowAttributes wa; + int i, fast = 0; + + for (i = 1; i < argc; i++) + /* these options take no arguments */ + if (!strcmp(argv[i], "-v")) { /* prints version information */ + puts("dmenu-"VERSION); + exit(0); + } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ + topbar = 0; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + fstrncmp = strncasecmp; + fstrstr = cistrstr; + } else if (i + 1 == argc) + usage(); + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); + else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ + lineheight = atoi(argv[++i]); + lineheight = MAX(lineheight, min_lineheight); + } + else if (!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); + else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ + prompt = argv[++i]; + else if (!strcmp(argv[i], "-fn")) /* font or font set */ + fonts[0] = argv[++i]; + else if (!strcmp(argv[i], "-nb")) /* normal background color */ + colors[SchemeNorm][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ + colors[SchemeNorm][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-sb")) /* selected background color */ + colors[SchemeSel][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ + colors[SchemeSel][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; + else + usage(); + + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("cannot open display"); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + if (!embed || !(parentwin = strtol(embed, NULL, 0))) + parentwin = root; + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + drw = drw_create(dpy, screen, root, wa.width, wa.height); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; + +#ifdef __OpenBSD__ + if (pledge("stdio rpath", NULL) == -1) + die("pledge"); +#endif + + if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); + } else { + readstdin(); + grabkeyboard(); + } + setup(); + run(); + + return 1; /* unreachable */ +} diff --git a/dmenu/dmenu.o b/dmenu/dmenu.o new file mode 100644 index 0000000..4bff4e5 Binary files /dev/null and b/dmenu/dmenu.o differ diff --git a/dmenu/dmenu_path b/dmenu/dmenu_path new file mode 100755 index 0000000..3a7cda7 --- /dev/null +++ b/dmenu/dmenu_path @@ -0,0 +1,13 @@ +#!/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 new file mode 100755 index 0000000..834ede5 --- /dev/null +++ b/dmenu/dmenu_run @@ -0,0 +1,2 @@ +#!/bin/sh +dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & diff --git a/dmenu/drw.c b/dmenu/drw.c new file mode 100644 index 0000000..f450508 --- /dev/null +++ b/dmenu/drw.c @@ -0,0 +1,455 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD + +static int +utf8decode(const char *s_in, long *u, int *err) +{ + static const unsigned char lens[] = { + /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */ + /* 110XX */ 2, 2, 2, 2, + /* 1110X */ 3, 3, + /* 11110 */ 4, + /* 11111 */ 0, /* invalid */ + }; + static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 }; + static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 }; + + const unsigned char *s = (const unsigned char *)s_in; + int len = lens[*s >> 3]; + *u = UTF_INVALID; + *err = 1; + if (len == 0) + return 1; + + long cp = s[0] & leading_mask[len - 1]; + for (int i = 1; i < len; ++i) { + if (s[i] == '\0' || (s[i] & 0xC0) != 0x80) + return i; + cp = (cp << 6) | (s[i] & 0x3F); + } + /* out of range, surrogate, overlong encoding */ + if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1]) + return len; + + *err = 0; + *u = cp; + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert, unsigned short transparency) +{ +/* if (!drw || !drw->scheme) + return; + XRenderColor render_color = { + .red = drw->scheme[ColFg].color.red, + .green = drw->scheme[ColFg].color.green, + .blue = drw->scheme[ColFg].color.blue, + .alpha = transparency + }; + XftColorAllocValue(drw->dpy, DefaultVisual(drw->dpy, DefaultScreen(drw->dpy)), DefaultColormap(drw->dpy, DefaultScreen(drw->dpy)), &render_color, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + /*/ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + int ty, ellipsis_x = 0; + unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + int utf8strlen, utf8charlen, utf8err, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0, overflow = 0; + /* keep track of a couple codepoints for which we have no match. */ + static unsigned int nomatches[128], ellipsis_width, invalid_width; + static const char invalid[] = "�"; + + if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) + return 0; + + if (!render) { + w = invert ? invert : ~invert; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + if (w < lpad) + return x + w; + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + if (!ellipsis_width && render) + ellipsis_width = drw_fontset_getwidth(drw, "..."); + if (!invalid_width && render) + invalid_width = drw_fontset_getwidth(drw, invalid); + while (1) { + ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, &utf8err); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); + if (ew + ellipsis_width <= w) { + /* keep track where the ellipsis still fits */ + ellipsis_x = x + ew; + ellipsis_w = w - ew; + ellipsis_len = utf8strlen; + } + + if (ew + tmpw > w) { + overflow = 1; + /* called from drw_fontset_getwidth_clamp(): + * it wants the width AFTER the overflow + */ + if (!render) + x += tmpw; + else + utf8strlen = ellipsis_len; + } else if (curfont == usedfont) { + text += utf8charlen; + utf8strlen += utf8err ? 0 : utf8charlen; + ew += utf8err ? 0 : tmpw; + } else { + nextfont = curfont; + } + break; + } + } + + if (overflow || !charexists || nextfont || utf8err) + break; + else + charexists = 0; + } + + if (utf8strlen) { + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); + } + x += ew; + w -= ew; + } + if (utf8err && (!render || invalid_width < w)) { + if (render) + drw_text(drw, x, y, w, h, 0, invalid, invert); + x += invalid_width; + w -= invalid_width; + } + if (render && overflow) + drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); + + if (!*text || overflow) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + hash = (unsigned int)utf8codepoint; + hash = ((hash >> 16) ^ hash) * 0x21F0AAAD; + hash = ((hash >> 15) ^ hash) * 0xD35A2D97; + h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches); + h1 = (hash >> 17) % LENGTH(nomatches); + /* avoid expensive XftFontMatch call when we know we won't find a match */ + if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint) + goto no_match; + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint; +no_match: + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +unsigned int +drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) +{ + unsigned int tmp = 0; + if (drw && drw->fonts && text && n) + tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); + return MIN(n, tmp); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/dmenu/drw.h b/dmenu/drw.h new file mode 100644 index 0000000..247a201 --- /dev/null +++ b/dmenu/drw.h @@ -0,0 +1,58 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct Fnt { + Display *dpy; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; + struct Fnt *next; +} Fnt; + +enum { ColFg, ColBg }; /* Clr scheme index */ +typedef XftColor Clr; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + Clr *scheme; + Fnt *fonts; +} Drw; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert, unsigned short transparency); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/dmenu/drw.o b/dmenu/drw.o new file mode 100644 index 0000000..f4793a7 Binary files /dev/null and b/dmenu/drw.o differ diff --git a/dmenu/stest b/dmenu/stest new file mode 100755 index 0000000..b5c56c8 Binary files /dev/null and b/dmenu/stest differ diff --git a/dmenu/stest.1 b/dmenu/stest.1 new file mode 100644 index 0000000..2667d8a --- /dev/null +++ b/dmenu/stest.1 @@ -0,0 +1,90 @@ +.TH STEST 1 dmenu\-VERSION +.SH NAME +stest \- filter a list of files by properties +.SH SYNOPSIS +.B stest +.RB [ -abcdefghlpqrsuwx ] +.RB [ -n +.IR file ] +.RB [ -o +.IR file ] +.RI [ file ...] +.SH DESCRIPTION +.B stest +takes a list of files and filters by the files' properties, analogous to +.IR test (1). +Files which pass all tests are printed to stdout. If no files are given, stest +reads files from stdin. +.SH OPTIONS +.TP +.B \-a +Test hidden files. +.TP +.B \-b +Test that files are block specials. +.TP +.B \-c +Test that files are character specials. +.TP +.B \-d +Test that files are directories. +.TP +.B \-e +Test that files exist. +.TP +.B \-f +Test that files are regular files. +.TP +.B \-g +Test that files have their set-group-ID flag set. +.TP +.B \-h +Test that files are symbolic links. +.TP +.B \-l +Test the contents of a directory given as an argument. +.TP +.BI \-n " file" +Test that files are newer than +.IR file . +.TP +.BI \-o " file" +Test that files are older than +.IR file . +.TP +.B \-p +Test that files are named pipes. +.TP +.B \-q +No files are printed, only the exit status is returned. +.TP +.B \-r +Test that files are readable. +.TP +.B \-s +Test that files are not empty. +.TP +.B \-u +Test that files have their set-user-ID flag set. +.TP +.B \-v +Invert the sense of tests, only failing files pass. +.TP +.B \-w +Test that files are writable. +.TP +.B \-x +Test that files are executable. +.SH EXIT STATUS +.TP +.B 0 +At least one file passed all tests. +.TP +.B 1 +No files passed all tests. +.TP +.B 2 +An error occurred. +.SH SEE ALSO +.IR dmenu (1), +.IR test (1) diff --git a/dmenu/stest.c b/dmenu/stest.c new file mode 100644 index 0000000..e27d3a5 --- /dev/null +++ b/dmenu/stest.c @@ -0,0 +1,109 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#include +#include +#include +#include +#include +#include + +#include "arg.h" +char *argv0; + +#define FLAG(x) (flag[(x)-'a']) + +static void test(const char *, const char *); +static void usage(void); + +static int match = 0; +static int flag[26]; +static struct stat old, new; + +static void +test(const char *path, const char *name) +{ + struct stat st, ln; + + if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ + && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ + && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ + && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ + && (!FLAG('e') || access(path, F_OK) == 0) /* exists */ + && (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */ + && (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */ + && (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */ + && (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */ + && (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */ + && (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */ + && (!FLAG('r') || access(path, R_OK) == 0) /* readable */ + && (!FLAG('s') || st.st_size > 0) /* not empty */ + && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ + && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ + && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ + if (FLAG('q')) + exit(0); + match = 1; + puts(name); + } +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] " + "[-n file] [-o file] [file...]\n", argv0); + exit(2); /* like test(1) return > 1 on error */ +} + +int +main(int argc, char *argv[]) +{ + struct dirent *d; + char path[PATH_MAX], *line = NULL, *file; + size_t linesiz = 0; + ssize_t n; + DIR *dir; + int r; + + ARGBEGIN { + case 'n': /* newer than file */ + case 'o': /* older than file */ + file = EARGF(usage()); + if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old)))) + perror(file); + break; + default: + /* miscellaneous operators */ + if (strchr("abcdefghlpqrsuvwx", ARGC())) + FLAG(ARGC()) = 1; + else + usage(); /* unknown flag */ + } ARGEND; + + if (!argc) { + /* read list from stdin */ + while ((n = getline(&line, &linesiz, stdin)) > 0) { + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + test(line, line); + } + free(line); + } else { + for (; argc; argc--, argv++) { + if (FLAG('l') && (dir = opendir(*argv))) { + /* test directory contents */ + while ((d = readdir(dir))) { + r = snprintf(path, sizeof path, "%s/%s", + *argv, d->d_name); + if (r >= 0 && (size_t)r < sizeof path) + test(path, d->d_name); + } + closedir(dir); + } else { + test(*argv, *argv); + } + } + } + return match ? 0 : 1; +} diff --git a/dmenu/stest.o b/dmenu/stest.o new file mode 100644 index 0000000..f1b5b23 Binary files /dev/null and b/dmenu/stest.o differ diff --git a/dmenu/util.c b/dmenu/util.c new file mode 100644 index 0000000..8e26a51 --- /dev/null +++ b/dmenu/util.c @@ -0,0 +1,37 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "util.h" + +void +die(const char *fmt, ...) +{ + va_list ap; + int saved_errno; + + saved_errno = errno; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') + fprintf(stderr, " %s", strerror(saved_errno)); + fputc('\n', stderr); + + exit(1); +} + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} diff --git a/dmenu/util.h b/dmenu/util.h new file mode 100644 index 0000000..c0a50d4 --- /dev/null +++ b/dmenu/util.h @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#define LENGTH(X) (sizeof (X) / sizeof (X)[0]) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/dmenu/util.o b/dmenu/util.o new file mode 100644 index 0000000..92033b0 Binary files /dev/null and b/dmenu/util.o differ diff --git a/dunst/dunstrc b/dunst/dunstrc new file mode 100755 index 0000000..12f0c95 --- /dev/null +++ b/dunst/dunstrc @@ -0,0 +1,494 @@ +# See dunst(5) for all configuration options + +[global] + ### Display ### + + # Which monitor should the notifications be displayed on. + monitor = 0 + + # Display notification on focused monitor. Possible modes are: + # mouse: follow mouse pointer + # keyboard: follow window with keyboard focus + # none: don't follow anything + # + # "keyboard" needs a window manager that exports the + # _NET_ACTIVE_WINDOW property. + # This should be the case for almost all modern window managers. + # + # If this option is set to mouse or keyboard, the monitor option + # will be ignored. + follow = none + + ### Geometry ### + + # The width of the window, excluding the frame. + # dynamic width from 0 to 300 + # width = (0, 300) + # constant width of 300 + width = 300 + + # The height of a single notification, excluding the frame. + # dynamic height from 0 to 300 + height = (0, 300) + # constant height of 300 + # height = 300 + # NOTE: Dunst from version 1.11 and older don't support dynamic height + # and the given value is treated as the maximum height + + # Position the notification in the top right corner + origin = top-right + + # Offset from the origin + # NOTE: Dunst from version 1.11 and older use this alternative notation + # offset = 10x50 + offset = (10, 50) + + # Scale factor. It is auto-detected if value is 0. + scale = 0 + + # Maximum number of notification (0 means no limit) + notification_limit = 20 + + ### Progress bar ### + + # Turn on the progress bar. It appears when a progress hint is passed with + # for example dunstify -h int:value:12 + progress_bar = true + + # Set the progress bar height. This includes the frame, so make sure + # it's at least twice as big as the frame width. + progress_bar_height = 10 + + # Set the frame width of the progress bar + progress_bar_frame_width = 1 + + # Set the minimum width for the progress bar + progress_bar_min_width = 150 + + # Set the maximum width for the progress bar + progress_bar_max_width = 300 + + # Corner radius for the progress bar. 0 disables rounded corners. + progress_bar_corner_radius = 0 + + # Define which corners to round when drawing the progress bar. If progress_bar_corner_radius + # is set to 0 this option will be ignored. + progress_bar_corners = all + + # Corner radius for the icon image. + icon_corner_radius = 0 + + # Define which corners to round when drawing the icon image. If icon_corner_radius + # is set to 0 this option will be ignored. + icon_corners = all + + # Show how many messages are currently hidden (because of + # notification_limit). + indicate_hidden = yes + + # The transparency of the window. Range: [0; 100]. + # This option will only work if a compositing window manager is + # present (e.g. xcompmgr, compiz, etc.). (X11 only) + transparency = 25 + + # Draw a line of "separator_height" pixel height between two + # notifications. + # Set to 0 to disable. + # If gap_size is greater than 0, this setting will be ignored. + separator_height = 3 + + # Padding between text and separator. + padding = 8 + + # Horizontal padding. + horizontal_padding = 8 + + # Padding between text and icon. + text_icon_padding = 0 + + # Defines width in pixels of frame around the notification window. + # Set to 0 to disable. + frame_width = 3 + + # Defines color of the frame around the notification window. + frame_color = "#4c7899" + + # Size of gap to display between notifications - requires a compositor. + # If value is greater than 0, separator_height will be ignored and a border + # of size frame_width will be drawn around each notification instead. + # Click events on gaps do not currently propagate to applications below. + gap_size = 0 + + # Define a color for the separator. + # possible values are: + # * auto: dunst tries to find a color fitting to the background; + # * foreground: use the same color as the foreground; + # * frame: use the same color as the frame; + # * anything else will be interpreted as a X color. + separator_color = frame + + # Sort type. + # possible values are: + # * id: sort by id + # * urgency_ascending: sort by urgency (low then normal then critical) + # * urgency_descending: sort by urgency (critical then normal then low) + # * update: sort by update (most recent always at the top) + sort = yes + + # Don't remove messages, if the user is idle (no mouse or keyboard input) + # for longer than idle_threshold seconds. + # Set to 0 to disable. + # A client can set the 'transient' hint to bypass this. See the rules + # section for how to disable this if necessary + # idle_threshold = 120 + + ### Text ### + + font = Monospace 8 + + # The spacing between lines. If the height is smaller than the + # font height, it will get raised to the font height. + line_height = 0 + + # Possible values are: + # full: Allow a small subset of html markup in notifications: + # bold + # italic + # strikethrough + # underline + # + # For a complete reference see + # . + # + # strip: This setting is provided for compatibility with some broken + # clients that send markup even though it's not enabled on the + # server. Dunst will try to strip the markup but the parsing is + # simplistic so using this option outside of matching rules for + # specific applications *IS GREATLY DISCOURAGED*. + # + # no: Disable markup parsing, incoming notifications will be treated as + # plain text. Dunst will not advertise that it has the body-markup + # capability if this is set as a global setting. + # + # It's important to note that markup inside the format option will be parsed + # regardless of what this is set to. + markup = full + + # The format of the message. Possible variables are: + # %a appname + # %s summary + # %b body + # %i iconname (including its path) + # %I iconname (without its path) + # %p progress value if set ([ 0%] to [100%]) or nothing + # %n progress value if set without any extra characters + # %% Literal % + # Markup is allowed + format = "%s\n%b" + + # Alignment of message text. + # Possible values are "left", "center" and "right". + alignment = left + + # Vertical alignment of message text and icon. + # Possible values are "top", "center" and "bottom". + vertical_alignment = center + + # Show age of message if message is older than show_age_threshold + # seconds. + # Set to -1 to disable. + show_age_threshold = 60 + + # Specify where to make an ellipsis in long lines. + # Possible values are "start", "middle" and "end". + ellipsize = middle + + # Ignore newlines '\n' in notifications. + ignore_newline = no + + # Stack together notifications with the same content + stack_duplicates = true + + # Hide the count of stacked notifications with the same content + hide_duplicate_count = false + + # Display indicators for URLs (U) and actions (A). + show_indicators = yes + + ### Icons ### + + # Recursive icon lookup. You can set a single theme, instead of having to + # define all lookup paths. + enable_recursive_icon_lookup = true + + # Set icon theme (only used for recursive icon lookup) + icon_theme = Adwaita + # You can also set multiple icon themes, with the leftmost one being used first. + # icon_theme = "Adwaita, breeze" + + # Align icons left/right/top/off + icon_position = left + + # Scale small icons up to this size, set to 0 to disable. Helpful + # for e.g. small files or high-dpi screens. In case of conflict, + # max_icon_size takes precedence over this. + min_icon_size = 32 + + # Scale larger icons down to this size, set to 0 to disable + max_icon_size = 64 + + # Paths to default icons (only necessary when not using recursive icon lookup) + icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/ + + ### History ### + + # Should a notification popped up from history be sticky or timeout + # as if it would normally do. + sticky_history = yes + + # Maximum amount of notifications kept in history + history_length = 20 + + ### Misc/Advanced ### + + # dmenu path. + dmenu = /usr/bin/dmenu -p dunst: + + # Browser for opening urls in context menu. + browser = /usr/bin/xdg-open + + # Always run rule-defined scripts, even if the notification is suppressed + always_run_script = true + + # Define the title of the windows spawned by dunst (X11 only) + title = Dunst + + # Define the class of the windows spawned by dunst (X11 only) + class = Dunst + + # Define the corner radius of the notification window + # in pixel size. If the radius is 0, you have no rounded + # corners. + # The radius will be automatically lowered if it exceeds half of the + # notification height to avoid clipping text and/or icons. + corner_radius = 15 + + # Define which corners to round when drawing the window. If the corner radius + # is set to 0 this option will be ignored. + # + # Comma-separated list of the corners. The accepted corner values are bottom-right, + # bottom-left, top-right, top-left, top, bottom, left, right or all. + corners = all + + # Ignore the dbus closeNotification message. + # Useful to enforce the timeout set by dunst configuration. Without this + # parameter, an application may close the notification sent before the + # user defined timeout. + ignore_dbusclose = false + + ### Wayland ### + # These settings are Wayland-specific. They have no effect when using X11 + + # Uncomment this if you want to let notifications appear under fullscreen + # applications (default: overlay) + # layer = top + + # Set this to true to use X11 output on Wayland. + force_xwayland = false + + ### Legacy + + # Use the Xinerama extension instead of RandR for multi-monitor support. + # This setting is provided for compatibility with older nVidia drivers that + # do not support RandR and using it on systems that support RandR is highly + # discouraged. + # + # By enabling this setting dunst will not be able to detect when a monitor + # is connected or disconnected which might break follow mode if the screen + # layout changes. + force_xinerama = false + + ### mouse + + # Defines list of actions for each mouse event + # Possible values are: + # * none: Don't do anything. + # * do_action: Invoke the action determined by the action_name rule. If there is no + # such action, open the context menu. + # * open_url: If the notification has exactly one url, open it. If there are multiple + # ones, open the context menu. + # * close_current: Close current notification. + # * close_all: Close all notifications. + # * context: Open context menu for the notification. + # * context_all: Open context menu for all notifications. + # These values can be strung together for each mouse event, and + # will be executed in sequence. + mouse_left_click = close_current + mouse_middle_click = do_action, close_current + mouse_right_click = do_action, close_current + +# Experimental features that may or may not work correctly. Do not expect them +# to have a consistent behaviour across releases. +[experimental] + # Calculate the dpi to use on a per-monitor basis. + # If this setting is enabled the Xft.dpi value will be ignored and instead + # dunst will attempt to calculate an appropriate dpi value for each monitor + # using the resolution and physical size. This might be useful in setups + # where there are multiple screens with very different dpi values. + per_monitor_dpi = false + + +[urgency_low] + # IMPORTANT: colors have to be defined in quotation marks. + # Otherwise the "#" and following would be interpreted as a comment. + background = "#222222" + foreground = "#888888" + timeout = 10 + # Icon for notifications with low urgency + default_icon = dialog-information + +[urgency_normal] + background = "#285577" + foreground = "#ffffff" + timeout = 10 + override_pause_level = 30 + # Icon for notifications with normal urgency + default_icon = dialog-information + +[urgency_critical] + background = "#891818" + foreground = "#ffffff" + frame_color = "#ab2828" + timeout = 0 + override_pause_level = 60 + # Icon for notifications with critical urgency + default_icon = dialog-warning + +# Every section that isn't one of the above is interpreted as a rules to +# override settings for certain messages. +# +# Messages can be matched by +# appname (discouraged, see desktop_entry) +# body +# category +# desktop_entry +# icon +# match_transient +# msg_urgency +# stack_tag +# summary +# +# and you can override the +# background +# foreground +# format +# frame_color +# fullscreen +# new_icon +# set_stack_tag +# set_transient +# set_category +# timeout +# urgency +# icon_position +# skip_display +# history_ignore +# action_name +# word_wrap +# ellipsize +# alignment +# hide_text +# override_pause_level +# +# Shell-like globbing will get expanded. +# +# Instead of the appname filter, it's recommended to use the desktop_entry filter. +# GLib based applications export their desktop-entry name. In comparison to the appname, +# the desktop-entry won't get localized. +# +# You can also allow a notification to appear even when paused. Notification will appear whenever notification's override_pause_level >= dunst's paused level. +# This can be used to set partial pause modes, where more urgent notifications get through, but less urgent stay paused. To do that, you can override the following in the rules: +# override_pause_level = X + +# SCRIPTING +# You can specify a script that gets run when the rule matches by +# setting the "script" option. +# The script will be called as follows: +# script appname summary body icon urgency +# where urgency can be "LOW", "NORMAL" or "CRITICAL". +# +# NOTE: It might be helpful to run dunst -print in a terminal in order +# to find fitting options for rules. + +# Disable the transient hint so that idle_threshold cannot be bypassed from the +# client +#[transient_disable] +# match_transient = yes +# set_transient = no +# +# Make the handling of transient notifications more strict by making them not +# be placed in history. +#[transient_history_ignore] +# match_transient = yes +# history_ignore = yes + +# fullscreen values +# show: show the notifications, regardless if there is a fullscreen window opened +# delay: displays the new notification, if there is no fullscreen window active +# If the notification is already drawn, it won't get undrawn. +# pushback: same as delay, but when switching into fullscreen, the notification will get +# withdrawn from screen again and will get delayed like a new notification +#[fullscreen_delay_everything] +# fullscreen = delay +#[fullscreen_show_critical] +# msg_urgency = critical +# fullscreen = show + +#[espeak] +# summary = "*" +# script = dunst_espeak.sh + +#[script-test] +# summary = "*script*" +# script = dunst_test.sh + +#[ignore] +# # This notification will not be displayed +# summary = "foobar" +# skip_display = true + +#[history-ignore] +# # This notification will not be saved in history +# summary = "foobar" +# history_ignore = yes + +#[skip-display] +# # This notification will not be displayed, but will be included in the history +# summary = "foobar" +# skip_display = yes + +#[signed_on] +# appname = Pidgin +# summary = "*signed on*" +# urgency = low +# +#[signed_off] +# appname = Pidgin +# summary = *signed off* +# urgency = low +# +#[says] +# appname = Pidgin +# summary = *says* +# urgency = critical +# +#[twitter] +# appname = Pidgin +# summary = *twitter.com* +# urgency = normal +# +#[stack-volumes] +# appname = "some_volume_notifiers" +# set_stack_tag = "volume" +# +# vim: ft=cfg diff --git a/generate.sh b/generate.sh new file mode 100755 index 0000000..cc89198 --- /dev/null +++ b/generate.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf lightdm/ kitty/ sway/ waybar/ helix/ dunst/ aliases packages + +mkdir lightdm + +xbps-query -m > packages +cp ~/.bash_aliases aliases +cp /etc/lightdm/lightdm.conf lightdm +cp /etc/lightdm/lightdm-mini-greeter.conf lightdm +cp /etc/lightdm/bg.png lightdm +cp -r ~/.config/kitty kitty +cp -r ~/.config/sway sway +cp -r ~/.config/waybar waybar +cp -r ~/.config/helix helix +cp -r ~/.config/dunst dunst diff --git a/helix/config.toml b/helix/config.toml new file mode 100644 index 0000000..bcda605 --- /dev/null +++ b/helix/config.toml @@ -0,0 +1,24 @@ +theme = "transparent_ayu_dark" + +[editor] +line-number = "absolute" +mouse = true + +[editor.indent-guides] +render = true +character = "▏" # Some characters that work well: "▏", "┆", "┊", "⸽" +skip-levels = 1 + +[editor.cursor-shape] +insert = "bar" +normal = "block" +select = "underline" + +[editor.file-picker] +hidden = false + +[editor.auto-save] +focus-lost = true + +[editor.lsp] +display-inlay-hints = true diff --git a/helix/languages.toml b/helix/languages.toml new file mode 100644 index 0000000..9d5e354 --- /dev/null +++ b/helix/languages.toml @@ -0,0 +1,6 @@ +# [[language]] +# name = "rust" +# auto-format = false + +# [[language]] +# name = "python" diff --git a/helix/themes/transparent_ayu_dark.toml b/helix/themes/transparent_ayu_dark.toml new file mode 100644 index 0000000..5f7bcf8 --- /dev/null +++ b/helix/themes/transparent_ayu_dark.toml @@ -0,0 +1,2 @@ +inherits = "ayu_dark" +"ui.background" ={} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..6478e84 --- /dev/null +++ b/install.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +cp aliases ~/.bash_aliases +sudo cp -a lightdm/. /etc/lightdm +cp -a kitty/. ~/.config/kitty +cp -a sway/. ~/.config/sway +cp -a waybar/. ~/.config/waybar +cp -a helix/. ~/.config/helix +cp -a dunst/. ~/.config/dunst +chmod +x ~/.startup +chmod +x ~/.bash_aliases + +sudo xbps-install -Su $(cat packages) + +cd dmenu +make clean install diff --git a/kitty/current-theme.conf b/kitty/current-theme.conf new file mode 100644 index 0000000..40197a4 --- /dev/null +++ b/kitty/current-theme.conf @@ -0,0 +1,64 @@ +## name: bl1nk +## author: dhay3 +## license: CC0 1.0 +## upstream: https://github.com/dhay3/kitty-bl1nk/blob/main/bl1nk.conf + +#: The basic colors +background #111111 +foreground #A0A0A0 +selection_foreground none +selection_background none + + +#: cursor colors +cursor none + + +#: URL underline color when hovering with mouse +url_color #0087bd + + +#: kitty window border colors and terminal bell colors +visual_bell_color none + + +#: Tab bar colors +active_tab_foreground #FFFFFF +active_tab_background #9C7BD7 +inactive_tab_foreground #FFFFFF +inactive_tab_background #545B7D + + +#: The basic 16 colors + +#: black +color0 #1A1C1D +color8 #505354 + +#: red +color1 #FF5894 +color9 #F92571 + +#: green +color2 #B5E354 +color10 #81B313 + +#: yellow +color3 #F5921D +color11 #FEED6B + +#: blue +color4 #4E81AA +color12 #0B72C1 + +#: magenta +color5 #8B54FE +color13 #9D6EFE + +#: cyan +color6 #465456 +color14 #889BA1 + +#: white +color7 #CBCBC5 +color15 #F8F8F2 diff --git a/kitty/kitty.conf b/kitty/kitty.conf new file mode 100644 index 0000000..6c6611b --- /dev/null +++ b/kitty/kitty.conf @@ -0,0 +1,13 @@ +confirm_os_window_close 0 +map ctrl+c copy_and_clear_or_interrupt +map ctrl+v paste_from_clipboard +map ctrl+equal increase_font_size +map ctrl+minus decrease_font_size +touch_scroll_multiplier 3.0 +wheel_scroll_multiplier 3.0 +background_opacity 0.9 + +# BEGIN_KITTY_THEME +# bl1nk +include current-theme.conf +# END_KITTY_THEME diff --git a/kitty/kitty.conf.bak b/kitty/kitty.conf.bak new file mode 100644 index 0000000..d93fbec --- /dev/null +++ b/kitty/kitty.conf.bak @@ -0,0 +1,10 @@ +confirm_os_window_close 0 +map ctrl+c copy_and_clear_or_interrupt +map ctrl+v paste_from_clipboard +map ctrl+equal increase_font_size +map ctrl+minus decrease_font_size +touch_scroll_multiplier 3.0 +wheel_scroll_multiplier 3.0 +background_opacity 0.9 + +include current-theme.conf diff --git a/lightdm/bg.png b/lightdm/bg.png new file mode 100644 index 0000000..7e4d433 Binary files /dev/null and b/lightdm/bg.png differ diff --git a/lightdm/lightdm-mini-greeter.conf b/lightdm/lightdm-mini-greeter.conf new file mode 100644 index 0000000..96d09ae --- /dev/null +++ b/lightdm/lightdm-mini-greeter.conf @@ -0,0 +1,88 @@ +# LightDM Mini Greeter Configuration +# +# To test your configuration out, run: lightdm --test-mode + +[greeter] +# The user to login as. +user = user +# Whether to show the password input's label. +show-password-label = true +# The text of the password input's label. +password-label-text = Password: +# The text shown when an invalid password is entered. May be blank. +invalid-password-text = Invalid Password +# Show a blinking cursor in the password input. +show-input-cursor = true +# The text alignment for the password input. Possible values are: +# "left", "center", or "right" +password-alignment = right +# The number of characters that should fit into the password input. +# A value of -1 will use GTK's default width. +# Note: The entered width is a suggestion, GTK may render a narrower input. +password-input-width = -1 +# Show the background image on all monitors or just the primary monitor. +show-image-on-all-monitors = false + + +[greeter-hotkeys] +# The modifier key used to trigger hotkeys. Possible values are: +# "alt", "control" or "meta" +# meta is also known as the "Windows"/"Super" key +mod-key = meta +# Power management shortcuts (single-key, case-sensitive) +shutdown-key = s +restart-key = r +hibernate-key = h +suspend-key = u + + +[greeter-theme] +# A color from X11's `rgb.txt` file, a quoted hex string(`"#rrggbb"`) or a +# RGB color(`rgb(r,g,b)`) are all acceptable formats. + +# The font to use for all text +font = "Sans" +# The font size to use for all text +font-size = 1em +# The font weight to use for all text +font-weight = bold +# The font style to use for all text +font-style = normal +# The default text color +text-color = "#F8F8F0" +# The color of the error text +error-color = "#F8F8F0" +# An absolute path to an optional background image. +# The image will be displayed centered & unscaled. +# Note: The file should be somewhere that LightDM has permissions to read +# (e.g., /etc/lightdm/). +# background-image = "/etc/lightdm/bg.png" +# The screen's background color. +background-color = "#000000" +# The password window's background color +window-color = "#1B1D1E" +# The color of the password window's border +border-color = "#080800" +# The width of the password window's border. +# A trailing `px` is required. +border-width = 2px +# The pixels of empty space around the password input. +# Do not include a trailing `px`. +layout-space = 15 +# The character used to mask your password. Possible values are: +# "-1", "0", or a single unicode character(including emojis) +# A value of -1 uses the default bullet & 0 displays no characters when you +# type your password. +password-character = -1 +# The color of the text in the password input. +password-color = "#F8F8F0" +# The background color of the password input. +password-background-color = "#1B1D1E" +# The color of the password input's border. +# Falls back to `border-color` if missing. +password-border-color = "#080800" +# The width of the password input's border. +# Falls back to `border-width` if missing. +password-border-width = 2px +# The border radius of the password input. +password-border-radius = 0em diff --git a/lightdm/lightdm.conf b/lightdm/lightdm.conf new file mode 100644 index 0000000..08ac1c1 --- /dev/null +++ b/lightdm/lightdm.conf @@ -0,0 +1,163 @@ +# +# General configuration +# +# start-default-seat = True to always start one seat if none are defined in the configuration +# greeter-user = User to run greeter as +# minimum-display-number = Minimum display number to use for X servers +# minimum-vt = First VT to run displays on +# lock-memory = True to prevent memory from being paged to disk +# user-authority-in-system-dir = True if session authority should be in the system location +# guest-account-script = Script to be run to setup guest account +# logind-check-graphical = True to on start seats that are marked as graphical by logind +# log-directory = Directory to log information to +# run-directory = Directory to put running state in +# cache-directory = Directory to cache to +# sessions-directory = Directory to find sessions +# remote-sessions-directory = Directory to find remote sessions +# greeters-directory = Directory to find greeters +# backup-logs = True to move add a .old suffix to old log files when opening new ones +# dbus-service = True if LightDM provides a D-Bus service to control it +# +[LightDM] +#start-default-seat=true +#greeter-user=lightdm +#minimum-display-number=0 +#minimum-vt=7 +#lock-memory=true +#user-authority-in-system-dir=false +#guest-account-script=guest-account +#logind-check-graphical=true +#log-directory=/var/log/lightdm +#run-directory=/var/run/lightdm +#cache-directory=/var/cache/lightdm +#sessions-directory=/usr/share/lightdm/sessions:/usr/share/xsessions:/usr/share/wayland-sessions +#remote-sessions-directory=/usr/share/lightdm/remote-sessions +#greeters-directory=$XDG_DATA_DIRS/lightdm/greeters:$XDG_DATA_DIRS/xgreeters +#backup-logs=true +#dbus-service=true + +# +# Seat configuration +# +# Seat configuration is matched against the seat name glob in the section, for example: +# [Seat:*] matches all seats and is applied first. +# [Seat:seat0] matches the seat named "seat0". +# [Seat:seat-thin-client*] matches all seats that have names that start with "seat-thin-client". +# +# type = Seat type (local, xremote) +# pam-service = PAM service to use for login +# pam-autologin-service = PAM service to use for autologin +# pam-greeter-service = PAM service to use for greeters +# xserver-command = X server command to run (can also contain arguments e.g. X -special-option) +# xmir-command = Xmir server command to run (can also contain arguments e.g. Xmir -special-option) +# xserver-config = Config file to pass to X server +# xserver-layout = Layout to pass to X server +# xserver-allow-tcp = True if TCP/IP connections are allowed to this X server +# xserver-share = True if the X server is shared for both greeter and session +# xserver-hostname = Hostname of X server (only for type=xremote) +# xserver-display-number = Display number of X server (only for type=xremote) +# xdmcp-manager = XDMCP manager to connect to (implies xserver-allow-tcp=true) +# xdmcp-port = XDMCP UDP/IP port to communicate on +# xdmcp-key = Authentication key to use for XDM-AUTHENTICATION-1 (stored in keys.conf) +# greeter-session = Session to load for greeter +# greeter-hide-users = True to hide the user list +# greeter-allow-guest = True if the greeter should show a guest login option +# greeter-show-manual-login = True if the greeter should offer a manual login option +# greeter-show-remote-login = True if the greeter should offer a remote login option +# user-session = Session to load for users +# allow-user-switching = True if allowed to switch users +# allow-guest = True if guest login is allowed +# guest-session = Session to load for guests (overrides user-session) +# session-wrapper = Wrapper script to run session with +# greeter-wrapper = Wrapper script to run greeter with +# guest-wrapper = Wrapper script to run guest sessions with +# display-setup-script = Script to run when starting a greeter session (runs as root) +# display-stopped-script = Script to run after stopping the display server (runs as root) +# greeter-setup-script = Script to run when starting a greeter (runs as root) +# session-setup-script = Script to run when starting a user session (runs as root) +# session-cleanup-script = Script to run when quitting a user session (runs as root) +# autologin-guest = True to log in as guest by default +# autologin-user = User to log in with by default (overrides autologin-guest) +# autologin-user-timeout = Number of seconds to wait before loading default user +# autologin-session = Session to load for automatic login (overrides user-session) +# autologin-in-background = True if autologin session should not be immediately activated +# exit-on-failure = True if the daemon should exit if this seat fails +# +[Seat:*] +#type=local +#pam-service=lightdm +#pam-autologin-service=lightdm-autologin +#pam-greeter-service=lightdm-greeter +#xserver-command=X +#xmir-command=Xmir +#xserver-config= +#xserver-layout= +#xserver-allow-tcp=false +#xserver-share=true +#xserver-hostname= +#xserver-display-number= +#xdmcp-manager= +#xdmcp-port=177 +#xdmcp-key= +greeter-session=lightdm-mini-greeter +#greeter-hide-users=false +#greeter-allow-guest=true +#greeter-show-manual-login=false +#greeter-show-remote-login=true +#user-session=default +#allow-user-switching=true +#allow-guest=true +#guest-session= +session-wrapper=/etc/lightdm/Xsession +#greeter-wrapper= +#guest-wrapper= +#display-setup-script= +#display-stopped-script= +greeter-setup-script=/usr/bin/numlockx on +#session-setup-script= +#session-cleanup-script= +#autologin-guest=false +#autologin-user= +#autologin-user-timeout=0 +#autologin-in-background=false +#autologin-session= +#exit-on-failure=false + +# +# XDMCP Server configuration +# +# enabled = True if XDMCP connections should be allowed +# port = UDP/IP port to listen for connections on +# listen-address = Host/address to listen for XDMCP connections (use all addresses if not present) +# key = Authentication key to use for XDM-AUTHENTICATION-1 or blank to not use authentication (stored in keys.conf) +# hostname = Hostname to report to XDMCP clients (defaults to system hostname if unset) +# +# The authentication key is a 56 bit DES key specified in hex as 0xnnnnnnnnnnnnnn. Alternatively +# it can be a word and the first 7 characters are used as the key. +# +[XDMCPServer] +#enabled=false +#port=177 +#listen-address= +#key= +#hostname= + +# +# VNC Server configuration +# +# enabled = True if VNC connections should be allowed +# command = Command to run Xvnc server with +# port = TCP/IP port to listen for connections on +# listen-address = Host/address to listen for VNC connections (use all addresses if not present) +# width = Width of display to use +# height = Height of display to use +# depth = Color depth of display to use +# +[VNCServer] +#enabled=false +#command=Xvnc +#port=5900 +#listen-address= +#width=1024 +#height=768 +#depth=8 diff --git a/packages b/packages new file mode 100644 index 0000000..335a8fa --- /dev/null +++ b/packages @@ -0,0 +1,269 @@ +7zip-25.00_1 +CopyQ-9.1.0_1 +ImageMagick-7.1.1.47_2 +Kooha-2.3.0_1 +NetworkManager-1.50.0_1 +PrismLauncher-9.4_1 +Thunar-4.20.3_1 +Waybar-0.13.0_3 +abootimg-0.6.20160512_3 +acpi-1.7_4 +aircrack-ng-1.7_5 +amdvlk-2025.Q1.3_1 +android-file-transfer-linux-4.5_2 +android-tools-35.0.1_1 +anki-2.1.15_7 +azote-1.16.0_2 +baobab-48.0_1 +base-system-0.114_2 +bemenu-0.6.23_1 +bind-utils-9.16.22_4 +blender-4.4.3_1 +blueman-2.4.4_1 +bluez-5.78_1 +brightnessctl-0.5.1_1 +btop-1.4.4_1 +cairo-devel-1.18.4_2 +chntpw-140201_2 +chromium-138.0.7204.92_1 +chromium-widevine-132.0.6834.83_1 +chrony-4.7_1 +clang-17_5 +cmake-4.0.2_1 +cmake-gui-4.0.2_1 +cmatrix-2.0_2 +cross-aarch64-linux-gnu-0.37_2 +cross-x86_64-w64-mingw32-12.0.0_1 +cryptsetup-2.7.5_2 +curl-8.14.1_1 +dbeaver-25.1.2_1 +dbus-1.16.2_2 +dbus-elogind-1.14.6_2 +dialog-1.3.20250116_1 +discord-0.0.87_1 +dmidecode-3.6_1 +docker-28.3.2_1 +docker-compose-2.37.1_1 +dotool-1.4_2 +dunst-1.12.2_1 +elogind-252.9_2 +eog-47.0_2 +espeak-1.51_1 +evtest-1.34_1 +fastfetch-2.47.0_1 +feh-3.10.3_1 +filezilla-3.67.1_1 +firefox-140.0_1 +flameshot-12.1.0_1 +flatpak-1.16.1_1 +flex-2.6.4_3 +font-awesome-4.7.0_3 +foot-1.22.3_1 +fswebcam-20200725_1 +fuse-devel-2.9.9_1 +gammastep-2.0.9_4 +gcc-14.2.1+20250405_2 +gdb-16.3_1 +gettext-0.22.5_1 +git-2.50.0_1 +git-lfs-3.6.1_1 +glfw-devel-3.4_1 +glib-devel-2.84.0_2 +gnome-calculator-48.1_1 +gnome-clocks-48.0_1 +gnome-disk-utility-46.1_1 +gnome-power-manager-43.0_1 +gnome-text-editor-48.3_1 +gnome-themes-extra-3.28_4 +gnome-tweak-tool-46.1_2 +go-1.24.5_1 +gobject-introspection-1.84.0_2 +gparted-1.7.0_1 +gradle-8.11.1_2 +grim-1.4.1_1 +grub-customizer-5.2.3_2 +grub-i386-efi-2.12_2 +grub-x86_64-efi-2.12_2 +gscreenshot-3.8.0_1 +gtk-doc-1.34.0_2 +gtk4-devel-4.18.5_1 +guvcview-2.1.0_2 +gvfs-1.56.1_1 +gvfs-devel-1.56.1_1 +helix-25.01.1_1 +htop-3.4.1_1 +i2c-tools-4.4_2 +i3blocks-1.5_2 +inetutils-telnet-2.6_1 +intellij-idea-community-edition-2025.1.2_1 +ipset-7.24_1 +jq-1.8.1_1 +kcalc-24.08.0_1 +kde-cli-tools-6.3.3_1 +kdenlive-25.04.2_1 +keyd-2.5.0_1 +kitty-0.42.1_1 +krita-5.2.9_3 +kwrite-25.04.2_1 +lego-4.23.1_1 +libX11-devel-1.8.12_2 +libXft-devel-2.3.9_2 +libXi-devel-1.8.2_2 +libXinerama-devel-1.1.5_1 +libXtst-devel-1.2.5_2 +libclang-17_5 +libevdev-devel-1.13.2_1 +libfprint0-1.0_2 +libgusb-devel-0.4.9_1 +libinput-devel-1.28.1_1 +libnotify-devel-0.8.4_2 +libreoffice-25.2.4.3_1 +libva-utils-2.22.0_1 +libva-vdpau-driver-0.7.4_4 +libvirt-10.5.0_3 +lightdm-1.32.0_7 +lightdm-mini-greeter-0.5.1_2 +lighttpd-1.4.79_1 +linux-6.12_1 +linux-mainline-6.15_1 +linux-mainline-headers-6.15_1 +linux6.12-6.12.36_1 +linux6.13-6.13.12_1 +linux6.13-headers-6.13.12_1 +lm_sensors-3.6.0_2 +lrzip-0.651_1 +lsd-1.1.5_2 +lshw-B.02.20_1 +lsof-4.99.5_1 +lvm2-2.03.29_1 +lxappearance-0.6.4_2 +make-4.4.1_1 +mate-calc-1.28.0_1 +mdadm-4.3_4 +mesa-dri-25.1.3_1 +mesa-vaapi-25.1.3_1 +mesa-vdpau-25.1.3_1 +mesa-vulkan-radeon-25.1.3_1 +meson-1.6.1_1 +mtools-4.0.43_1 +nano-8.5_1 +ncurses-devel-6.5_2 +neofetch-7.1.0_2 +nerd-fonts-3.3.0_1 +nheko-0.12.0_3 +nim-2.2.4_1 +nodejs-22.15.0_2 +noto-fonts-emoji-2.048_1 +ntfs-3g-2022.10.3_1 +numlockx-1.2_5 +nwg-look-0.2.7_2 +obs-31.0.2_6 +obs-devel-31.0.2_6 +openjdk-jre-8u999_1 +openjdk17-17.0.15+2_2 +openjdk21-21.0.7+2_2 +openjdk8-8u332b05_3 +openssl-devel-3.5.1_1 +pango-devel-1.56.3_2 +parted-3.6_1 +patch-2.7.6_4 +pavucontrol-6.1_1 +pcmanfm-1.4.0_1 +pcmanfm-qt-2.2.0_1 +pfetch-0.6.0_2 +picocom-3.1_2 +pkg-config-0.29.2_3 +plymouth-22.02.122_1 +polkit-elogind-126_2 +powerdevil-6.3.3_1 +powertop-2.15_2 +proxychains-ng-4.17_1 +pulseaudio-16.1_2 +putty-0.81_1 +pycharm-community-2025.1.1.1_1 +python-pip-20.3.4_1 +python2-2.7.18.11_2 +python3-devel-3.13.5_1 +python3-evdev-1.7.1_1 +python3-libevdev-0.9_6 +python3-pip-25.1.1_1 +python3-pyudev-0.24.0_3 +python3-tkinter-3.13.5_1 +qbittorrent-5.1.0_1 +qemu-10.0.2_1 +qt5-5.15.11+20231124_5 +qt5-devel-5.15.11+20231124_5 +qt5-svg-devel-5.15.11+20231124_5 +qt5-tools-5.15.11+20231124_5 +qt5-tools-devel-5.15.11+20231124_5 +redshift-1.12_9 +rofi-1.7.9.1_1 +ruff-0.12.2_1 +shadowsocks-libev-3.3.4_6 +slurp-1.5.0_1 +smartmontools-7.5_1 +spdlog-1.11.0_1 +speech-dispatcher-0.11.5_2 +sqlite-devel-3.49.2_1 +surf-2.1_2 +swappy-1.5.1_1 +sway-1.11_1 +swayidle-1.8.0_1 +swaylock-1.8.2_1 +syslinux-6.03_8 +telegram-desktop-5.12.3_1 +thunar-archive-plugin-0.5.3_1 +thunar-volman-4.20.0_1 +tk-devel-8.6.14_1 +tlp-1.8.0_1 +tlpui-1.8.0_1 +tmux-3.5a_1 +tsocks-1.8beta5_4 +twemoji-15.1.0_1 +udisks2-devel-2.10.1_1 +unzip-6.0_15 +v4l2loopback-0.15.0_1 +valgrind-3.25.1_1 +vim-9.1.1215_2 +virt-manager-5.0.0_1 +virtualbox-ose-7.1.10_1 +vitetris-0.59.1_1 +vlc-3.0.21_4 +void-docs-browse-2025.01.25_1 +void-live-audio-0.1.1_1 +void-repo-multilib-6_4 +void-repo-multilib-nonfree-6_4 +void-repo-nonfree-9_6 +vscode-1.100.2_1 +vulkan-loader-1.4.313.0_1 +vulkan-loader-devel-1.4.313.0_1 +wayland-devel-1.23.1_1 +webrtc-audio-processing-devel-1.3_1 +wev-1.0.0_2 +wget-1.25.0_1 +whois-5.6.2_1 +wine-10.11_1 +wine-32bit-10.11_1 +wine-common-10.11_1 +wine-mono-10.1.0_1 +wine-tools-10.11_1 +winetricks-20250102_1 +wl-clipboard-2.2.1_1 +wlroots-0.17_1 +wmenu-0.2.0_1 +wpa-cute-0.8.6_1 +xarchiver-0.5.4.25_1 +xcompmgr-1.1.10_1 +xdg-desktop-portal-1.20.3_1 +xdg-desktop-portal-gtk-1.15.3_1 +xdg-desktop-portal-wlr-0.7.1_1 +xdg-user-dirs-0.18_1 +xdg-user-dirs-gtk-0.14_1 +xf86-video-amdgpu-23.0.0_1 +xfconf-4.20.0_1 +xkb-switch-1.6.0_1 +xonotic-0.8.6_4 +xorg-7.6_6 +yt-dlp-2025.06.30_1 +zip-3.0_6 +zsh-5.9_3 diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..09a8450 Binary files /dev/null and b/screenshot.png differ diff --git a/sway/brightness.sh b/sway/brightness.sh new file mode 100755 index 0000000..c6ab6d9 --- /dev/null +++ b/sway/brightness.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +now_delta="$(brightnessctl get)" +delta="$(python -c "print(max(0, min(255, $now_delta + int($1 / 100 * 255))))")" +iter="$(python -c "print(-1 if $1 < 0 else 1)")" + +for i in $(seq $now_delta $iter $delta) +do + if [ $iter == -1 && $(brightnessctl get) < $i ] + then + break + fi + + if [ $iter == 1 && $(brightnessctl get) > $i ] + then + break + fi + + brightnessctl set $i + sleep 0.01s +done diff --git a/sway/config b/sway/config new file mode 100644 index 0000000..15480f8 --- /dev/null +++ b/sway/config @@ -0,0 +1,355 @@ +# Default config for sway +# +# Copy this to ~/.config/sway/config and edit it to your liking. +# +# Read `man 5 sway` for a complete reference. + +### Variables +# +# Logo key. Use Mod1 for Alt. +set $mod Mod4 +# Home row direction keys, like vim +set $left h +set $down j +set $up k +set $right l +# Your preferred terminal emulator +set $term kitty +# Your preferred application launcher +set $menu dmenu_run + +set $bindsym bindsym --to-code + +### Output configuration +# +# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/) +# output * bg /home/user/Pictures/bg.png fill +# +# Example configuration: +# +# output HDMI-A-1 resolution 1920x1080 position 1920,0 +# +# You can get the names of your outputs by running: swaymsg -t get_outputs + +### Idle configuration +# +# Example configuration: +# +exec ~/.config/sway/idle.sh + + +# $bindsym $mod+z exec ~/.config/sway/idle.sh +# +# This will lock your screen after 300 seconds of inactivity, then turn off +# your displays after another 300 seconds, and turn your screens back on when +# resumed. It will also lock your screen before your computer goes to sleep. + +### Input configuration +# +# Example configuration: +# +# CHANGE TOUCHPAD ID HERE (get identifiers: swaymsg -t get_inputs) +input "2362:597:HTIX5288:00_093A:0255_Touchpad" { + dwt disabled + tap enabled + natural_scroll enabled + middle_emulation enabled + scroll_factor 0.3 + drag_lock disabled +} + + +input type:keyboard { + xkb_layout "us,ru" + xkb_options "grp:alt_caps_toggle" + xkb_numlock enabled +} + +# +# You can get the names of your inputs by running: swaymsg -t get_inputs +# Read `man 5 sway-input` for more information about this section. + +### Key bindings +# +# Basics: +# + # Start a terminal + $bindsym $mod+Return exec $term + + # Kill focused window + $bindsym $mod+Shift+q kill + + # Start your launcher + $bindsym $mod+d exec $menu + + # Drag floating windows by holding down $mod and left mouse button. + # Resize them with right mouse button + $mod. + # Despite the name, also works for non-floating windows. + # Change normal to inverse to use left mouse button for resizing and right + # mouse button for dragging. + floating_modifier $mod normal + + # Reload the configuration file + $bindsym $mod+Shift+c reload + # mod+shift+c + + # Exit sway (logs you out of your Wayland session) + $bindsym $mod+Shift+d exit + # mod+shift+d +# +# Moving around: +# + # Move your focus around + $bindsym $mod+$left focus left + # h + $bindsym $mod+$down focus down + # j + $bindsym $mod+$up focus up + # k + $bindsym $mod+$right focus right + # l + # Or use $mod+[up|down|left|right] + $bindsym $mod+Left focus left + $bindsym $mod+Down focus down + $bindsym $mod+Up focus up + $bindsym $mod+Right focus right + + # Move the focused window with the same, but add Shift + $bindsym $mod+Shift+$left move left + # h + $bindsym $mod+Shift+$down move down + # j + $bindsym $mod+Shift+$up move up + # k + $bindsym $mod+Shift+$right move right + # l + # Ditto, with arrow keys + $bindsym $mod+Shift+Left move left + $bindsym $mod+Shift+Down move down + $bindsym $mod+Shift+Up move up + $bindsym $mod+Shift+Right move right + focus_follows_mouse no + + $bindsym $mod+Shift+s sticky toggle +# +# Workspaces: +# + # Switch to workspace + $bindsym $mod+1 workspace number 1 + $bindsym $mod+2 workspace number 2 + $bindsym $mod+3 workspace number 3 + $bindsym $mod+4 workspace number 4 + $bindsym $mod+5 workspace number 5 + $bindsym $mod+6 workspace number 6 + $bindsym $mod+7 workspace number 7 + $bindsym $mod+8 workspace number 8 + $bindsym $mod+9 workspace number 9 + $bindsym $mod+0 workspace number 10 + # Move focused container to workspace + $bindsym $mod+Shift+1 move container to workspace number 1 + $bindsym $mod+Shift+2 move container to workspace number 2 + $bindsym $mod+Shift+3 move container to workspace number 3 + $bindsym $mod+Shift+4 move container to workspace number 4 + $bindsym $mod+Shift+5 move container to workspace number 5 + $bindsym $mod+Shift+6 move container to workspace number 6 + $bindsym $mod+Shift+7 move container to workspace number 7 + $bindsym $mod+Shift+8 move container to workspace number 8 + $bindsym $mod+Shift+9 move container to workspace number 9 + $bindsym $mod+Shift+0 move container to workspace number 10 + # Note: workspaces can have any name you want, not just numbers. + # We just use 1-10 as the default. +# +# Layout stuff: +# + # You can "split" the current object of your focus with + # $mod+b or $mod+v, for horizontal and vertical splits + # respectively. + $bindsym $mod+b splith + # mod+b + $bindsym $mod+v splitv + # mod+v + + # Switch the current container between different layout styles + $bindsym $mod+s layout stacking + # mod+s + $bindsym $mod+w layout tabbed + # mod+w + $bindsym $mod+e layout toggle split + # mod+e + + # Make the current focus fullscreen + $bindsym $mod+f fullscreen + # mod+f + + # Toggle the current focus between tiling and floating mode + $bindsym $mod+Shift+space floating toggle + + # Swap focus between the tiling area and the floating area + $bindsym $mod+space focus mode_toggle + + # Move focus to the parent container + $bindsym $mod+a focus parent + # mod+a +# +# Scratchpad: +# + # Sway has a "scratchpad", which is a bag of holding for windows. + # You can send windows there and get them back later. + + # Move the currently focused window to the scratchpad + $bindsym $mod+Shift+minus move scratchpad + + # Show the next scratchpad window or hide the focused scratchpad window. + # If there are multiple scratchpad windows, this command cycles through them. + $bindsym $mod+minus scratchpad show + + $bindsym $mod+g exec "$HOME/.config/sway/random-bg.py onetime" + +# +# Resizing containers: +# +mode "resize" { + # left will shrink the containers width + # right will grow the containers width + # up will shrink the containers height + # down will grow the containers height + $bindsym $left resize shrink width 10px + $bindsym $down resize grow height 10px + $bindsym $up resize shrink height 10px + $bindsym $right resize grow width 10px + + # Ditto, with arrow keys + $bindsym Left resize shrink width 10px + $bindsym Down resize grow height 10px + $bindsym Up resize shrink height 10px + $bindsym Right resize grow width 10px + + # Return to default mode + $bindsym Return mode "default" + $bindsym Escape mode "default" +} +$bindsym $mod+r mode "resize" + # mod+r +# +# Utilities: +# + # Special keys to adjust volume via PulseAudio + $bindsym --locked XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle + $bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% + $bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% + $bindsym --locked XF86AudioMicMute exec pactl set-source-mute @DEFAULT_SOURCE@ toggle + # Special keys to adjust brightness via brightnessctl + $bindsym --locked XF86MonBrightnessDown exec $HOME/.config/sway/brightness.sh -5 + $bindsym --locked XF86MonBrightnessUp exec $HOME/.config/sway/brightness.sh +5 + # Special key to take a screenshot with grim + # + # $bindsym XF86Sleep exec swaylock -f -c 000000 + + $bindsym $mod+n exec thunar + # mod+n + $bindsym Print exec slurp | grim -g - - | swappy -f - + $bindsym $mod+Print exec slurp | grim -g - - | feh --auto-zoom --scale-down - + $bindsym Shift+Print exec grim - | swappy -f - + $bindsym $mod+c exec copyq toggle + $bindsym $mod+o exec gnome-calculator + $bindsym $mod+i exec chromium + $bindsym $mod+z exec woomer + # https://github.com/coffeeispower/woomer + # mod+c + $bindsym $mod+Shift+g exec bash -c "cd $HOME/Source/touchpaddraw && ./toggle.sh touchpad" + +# +# Status Bar: +# +# Read `man 5 sway-bar` for more information about this section. +bar { + swaybar_command waybar + # position top + + # When the status_command prints a new line to stdout, swaybar updates. + # The default just shows the current date and time. + # status_command i3blocks + + # colors { + # statusline #ffffff + # background #323232 + # inactive_workspace #32323200 #32323200 #5c5c5c + # } +} + +set { + $ii inhibit_idle focus + $game inhibit_idle focus; floating enable; border none; fullscreen enable; shadows disable + $popup floating enable; border pixel 1; sticky enable; shadows enable + $float floating enable; border pixel 1; shadows enable + $video inhibit_idle fullscreen; border none; max_render_time off + $important inhibit_idle open; floating enable; border pixel 1 + $max inhibit_idle visible; floating enable; sticky enable; border pixel 1 +} + +for_window { +#popup - floating enable; sticky enable + [app_id="org.kde.kcalc"] $popup + [app_id="dunst"] $popup + [app_id="com.github.hluk.copyq"] $popup + [class="feh"] $popup + [class="Gnome-power-statistics"] $popup + [title="Picture-in-Picture"] $popup + [title="Picture in picture"] $popup + [app_id="stoken-gui"] $popup + [app_id="org.twosheds.iwgtk"] $popup + [app_id="iwgtk"] $popup + [app_id="ksysguard"] $popup + [app_id="net.nokyan.Resources"] $popup + [app_id="galculator"] $popup + [title="(?:Open|Save) (?:File|Folder|As)" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $popup + [title="^(File|Folder)\s*Already Exists\s*—\s*" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $popup + [title="Confirm to replace files" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $popup + [app_id="pavucontrol"] $popup + [class="wpaCute"] $popup + [app_id="qtalarm"] $popup + [app_id="blueman-manager"] $popup + [app_id="deluge" title="Add Torrents*"] $popup + [app_id="org.telegram.desktop"] border none; shadows enable + +#float - floating enable; border pixel 1 + [window_role="pop-up,task_dialog,About"] $float; shadows enable + [window_type="dialog"] $float; shadows enable + [window_type="utility"] $float; shadows enable + [window_type="toolbar"] $float; shadows enable + [window_type="splash"] $float; shadows enable + [window_type="menu"] $float; shadows enable + [window_type="dropdown_menu"] $float; shadows enable + [window_type="popup_menu"] $float; shadows enable + [window_type="tooltip"] $float; shadows enable + [window_type="notification"] $float; shadows enable + [class="bRAC"] $float + +#video - inhibit_idle fullscreen; border none; max_render_time off + [instance="chromium"] $video + [app_id="mpv"] $video + [app_id="vlc"] $video + [class="firefox"] $video + [app_id="firefox"] $video + [class="Nightly"] $video + +#important - inhibit_idle open; floating enable; border pixel 1 + [title="Move files" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $important + [title="^(Copying|Moving)\s*—\s*Dolphin" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $important + [title="^Extracting\s" app_id="(dolphin|org.kde.ark)"] $important + [title="Copy Files" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $important + [title="Delete Files" app_id="dolphin|org.kde.ark|pcmanfm|pcmanfm-qt"] $important + [title="Removable medium is inserted" app_id="pcmanfm|pcmanfm-qt"] $important + [title="Compressing (.*) — Ark" app_id="org.kde.ark"] $important; resize set width 18 ppt + + [app_id="org.gnome.clocks"] floating enable + [app_id="org.gnome.Calculator"] floating enable +} + +# bindsym XF86AudioRaiseVolume exec amixer -q -D pulse sset Master 5%+ +# bindsym XF86AudioLowerVolume exec amixer -q -D pulse sset Master 5%- && pkill -RTMIN+1 i3blocks +# bindsym XF86AudioMute exec amixer -q -D pulse sset Master toggle && pkill -RTMIN+1 i3blocks + +exec "$HOME/.config/sway/startup.sh" + +include /etc/sway/config.d/* diff --git a/sway/idle.sh b/sway/idle.sh new file mode 100755 index 0000000..7e0e2c2 --- /dev/null +++ b/sway/idle.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +LOCK_CMD="swaylock -f --color 000000" + +swayidle -w \ + timeout 600 "$LOCK_CMD" \ + timeout 1200 'sudo zzz' \ + before-sleep "$LOCK_CMD" \ + diff --git a/sway/random-bg.py b/sway/random-bg.py new file mode 100755 index 0000000..a59262d --- /dev/null +++ b/sway/random-bg.py @@ -0,0 +1,72 @@ +#!/usr/bin/python + +import random +import time +import subprocess +import threading +import sys +import os +import psutil + +WALLPAPERS_DIR = os.path.join(os.path.dirname(__file__), "wallpapers/") +INTERVAL_SECONDS = 60 * 10 + +def get_wallpapers(): + return [os.path.join(WALLPAPERS_DIR, i) for i in os.listdir(WALLPAPERS_DIR)] + +def get_random_wallpaper(): + return random.choice(get_wallpapers()) + +def create_wallpaper_process(path): + process = subprocess.Popen( + ["swaybg", "-m", "fill", "-i", path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + return process + +def send_wallpaper(path, interval): + process = create_wallpaper_process(path) + time.sleep(1) + kill_old_processes(process.pid) + time.sleep(interval-1) + process.kill() + +def kill_old_processes(new_pid): + for proc in psutil.process_iter(): + if proc.pid != new_pid and proc.name() == "swaybg": + print(proc.name(), proc.pid) + proc.kill() + +def main(): + args = sys.argv[1:] + + if len(args) == 1: + if args[0] == "loop": + while True: + wallpapers = get_wallpapers() + random.shuffle(wallpapers) + + for wallpaper in wallpapers: + thread = threading.Thread( + target = lambda: send_wallpaper( + wallpaper, + INTERVAL_SECONDS + 1 + ) + ) + thread.start() + time.sleep(INTERVAL_SECONDS) + return + elif args[0] == "onetime": + process = create_wallpaper_process(get_random_wallpaper()) + while process.stdout.read() not in "1234567890-:_": + time.sleep(1/60) + if process.poll() is None: + kill_old_processes(process.pid) + process.wait() + return + + print("Usage:", sys.argv[0], "") + +if __name__ == "__main__": + main() diff --git a/sway/startup.sh b/sway/startup.sh new file mode 100755 index 0000000..2d3dfcc --- /dev/null +++ b/sway/startup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +dunst & +copyq & +blueman-applet & +~/.config/sway/random-bg.py loop & +~/.startup & + +wait diff --git a/sway/wallpapers/1086198.png b/sway/wallpapers/1086198.png new file mode 100755 index 0000000..1f2d8a1 Binary files /dev/null and b/sway/wallpapers/1086198.png differ diff --git a/sway/wallpapers/108764.jpg b/sway/wallpapers/108764.jpg new file mode 100755 index 0000000..956e0f8 Binary files /dev/null and b/sway/wallpapers/108764.jpg differ diff --git a/sway/wallpapers/110811.jpg b/sway/wallpapers/110811.jpg new file mode 100755 index 0000000..022f847 Binary files /dev/null and b/sway/wallpapers/110811.jpg differ diff --git a/sway/wallpapers/113424.jpg b/sway/wallpapers/113424.jpg new file mode 100755 index 0000000..2d50d80 Binary files /dev/null and b/sway/wallpapers/113424.jpg differ diff --git a/sway/wallpapers/1270543.jpg b/sway/wallpapers/1270543.jpg new file mode 100755 index 0000000..9cdf02e Binary files /dev/null and b/sway/wallpapers/1270543.jpg differ diff --git a/sway/wallpapers/1289103.jpg b/sway/wallpapers/1289103.jpg new file mode 100755 index 0000000..9ea5d7e Binary files /dev/null and b/sway/wallpapers/1289103.jpg differ diff --git a/sway/wallpapers/18208.jpg b/sway/wallpapers/18208.jpg new file mode 100755 index 0000000..a41691f Binary files /dev/null and b/sway/wallpapers/18208.jpg differ diff --git a/sway/wallpapers/705791.png b/sway/wallpapers/705791.png new file mode 100755 index 0000000..a9d6d14 Binary files /dev/null and b/sway/wallpapers/705791.png differ diff --git a/sway/wallpapers/722359.png b/sway/wallpapers/722359.png new file mode 100755 index 0000000..9be6910 Binary files /dev/null and b/sway/wallpapers/722359.png differ diff --git a/sway/wallpapers/969569.jpg b/sway/wallpapers/969569.jpg new file mode 100755 index 0000000..fc29c08 Binary files /dev/null and b/sway/wallpapers/969569.jpg differ diff --git a/sway/wallpapers/997285.jpg b/sway/wallpapers/997285.jpg new file mode 100755 index 0000000..72dfb97 Binary files /dev/null and b/sway/wallpapers/997285.jpg differ diff --git a/sway/wallpapers/snapedit_1740823344276.png b/sway/wallpapers/snapedit_1740823344276.png new file mode 100755 index 0000000..55a4d47 Binary files /dev/null and b/sway/wallpapers/snapedit_1740823344276.png differ diff --git a/sway/wallpapers/void-anime-wallpaper.jpg b/sway/wallpapers/void-anime-wallpaper.jpg new file mode 100644 index 0000000..d1b48ff Binary files /dev/null and b/sway/wallpapers/void-anime-wallpaper.jpg differ diff --git a/sway/wallpapers/Без имени.jpg b/sway/wallpapers/Без имени.jpg new file mode 100755 index 0000000..0b8d76f Binary files /dev/null and b/sway/wallpapers/Без имени.jpg differ diff --git a/waybar/config.jsonc b/waybar/config.jsonc new file mode 100644 index 0000000..2b6c17e --- /dev/null +++ b/waybar/config.jsonc @@ -0,0 +1,225 @@ +// ============================================================================= +// +// Waybar configuration +// +// Configuration reference: https://github.com/Alexays/Waybar/wiki/Configuration +// +// ============================================================================= +{ + // ------------------------------------------------------------------------- + // Global configuration + // ------------------------------------------------------------------------- + "layer": "top", + "position": "top", + // If height property would be not present, it'd be calculated dynamically + "height": 23, + "modules-left": [ + "sway/workspaces", + "sway/scratchpad", + "sway/mode", + "sway/window" + ], + "modules-right": [ + "tray", + "custom/keyboard-layout", + "backlight", + //"keyboard-state", + // "bluetooth", + "pulseaudio", + "network", + "memory", + "cpu", + // "temperature", + // "custom/keyboard-layout", + "battery", + // "battery#bat2", + // "pulseaudio", + // "tray", + "clock#date", + "clock#time", + "custom/power" + ], + // ------------------------------------------------------------------------- + // Modules + // ------------------------------------------------------------------------- + "backlight": { + "device": "amdgpu_bl0", + "format": "{percent}% {icon}", + "format-icons": [ + "🌑", + "🌘", + "🌗", + "🌖", + "🌕" + ] + }, + "keyboard-state": { + "numlock": true, + "capslock": false, + "format": { + "numlock": "{icon} ", + "capslock": "{icon} " + }, + "format-icons": { + "locked": "󰎠", + "unlocked": "󱧓" + } + }, + "bluetooth": { + "format": " {status}", + "format-connected": " {device_alias}", + "format-connected-battery": " {device_alias} {device_battery_percentage}%", + // "format-device-preference": [ "device1", "device2" ], // preference list deciding the displayed device + "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected", + "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}", + "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}", + "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%" + }, + "battery": { + "interval": 10, + "states": { + "warning": 30, + "critical": 15 + }, + // Connected to AC + "format": " {capacity}%", // Icon: bolt + // Not connected to AC + "format-discharging": "{icon} {capacity}%", + "format-icons": [ + "", // Icon: battery-full + "", // Icon: battery-three-quarters + "", // Icon: battery-half + "", // Icon: battery-quarter + "" // Icon: battery-empty + ], + "format-alt": "{time} {icon}", + "tooltip": true, + "on-click": "gnome-power-statistics" + }, + // "battery#bat2": { + // "bat": "BAT2" + // }, + "clock#time": { + "interval": 1, + "format": "{:%H:%M:%S}", + "tooltip": false, + "on-click": "gnome-clocks" + }, + "clock#date": { + "interval": 10, + "format": " {:%e %b %Y}", // Icon: calendar-alt + "tooltip-format": "{calendar}", + "locale": "ru_RU.UTF-8", + "calendar": { + "format": { + "today": "{}" + } + } + }, + "cpu": { + "interval": 5, + "format": " {usage}% ({load})", // Icon: microchip + "states": { + "warning": 70, + "critical": 90 + } + }, + "custom/keyboard-layout": { + "exec": "swaymsg -t get_inputs | grep -m1 'xkb_active_layout_name' | cut -d '\"' -f4", + // Interval set only as a fallback, as the value is updated by signal + "interval": 1, + "format": " {}", // Icon: keyboard + // Signal sent by Sway key binding (~/.config/sway/key-bindings) + "signal": 1, // SIGHUP + "tooltip": false + // "locale": "ru_RU.UTF-8" + }, + "memory": { + "interval": 5, + "format": "\uefc5 {}%", // Icon: memory + "states": { + "warning": 70, + "critical": 90 + } + }, + "network": { + "interval": 5, + "format-wifi": " {essid} ({signalStrength}%)", // Icon: wifi + "format-ethernet": "\udb80\ude00 {ifname}: {ipaddr}/{cidr}", // Icon: ethernet + "format-disconnected": "⚠ Disconnected", + "tooltip-format": "{ifname}: {ipaddr}", + "on-click": "tail -n+3 /proc/net/wireless | grep -q . && wpa-cute" + }, + "sway/mode": { + "format": "\udb85\udc0e {}", // Icon: expand-arrows-alt + "tooltip": false + }, + "sway/window": { + "format": "{}", + "max-length": 120 + }, + "sway/scratchpad": { + "format": "{icon} {count}", + "show-empty": false, + "format-icons": [ + "", + "" + ], + "tooltip": true, + "tooltip-format": "{app}: {title}", + "on-click": "swaymsg scratchpad show" + }, + "sway/workspaces": { + "all-outputs": false, + "disable-scroll": true, + "format": "{icon}" + }, + "pulseaudio": { + //"scroll-step": 1, + "format": "{icon} {volume}%", + "format-bluetooth": "{icon}  {volume}%", + "format-muted": "", + "format-icons": { + "headphones": "", + "handsfree": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": [ + "", + "" + ] + }, + "on-click": "pavucontrol" + }, + "temperature": { + "critical-threshold": 80, + "interval": 5, + "format": "{icon} {temperatureC}°C", + "format-icons": [ + "", // Icon: temperature-empty + "", // Icon: temperature-quarter + "", // Icon: temperature-half + "", // Icon: temperature-three-quarters + "" // Icon: temperature-full + ], + "tooltip": true + }, + "tray": { + "icon-size": 21, + "spacing": 10 + }, + "custom/power": { + "format": "⏻ ", + "tooltip": false, + "menu": "on-click", + "menu-file": "$HOME/.config/waybar/power_menu.xml", // Menu file in resources folder + "menu-actions": { + "shutdown": "loginctl poweroff", + "reboot": "loginctl reboot", + "suspend": "loginctl suspend", + "hibernate": "loginctl hibernate" + } + } +} \ No newline at end of file diff --git a/waybar/power_menu.xml b/waybar/power_menu.xml new file mode 100644 index 0000000..aa2a42c --- /dev/null +++ b/waybar/power_menu.xml @@ -0,0 +1,28 @@ + + + + + + Suspend + + + + + Hibernate + + + + + Shutdown + + + + + + + + Reboot + + + + diff --git a/waybar/style.css b/waybar/style.css new file mode 100644 index 0000000..bc3d9fb --- /dev/null +++ b/waybar/style.css @@ -0,0 +1,244 @@ +/* ============================================================================= + * + * Waybar configuration + * + * Configuration reference: https://github.com/Alexays/Waybar/wiki/Configuration + * + * =========================================================================== */ + +/* ----------------------------------------------------------------------------- + * Keyframes + * -------------------------------------------------------------------------- */ + +@keyframes blink-warning { + 70% { + color: white; + } + + to { + color: white; + background-color: orange; + } +} + +@keyframes blink-critical { + 70% { + color: white; + } + + to { + color: white; + background-color: red; + } +} + + +/* ----------------------------------------------------------------------------- + * Base styles + * -------------------------------------------------------------------------- */ + +/* Reset all styles */ +* { + border: none; + border-radius: 0; + min-height: 0; + margin: 0; + padding: 0; +} + +/* The whole bar */ +#waybar { + background: rgba(25, 25, 25, 0.75); + /*filter: blur(10px);*/ + color: white; + font-family: UbuntuMono Nerd Font; + font-size: 15px; +} + +/* Each module */ +#battery, +#clock, +#cpu, +#custom-keyboard-layout, +#keyboard-state, +#memory, +#mode, +#network, +#pulseaudio, +#temperature, +#backlight, +#tray { + margin: 0 5px; + padding-left: 5px; + padding-right: 5px; +} + +#custom-power { + padding-right: 5px; + padding-left: 5px; + margin-left: 5px; +} + +#battery, +#clock, +#cpu, +#custom-keyboard-layout, +#memory, +#mode, +#keyboard-state, +#network, +#pulseaudio, +#backlight, +#temperature { + box-shadow: inset 0 3px #ddd; +} + +/* ----------------------------------------------------------------------------- + * Module styles + * -------------------------------------------------------------------------- */ + +#battery { + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#battery.warning { + color: orange; +} + +#battery.critical { + color: red; +} + +#battery.warning.discharging { + animation-name: blink-warning; + animation-duration: 3s; +} + +#battery.critical.discharging { + animation-name: blink-critical; + animation-duration: 2s; +} + +#clock { + font-weight: bold; +} + +#cpu { + /* No styles */ +} + +#cpu.warning { + color: orange; +} + +#cpu.critical { + color: red; +} + +#memory { + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#memory.warning { + color: orange; +} + +#memory.critical { + color: red; + animation-name: blink-critical; + animation-duration: 2s; +} + +#mode { + background: #64727D; + border-top: 2px solid white; + /* To compensate for the top border and still have vertical centering */ + padding-bottom: 2px; +} + +#network { + /* No styles */ +} + +#network.disconnected { + color: orange; +} + +#pulseaudio { + /* No styles */ +} + +#pulseaudio.muted { + /* No styles */ +} + +#custom-spotify { + color: rgb(102, 220, 105); +} + +#temperature { + /* No styles */ +} + +#temperature.critical { + color: red; +} + +#tray { + /* No styles */ +} + +#window { + font-weight: bold; + margin-left: 10px; +} + +#scratchpad { + box-shadow: inset 0 3px #ddd; + padding-bottom: 2px; + padding-left: 5px; + padding-right: 5px; + padding-top: 2px; + padding-bottom: 0; + color: white; + background-color: #888888; +} + +#workspaces button { + padding: 0 5px; + background-color: transparent; + color: #ffffff; + transition: box-shadow 0.1s, font-weight 0.1s; +} + +#workspaces button:hover { + box-shadow: none; /* Remove predefined box-shadow */ + text-shadow: none; /* Remove predefined text-shadow */ + background: none; /* Remove predefined background color (white) */ + /* transition: none; Disable predefined animations */ + font-weight: bold; + + box-shadow: inset 0 3px #4c7899; +} + +#workspaces button.focused { + background-color: #285577; + box-shadow: inset 0 3px #4c7899; + transition: box-shadow 0.1s, font-weight 0.1s; + +} + +#workspaces button.urgent { + background-color: #891818; + box-shadow: inset 0 3px #ab2828; + transition: box-shadow 0.1s, font-weight 0.1s; + +} + +#workspaces button.urgent:hover { + box-shadow: inset 0 3px #4c7899; +}