dotfiles

Mahdi's dotfiles
git clone git://mahdi.pw/dotfiles.git
Log | Files | Refs | Submodules | README | LICENSE

commit d01a5382c9abd1def8b014320f9db4d2788aab32
Author: Mahdi Mirzade <[email protected]>
Date:   Sat,  6 Aug 2022 00:30:44 +0430

initial commit

Diffstat:
A.config/Kvantum/kvantum.kvconfig | 5+++++
A.config/fontconfig/fonts.conf | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/git/config | 5+++++
A.config/mbsync/mbsyncrc | 31+++++++++++++++++++++++++++++++
A.config/mpv/input.conf | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mpv/mpv.conf | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mpv/scripts/SmartCopyPaste.lua | 856+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mpv/scripts/mpvSockets.lua | 36++++++++++++++++++++++++++++++++++++
A.config/mutt/alias | 18++++++++++++++++++
A.config/mutt/display | 24++++++++++++++++++++++++
A.config/mutt/mailcap | 15+++++++++++++++
A.config/mutt/muttrc | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mutt/muttrc.bak | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/picom/picom.conf | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/qutebrowser/config.py | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/shell/aliasrc | 37+++++++++++++++++++++++++++++++++++++
A.config/shell/inputrc | 15+++++++++++++++
A.config/shell/profile | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/surf/script.js | 1+
A.config/surf/styles/default.css | 25+++++++++++++++++++++++++
A.config/surf/styles/default.css.in | 25+++++++++++++++++++++++++
A.config/vis/visrc.lua | 50++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/wget/wgetrc | 3+++
A.config/x11/colors | 31+++++++++++++++++++++++++++++++
A.config/x11/fonts | 10++++++++++
A.config/x11/themes/dracula | 20++++++++++++++++++++
A.config/x11/themes/gruvbox-dark | 46++++++++++++++++++++++++++++++++++++++++++++++
A.config/x11/themes/nord | 47+++++++++++++++++++++++++++++++++++++++++++++++
A.config/x11/themes/oceanic-next | 40++++++++++++++++++++++++++++++++++++++++
A.config/x11/themes/onedark | 32++++++++++++++++++++++++++++++++
A.config/x11/themes/solarized-dark | 36++++++++++++++++++++++++++++++++++++
A.config/x11/themes/tomorrownight | 32++++++++++++++++++++++++++++++++
A.config/x11/xinitrc | 48++++++++++++++++++++++++++++++++++++++++++++++++
A.config/x11/xresources | 2++
A.config/yt-dlp/config | 17+++++++++++++++++
A.config/zathura/zathurarc | 41+++++++++++++++++++++++++++++++++++++++++
A.config/zathura/zathurarc.in | 41+++++++++++++++++++++++++++++++++++++++++
A.kshrc | 32++++++++++++++++++++++++++++++++
A.local/bin/bg-gen | 22++++++++++++++++++++++
A.local/bin/bg-set | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/bright | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/dmenu-archwiki | 10++++++++++
A.local/bin/dmenu-askpass | 3+++
A.local/bin/dmenu-emoji | 1831+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/dmenu-fix-sheet | 21+++++++++++++++++++++
A.local/bin/dmenu-man | 3+++
A.local/bin/dmenu-mpd | 41+++++++++++++++++++++++++++++++++++++++++
A.local/bin/dmenu-power | 20++++++++++++++++++++
A.local/bin/dmenu-record | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/doas-askpass | 36++++++++++++++++++++++++++++++++++++
A.local/bin/dwm-bar | 391+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/email | 38++++++++++++++++++++++++++++++++++++++
A.local/bin/ix | 29+++++++++++++++++++++++++++++
A.local/bin/lock | 10++++++++++
A.local/bin/media-controller | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/metch | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/pacman-rm | 6++++++
A.local/bin/pacman-up | 34++++++++++++++++++++++++++++++++++
A.local/bin/screenshot | 47+++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/theme-sel | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/toggle-touch | 16++++++++++++++++
A.local/bin/upload | 34++++++++++++++++++++++++++++++++++
A.local/bin/volume | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/bin/vpn | 11+++++++++++
A.local/bin/webcam | 23+++++++++++++++++++++++
A.local/src/dmenu/LICENSE | 30++++++++++++++++++++++++++++++
A.local/src/dmenu/Makefile | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/README | 24++++++++++++++++++++++++
A.local/src/dmenu/arg.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/config.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/config.mk | 35+++++++++++++++++++++++++++++++++++
A.local/src/dmenu/dmenu | 0
A.local/src/dmenu/dmenu.1 | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/dmenu.c | 1011+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/dmenu.o | 0
A.local/src/dmenu/dmenu_path | 13+++++++++++++
A.local/src/dmenu/dmenu_run | 2++
A.local/src/dmenu/dmenu_run.hist | 50++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/drw.c | 467+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/drw.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/drw.o | 0
A.local/src/dmenu/patches/dmenu-alpha-20210605-1a13d04.diff | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-bidi-20210723-b34d318.diff | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-highlight-20201211-fcdc159.diff | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-linesbelowprompt-and-fullwidth-20211014.diff | 25+++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-password-5.0.diff | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-preselect-20200513-db6093f.diff | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/patches/dmenu-xresources-alt-5.0.diff | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/stest | 0
A.local/src/dmenu/stest.1 | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/stest.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dmenu/stest.o | 0
A.local/src/dmenu/util.c | 35+++++++++++++++++++++++++++++++++++
A.local/src/dmenu/util.h | 8++++++++
A.local/src/dmenu/util.o | 0
A.local/src/dwm/LICENSE | 37+++++++++++++++++++++++++++++++++++++
A.local/src/dwm/Makefile | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/README | 48++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/config.h | 303+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/config.mk | 42++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/drw.c | 437+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/drw.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/drw.o | 0
A.local/src/dwm/dwm | 0
A.local/src/dwm/dwm.1 | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/dwm.c | 3243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/dwm.o | 0
A.local/src/dwm/dwm.png | 0
A.local/src/dwm/patches/accessnthmon.diff | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-actualfullscreen-20211013-cb3f58a.diff | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-attachbottom-20201227-61bb8b2.diff | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-bidi-20220309-0386419.diff | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-centeredwindowname-20200723-f035e1e.diff | 30++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-fullgaps-20200508-7b77734.diff | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-hide_vacant_tags-6.3.diff | 39+++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-movestack-20211115-a786211.diff | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-noborderfloatingfix-6.2.diff | 31+++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-placemouse-6.3.diff | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-rainbowtags-6.2.diff | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-restartsig-20180523-6.2.diff | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-setstatus-6.2.diff | 49+++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-status2d-systray-6.3.diff | 888+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-statusallmons-6.2.diff | 25+++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-sticky-6.1.diff | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-warp-6.2.diff | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/dwm-xrdb-6.2.diff | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/patches/shiftview.c | 19+++++++++++++++++++
A.local/src/dwm/transient.c | 42++++++++++++++++++++++++++++++++++++++++++
A.local/src/dwm/util.c | 35+++++++++++++++++++++++++++++++++++
A.local/src/dwm/util.h | 8++++++++
A.local/src/dwm/util.o | 0
A.local/src/merbe/.gitignore | 3+++
A.local/src/merbe/LICENSE | 22++++++++++++++++++++++
A.local/src/merbe/Makefile | 31+++++++++++++++++++++++++++++++
A.local/src/merbe/README | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/merbe/config.def.h | 19+++++++++++++++++++
A.local/src/merbe/merbe | 0
A.local/src/merbe/merbe.c | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/LICENSE | 24++++++++++++++++++++++++
A.local/src/slock/Makefile | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/README | 24++++++++++++++++++++++++
A.local/src/slock/arg.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/config.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/config.mk | 40++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/explicit_bzero.c | 19+++++++++++++++++++
A.local/src/slock/explicit_bzero.o | 0
A.local/src/slock/patches/slock-dpms-1.4.diff | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/patches/slock-failure-command-1.4.diff | 39+++++++++++++++++++++++++++++++++++++++
A.local/src/slock/patches/slock-foreground-and-background-20210611-35633d4.diff | 340+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/patches/slock-message-xft-20210315-ae681c5.patch | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/patches/slock-xresources-20191126-53e56c7.diff | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/slock | 0
A.local/src/slock/slock.1 | 39+++++++++++++++++++++++++++++++++++++++
A.local/src/slock/slock.c | 627+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/slock/slock.o | 0
A.local/src/slock/util.h | 5+++++
A.local/src/st/FAQ | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/LEGACY | 17+++++++++++++++++
A.local/src/st/LICENSE | 34++++++++++++++++++++++++++++++++++
A.local/src/st/Makefile | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/README | 34++++++++++++++++++++++++++++++++++
A.local/src/st/TODO | 28++++++++++++++++++++++++++++
A.local/src/st/arg.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/config.h | 498+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/config.mk | 35+++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-anysize-0.8.4.diff | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-blinking_cursor-20211116-2f6e597.diff | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-columns-rows-reflow-st-unpatched-new.diff | 1529+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-dynamic-cursor-color-0.8.4.diff | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-externalpipe-0.8.4.diff | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-externalpipe-eternal-0.8.3.diff | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-font2-20190416-ba72400.diff | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-hidecursor-0.8.3.diff | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/patches/st-xresources-signal-reloading-20220312-6685098.diff | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/st | 0
A.local/src/st/st-copyout | 13+++++++++++++
A.local/src/st/st-urlhandler | 19+++++++++++++++++++
A.local/src/st/st.1 | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/st.c | 3183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/st.h | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/st.info | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/st.o | 0
A.local/src/st/win.h | 40++++++++++++++++++++++++++++++++++++++++
A.local/src/st/x.c | 2400+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/st/x.o | 0
A.local/src/surf/FAQ.md | 10++++++++++
A.local/src/surf/LICENSE | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/Makefile | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/README | 40++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/TODO.md | 10++++++++++
A.local/src/surf/arg.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/common.h | 1+
A.local/src/surf/config.h | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/config.mk | 32++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-2.0-externalpipe.diff | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-2.0-homepage.diff | 24++++++++++++++++++++++++
A.local/src/surf/patches/surf-2.1-history.diff | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-bookmarks-20170722-723ff26.diff | 42++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-clipboard-20200112-a6a8878.diff | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-git-20170323-webkit2-searchengines.diff | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/patches/surf-playexternal-20190724-b814567.diff | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/surf | 0
A.local/src/surf/surf-edit-source | 5+++++
A.local/src/surf/surf-link-select | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/surf-open | 19+++++++++++++++++++
A.local/src/surf/surf.1 | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/surf.c | 2288+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/surf.o | 0
A.local/src/surf/surf.png | 0
A.local/src/surf/webext-surf.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/surf/webext-surf.o | 0
A.local/src/surf/webext-surf.so | 0
A.local/src/tabbed/LICENSE | 23+++++++++++++++++++++++
A.local/src/tabbed/Makefile | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/README | 22++++++++++++++++++++++
A.local/src/tabbed/TODO | 4++++
A.local/src/tabbed/arg.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/config.h | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/config.mk | 33+++++++++++++++++++++++++++++++++
A.local/src/tabbed/patches/tabbed-bar-height-0.6.diff | 24++++++++++++++++++++++++
A.local/src/tabbed/patches/tabbed-clientnumber-20160702-bc23614.diff | 23+++++++++++++++++++++++
A.local/src/tabbed/patches/tabbed-hidetabs-20191216-b5f9ec6.diff | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/patches/tabbed-keyrelease-20191216-b5f9ec6.diff | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/patches/tabbed-xresources-20210317-dabf6a2.diff | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/tabbed | 0
A.local/src/tabbed/tabbed.1 | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/tabbed.c | 1512+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/tabbed.o | 0
A.local/src/tabbed/xembed | 0
A.local/src/tabbed/xembed.1 | 35+++++++++++++++++++++++++++++++++++
A.local/src/tabbed/xembed.c | 45+++++++++++++++++++++++++++++++++++++++++++++
A.local/src/tabbed/xembed.o | 0
A.local/src/xwallpaper/.deps/xwallpaper-debug.Po | 28++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-load_jpeg.Po | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-load_png.Po | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-load_xpm.Po | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-main.Po | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-options.Po | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-outputs.Po | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/.deps/xwallpaper-seccomp.Po | 1+
A.local/src/xwallpaper/.deps/xwallpaper-util.Po | 23+++++++++++++++++++++++
A.local/src/xwallpaper/LICENSE | 15+++++++++++++++
A.local/src/xwallpaper/Makefile | 1092+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/Makefile.am | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/Makefile.in | 1092+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/README.md | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/_xwallpaper | 26++++++++++++++++++++++++++
A.local/src/xwallpaper/aclocal.m4 | 1494+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autogen.sh | 11+++++++++++
A.local/src/xwallpaper/autom4te.cache/output.0 | 6843+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/output.1 | 6843+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/output.2 | 6845+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/requests | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/traces.0 | 1229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/traces.1 | 524+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/autom4te.cache/traces.2 | 524+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/compile | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/config.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/config.h.in | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/config.log | 505+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/config.status | 1206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/configure | 6844+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/configure.ac | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/debug.c | 33+++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/depcomp | 791+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/functions.h | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/install-sh | 541+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/load_jpeg.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/load_png.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/load_xpm.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/main.c | 825+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/missing | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/options.c | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/outputs.c | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/seccomp.c | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.local/src/xwallpaper/stamp-h1 | 1+
A.local/src/xwallpaper/util.c | 31+++++++++++++++++++++++++++++++
A.local/src/xwallpaper/xwallpaper | 0
A.local/src/xwallpaper/xwallpaper-debug.o | 0
A.local/src/xwallpaper/xwallpaper-load_jpeg.o | 0
A.local/src/xwallpaper/xwallpaper-load_png.o | 0
A.local/src/xwallpaper/xwallpaper-load_xpm.o | 0
A.local/src/xwallpaper/xwallpaper-main.o | 0
A.local/src/xwallpaper/xwallpaper-options.o | 0
A.local/src/xwallpaper/xwallpaper-outputs.o | 0
A.local/src/xwallpaper/xwallpaper-util.o | 0
A.local/src/xwallpaper/xwallpaper.1 | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.mkshrc | 45+++++++++++++++++++++++++++++++++++++++++++++
A.profile | 30++++++++++++++++++++++++++++++
A.viminfo | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ALICENSE | 21+++++++++++++++++++++
AMakefile | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afreebsd/doas.conf | 2++
Afreebsd/src/dmenu | 1+
Afreebsd/src/dwm | 1+
Afreebsd/src/slock | 1+
Afreebsd/src/st | 1+
Afreebsd/src/surf | 1+
Afreebsd/src/tabbed | 1+
Ainstall | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apkgs-arch.mk | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Apkgs-freebsd.mk | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
305 files changed, 76181 insertions(+), 0 deletions(-)

diff --git a/.config/Kvantum/kvantum.kvconfig b/.config/Kvantum/kvantum.kvconfig @@ -0,0 +1,5 @@ +[General] +theme=KvArcDark + +[Applications] +KvArcDark=QFileDialog, telegram-desktop diff --git a/.config/fontconfig/fonts.conf b/.config/fontconfig/fonts.conf @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> + <match target="font"> + <edit mode="assign" name="antialias"> + <bool>true</bool> + </edit> + <edit mode="assign" name="embeddedbitmap"> + <bool>false</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit mode="assign" name="hinting"> + <bool>true</bool> + </edit> + <edit mode="assign" name="hintstyle"> + <const>hintslight</const> + </edit> + <edit mode="assign" name="lcdfilter"> + <const>lcddefault</const> + </edit> + <edit mode="assign" name="rgba"> + <const>rgb</const> + </edit> + </match> + <alias> + <family>sans</family> + <prefer> + <family>JetBrainsMono Nerd Font Thin</family> + <family>Vazirmatn</family> + <family>Noto Sans CJK JP</family> + <family>Noto Sans CJK KR</family> + <family>Noto Sans CJK HK</family> + <family>Noto Sans CJK SC</family> + <family>Noto Sans CJK TC</family> + <family>Noto Color Emoji</family> + </prefer> + </alias> + <alias> + <family>serif</family> + <prefer> + <family>JetBrainsMono Nerd Font Thin</family> + <family>Vazirmatn</family> + <family>Noto Sans CJK JP</family> + <family>Noto Sans CJK KR</family> + <family>Noto Sans CJK HK</family> + <family>Noto Sans CJK SC</family> + <family>Noto Sans CJK TC</family> + <family>Noto Color Emoji</family> + </prefer> + </alias> + <alias> + <family>sans-serif</family> + <prefer> + <family>JetBrainsMono Nerd Font Thin</family> + <family>Vazirmatn</family> + <family>Noto Sans CJK JP</family> + <family>Noto Sans CJK KR</family> + <family>Noto Sans CJK HK</family> + <family>Noto Sans CJK SC</family> + <family>Noto Sans CJK TC</family> + <family>Noto Color Emoji</family> + </prefer> + </alias> + <alias> + <family>monospace</family> + <prefer> + <family>JetBrainsMono Nerd Font</family> + <family>Vazirmatn</family> + <family>Noto Sans Mono CJK JP</family> + <family>Noto Sans Mono CJK KR</family> + <family>Noto Sans Mono CJK HK</family> + <family>Noto Sans Mono CJK SC</family> + <family>Noto Sans Mono CJK TC</family> + <family>Noto Color Emoji</family> + </prefer> + </alias> +</fontconfig> diff --git a/.config/git/config b/.config/git/config @@ -0,0 +1,5 @@ +[user] + name = Mahdi Mirzade + email = [email protected] +[init] + defaultBranch = master diff --git a/.config/mbsync/mbsyncrc b/.config/mbsync/mbsyncrc @@ -0,0 +1,31 @@ +IMAPAccount acct0 +Host mail.mahdi.pw +User me +# Pass "This is my secure password" +PassCmd "pass email" +# Use SSL +SSLType IMAPS +SSLVersions TLSv1.2 +AuthMechs LOGIN +PipelineDepth 50 + +IMAPStore acct0-remote +Account acct0 + +MaildirStore acct0-local +Subfolders Verbatim +# The trailing "/" is important +Path ~/.local/share/mail/acct0/ +Inbox ~/.local/share/mail/acct0/Inbox + +Channel acct0 +Far :acct0-remote: +Near :acct0-local: +# Include everything +Patterns * +# Automatically create missing mailboxes, both locally and on the server +Create Both +# Sync the movement of messages between folders and deletions, add after making sure the sync works +Expunge Both +# Save the synchronization state files in the relevant directory +SyncState * diff --git a/.config/mpv/input.conf b/.config/mpv/input.conf @@ -0,0 +1,71 @@ +# Main reference: +# https://mpv.io/manual/master/#command-interface + +# Rebind +. cycle-values loop-file inf no +a cycle audio +s cycle sub +Shift+a cycle audio down +Shift+s cycle sub down +Ctrl+s screenshot video # without subtitles +Ctrl+Shift+s screenshot # with subtitles + +# Volume controls +k add volume 5 +j add volume -5 +UP add volume 5 +DOWN add volume -5 + +# Position Seeking +l seek 5 +h seek -5 +RIGHT seek 5 +LEFT seek -5 + +# 2x volume controls +Shift+k add volume 10 +Shift+j add volume -10 +Shift+UP add volume 10 +Shift+DOWN add volume -10 + +# 6x Position Seeking +Shift+l seek 30 +Shift+h seek -30 +Shift+RIGHT seek 30 +Shift+LEFT seek -30 + +# Define Ctrl+[/] to rotate video +Ctrl+[ add video-rotate 90 +Ctrl+] add video-rotate -90 + +# Define Alt+=/- to zoom in / zoom out +Alt+= add video-zoom 0.25 +Alt+- add video-zoom -0.25 + +# Reset zooming with Alt+Backspace +Alt+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 + +# ------------------------------------------------------------------------ +# Scripts +# - Copy the full path of the current file +Ctrl+d run "/bin/sh" "-c" "(choice=`printf 'Yes\nNo' | dmenu -p \"Delete \\\"${path}\\\"?\"` && [ $choice = 'Yes' ] && rm \"$PWD/${path}\" && dunstify \"MPV\" \"Removed \\\"$PWD/${path}\\\".\")" + +# - Copy the full path of the current file +Ctrl+c run "/bin/sh" "-c" "echo $PWD/${path} | xclip -selection c" + +# - Copy only the name of the file +Ctrl+Shift+c run "/bin/sh" "-c" "echo ${path} | xclip -selection c" + +# ------------------------------------------------------------------------ +# Mouse controls +# - Define mouse scrolling to change volume +WHEEL_UP add volume 5 +WHEEL_DOWN add volume -5 + +# - Define mouse scrolling to change position +WHEEL_RIGHT seek 5 +WHEEL_LEFT seek -5 + +# - Define Shift+Mouse-Scrolling to move 5s +Shift+WHEEL_UP seek 5 +Shift+WHEEL_DOWN seek -5 diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf @@ -0,0 +1,81 @@ +# Main reference: +# https://mpv.io/manual/master/ + +# youtube-dl video quality configuration +ytdl-format=bestvideo[height<=480]+bestaudio/best[height<=480] +#ytdl-format=bestvideo[height<=720]+bestaudio/best[height<=720] +#ytdl-format=bestvideo[height<=1080]+bestaudio/best[height<=1080] +#ytdl-format=bestvideo[height<=2160]+bestaudio/best[height<=2160] + +# Start in fullscreen mode by default. +fs=yes + +# force starting with centered window +geometry=40%:60% + +# don't allow a new window to have a size larger than 90% of the screen size +autofit-larger=60%x60% + +# Do not close the window on exit. +#keep-open=yes + +# Do not wait with showing the video window until it has loaded. (This will +# resize the window once video is loaded. Also always shows a window with +# audio.) +#force-window=immediate + +# Disable the On Screen Controller (OSC). +#osc=no + +# Keep the player window on top of all other windows. +#ontop=yes + +# Enable hardware decoding if available. +hwdec=no +#hwdec=auto + +# Pretend to be a web browser. Might fix playback with some streaming sites, +# but also will break with shoutcast streams. +user-agent="Mozilla/5.0" + +# Enable fuzzy searching for subtitles. +sub-auto=fuzzy + +# Display English subtitles if available. +slang=en,en-GB,en-US,eng,english + +# Play Farsi audio if available, fall back to English otherwise. +#alang=fa,en + +# Set max volume to 100% +volume-max=150 +volume=75 + +# Change title to filename instead of media-title +#title='${filename} - mpv' +#script-opts='osc-title=${filename}' + +# Save video's volume amount and position +# It's when you quit mpv without killing the instance (not working with Shift+Q) +save-position-on-quit + +# Adjusting the window size for music. +[extension.mp3] +video=no +geometry=250x250 + +# If webm file is selected, playback forever. +[extension.webm] +loop-file=inf + +# If gif file is selected, playback forever. +[extension.gif] +loop-file=inf + +# If image is selected, keep it forever. +image-display-duration=inf + +# Misc +## youtube-dl subtitle configuration (non-auto-generated subtitles) +## Swith to yt-dlp +script-opts=ytdl-all-subs,ytdl_hook-ytdl_path=yt-dlp diff --git a/.config/mpv/scripts/SmartCopyPaste.lua b/.config/mpv/scripts/SmartCopyPaste.lua @@ -0,0 +1,856 @@ +-- Copyright (c) 2022, Eisa AlAwadhi +-- License: BSD 2-Clause License +-- Creator: Eisa AlAwadhi +-- Project: SmartCopyPaste +-- Version: 3.1 + +local o = { +---------------------------USER CUSTOMIZATION SETTINGS--------------------------- +--These settings are for users to manually change some options. +--Changes are recommended to be made in the script-opts directory. + + -----Script Settings---- + device = 'auto', --'auto' is for automatic device detection, or manually change to: 'windows' or 'mac' or 'linux' + linux_copy = 'xclip -silent -selection clipboard -in', --copy command that will be used in Linux. OR write a different command + linux_paste = 'xclip -selection clipboard -o', --paste command that will be used in Linux. OR write a different command + mac_copy = 'pbcopy', --copy command that will be used in MAC. OR write a different command + mac_paste = 'pbpaste', --paste command that will be used in MAC. OR write a different command + windows_copy = 'powershell', --'powershell' is for using windows powershell to copy. OR write the copy command, e.g: ' clip' + windows_paste = 'powershell', --'powershell' is for using windows powershell to paste. OR write the paste command + resume_offset = -0.65, --change to 0 so item resumes from the exact position, or decrease the value so that it gives you a little preview before loading the resume point + osd_messages = true, --true is for displaying osd messages when actions occur. Change to false will disable all osd messages generated from this script + time_seperator = ' 🕒 ', --Time seperator that will be shown before the saved time in osd messages + prefer_filename_over_title = 'local', --Prefers to copy filename over filetitle. Select between 'local', 'protocols', 'all', and 'none'. 'local' prefer filenames for videos that are not protocols. 'protocols' will prefer filenames for protocols only. 'all' will prefer filename over filetitle for both protocols and not protocols videos. 'none' will always use filetitle instead of filename + copy_time_method = 'all', --Option to copy time with video, 'none' for disabled, 'all' to copy time for all videos, 'protocols' for copying time only for protocols, 'specifics' to copy time only for websites defined below, 'local' to copy time for videos that are not protocols + specific_time_attributes=[[ + [ ["twitter", "?t=", ""], ["twitch", "?t=", "s"], ["youtube", "&t=", "s"] ] + ]], --The time attributes which will be added when copying protocols of specific websites from this list. Additional attributes can be added following the same format. + protocols_time_attribute = '&t=', --The text that will be copied before the seek time when copying a protocol video from mpv + local_time_attribute = '&time=', --The text that will be copied before the seek time when copying a local video from mpv + pastable_time_attributes=[[ + [" | time="] + ]], --The time attributes that can be pasted for resume, specific_time_attributes, protocols_time_attribute, local_time_attribute are automatically added + copy_keybind=[[ + ["ctrl+c", "ctrl+C", "meta+c", "meta+C"] + ]], --Keybind that will be used to copy + running_paste_behavior = 'playlist', --The priority of paste behavior when a video is running. select between 'playlist', 'timestamp', 'force'. + paste_keybind=[[ + ["ctrl+v", "ctrl+V", "meta+v", "meta+V"] + ]], --Keybind that will be used to paste + copy_specific_behavior = 'path', --Copy behavior when using copy_specific_keybind. select between 'title', 'path', 'timestamp', 'path&timestamp'. + copy_specific_keybind=[[ + ["ctrl+alt+c", "ctrl+alt+C", "meta+alt+c", "meta+alt+C"] + ]], --Keybind that will be used to copy based on the copy behavior specified + paste_specific_behavior = 'playlist', --Paste behavior when using paste_specific_keybind. select between 'playlist', 'timestamp', 'force'. + paste_specific_keybind=[[ + ["ctrl+alt+v", "ctrl+alt+V", "meta+alt+v", "meta+alt+V"] + ]], --Keybind that will be used to paste based on the paste behavior specified + paste_protocols=[[ + ["https?://", "magnet:", "rtmp:"] + ]], --add above (after a comma) any protocol you want paste to work with; e.g: ,'ftp://'. Or set it as "" by deleting all defined protocols to make paste works with any protocol. + paste_extensions=[[ + ["ac3", "a52", "eac3", "mlp", "dts", "dts-hd", "dtshd", "true-hd", "thd", "truehd", "thd+ac3", "tta", "pcm", "wav", "aiff", "aif", "aifc", "amr", "awb", "au", "snd", "lpcm", "yuv", "y4m", "ape", "wv", "shn", "m2ts", "m2t", "mts", "mtv", "ts", "tsv", "tsa", "tts", "trp", "adts", "adt", "mpa", "m1a", "m2a", "mp1", "mp2", "mp3", "mpeg", "mpg", "mpe", "mpeg2", "m1v", "m2v", "mp2v", "mpv", "mpv2", "mod", "tod", "vob", "vro", "evob", "evo", "mpeg4", "m4v", "mp4", "mp4v", "mpg4", "m4a", "aac", "h264", "avc", "x264", "264", "hevc", "h265", "x265", "265", "flac", "oga", "ogg", "opus", "spx", "ogv", "ogm", "ogx", "mkv", "mk3d", "mka", "webm", "weba", "avi", "vfw", "divx", "3iv", "xvid", "nut", "flic", "fli", "flc", "nsv", "gxf", "mxf", "wma", "wm", "wmv", "asf", "dvr-ms", "dvr", "wtv", "dv", "hdv", "flv","f4v", "f4a", "qt", "mov", "hdmov", "rm", "rmvb", "ra", "ram", "3ga", "3ga2", "3gpp", "3gp", "3gp2", "3g2", "ay", "gbs", "gym", "hes", "kss", "nsf", "nsfe", "sap", "spc", "vgm", "vgz", "m3u", "m3u8", "pls", "cue", + "ase", "art", "bmp", "blp", "cd5", "cit", "cpt", "cr2", "cut", "dds", "dib", "djvu", "egt", "exif", "gif", "gpl", "grf", "icns", "ico", "iff", "jng", "jpeg", "jpg", "jfif", "jp2", "jps", "lbm", "max", "miff", "mng", "msp", "nitf", "ota", "pbm", "pc1", "pc2", "pc3", "pcf", "pcx", "pdn", "pgm", "PI1", "PI2", "PI3", "pict", "pct", "pnm", "pns", "ppm", "psb", "psd", "pdd", "psp", "px", "pxm", "pxr", "qfx", "raw", "rle", "sct", "sgi", "rgb", "int", "bw", "tga", "tiff", "tif", "vtf", "xbm", "xcf", "xpm", "3dv", "amf", "ai", "awg", "cgm", "cdr", "cmx", "dxf", "e2d", "egt", "eps", "fs", "gbr", "odg", "svg", "stl", "vrml", "x3d", "sxd", "v2d", "vnd", "wmf", "emf", "art", "xar", "png", "webp", "jxr", "hdp", "wdp", "cur", "ecw", "iff", "lbm", "liff", "nrrd", "pam", "pcx", "pgf", "sgi", "rgb", "rgba", "bw", "int", "inta", "sid", "ras", "sun", "tga", + "torrent"] + ]], --add above (after a comma) any extension you want paste to work with; e.g: ,'pdf'. Or set it as "" by deleting all defined extension to make paste works with any extension. + paste_subtitles=[[ + ["aqt", "gsub", "jss", "sub", "ttxt", "pjs", "psb", "rt", "smi", "slt", "ssf", "srt", "ssa", "ass", "usf", "idx", "vtt"] + ]], --add above (after a comma) any extension you want paste to attempt to add as a subtitle file, e.g.:'txt'. Or set it as "" by deleting all defined extension to make paste attempt to add any subtitle. + + -----Time Format Settings----- + --in the first parameter, you can define from the available styles: default, hms, hms-full, timestamp, timestamp-concise "default" to show in HH:MM:SS.sss format. "hms" to show in 1h 2m 3.4s format. "hms-full" is the same as hms but keeps the hours and minutes persistent when they are 0. "timestamp" to show the total time as timestamp 123456.700 format. "timestamp-concise" shows the total time in 123456.7 format (shows and hides decimals depending on availability). + --in the second parameter, you can define whether to show milliseconds, round them or truncate them. Available options: 'truncate' to remove the milliseconds and keep the seconds. 0 to remove the milliseconds and round the seconds. 1 or above is the amount of milliseconds to display. The default value is 3 milliseconds. + --in the third parameter you can define the seperator between hour:minute:second. "default" style is automatically set to ":", "hms", "hms-full" are automatically set to " ". You can define your own. Some examples: ["default", 3, "-"],["hms-full", 5, "."],["hms", "truncate", ":"],["timestamp-concise"],["timestamp", 0],["timestamp", "truncate"],["timestamp", 5] + copy_time_format=[[ + ["timestamp-concise"] + ]], + osd_time_format=[[ + ["default", "truncate"] + ]], + +---------------------------END OF USER CUSTOMIZATION SETTINGS--------------------------- +} + +(require 'mp.options').read_options(o) +local utils = require 'mp.utils' +local msg = require 'mp.msg' + +o.copy_keybind = utils.parse_json(o.copy_keybind) +o.paste_keybind = utils.parse_json(o.paste_keybind) +o.copy_specific_keybind = utils.parse_json(o.copy_specific_keybind) +o.paste_specific_keybind = utils.parse_json(o.paste_specific_keybind) +o.paste_protocols = utils.parse_json(o.paste_protocols) +o.paste_extensions = utils.parse_json(o.paste_extensions) +o.paste_subtitles = utils.parse_json(o.paste_subtitles) +o.specific_time_attributes = utils.parse_json(o.specific_time_attributes) +o.pastable_time_attributes = utils.parse_json(o.pastable_time_attributes) +o.copy_time_format = utils.parse_json(o.copy_time_format) +o.osd_time_format = utils.parse_json(o.osd_time_format) + +local protocols = {'https?:', 'magnet:', 'rtmps?:', 'smb:', 'ftps?:', 'sftp:'} +local seekTime = 0 +local clip, clip_time, clip_file, filePath, fileTitle +local clipboard_pasted = false + +function has_value(tab, val) + for index, value in ipairs(tab) do + if value == val then + return true + end + end + + return false +end + +table.insert(o.pastable_time_attributes, o.protocols_time_attribute) +table.insert(o.pastable_time_attributes, o.local_time_attribute) +for i = 1, #o.specific_time_attributes do + if not has_value(o.pastable_time_attributes, o.specific_time_attributes[i][2]) then + table.insert(o.pastable_time_attributes, o.specific_time_attributes[i][2]) + end +end + +if not o.device or o.device == 'auto' then + if os.getenv('windir') ~= nil then + o.device = 'windows' + elseif os.execute '[ -d "/Applications" ]' == 0 and os.execute '[ -d "/Library" ]' == 0 or os.execute '[ -d "/Applications" ]' == true and os.execute '[ -d "/Library" ]' == true then + o.device = 'mac' + else + o.device = 'linux' + end +end + +function starts_protocol(tab, val) + for index, value in ipairs(tab) do + if (val:find(value) == 1) then + return true + end + end + return false +end + +function contain_value(tab, val) + if not tab then return end + if not val then return end + + for index, value in ipairs(tab) do + if value.match(string.lower(val), string.lower(value)) then + return true + end + end + + return false +end + +function file_exists(name) + local f = io.open(name, "r") + if f ~= nil then io.close(f) return true else return false end +end + +function format_time(seconds, sep, decimals, style) + local function divmod (a, b) + return math.floor(a / b), a % b + end + decimals = decimals == nil and 3 or decimals + + local s = seconds + local h, s = divmod(s, 60*60) + local m, s = divmod(s, 60) + + if decimals == 'truncate' then + s = math.floor(s) + decimals = 0 + if style == 'timestamp' then + seconds = math.floor(seconds) + end + end + + if not style or style == '' or style == 'default' then + local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals) + sep = sep and sep or ":" + return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s) + elseif style == 'hms' or style == 'hms-full' then + sep = sep ~= nil and sep or " " + if style == 'hms-full' or h > 0 then + return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s) + elseif m > 0 then + return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s) + else + return string.format("%." .. tostring(decimals) .. "fs", s) + end + elseif style == 'timestamp' then + return string.format("%." .. tostring(decimals) .. "f", seconds) + elseif style == 'timestamp-concise' then + return seconds + end +end + +function get_path() + local path = mp.get_property('path') + if not path then return end + + local title = mp.get_property('media-title'):gsub("\"", "") + + if starts_protocol(protocols, path) and o.prefer_filename_over_title == 'protocols' then + title = mp.get_property('filename'):gsub("\"", "") + elseif not starts_protocol(protocols, path) and o.prefer_filename_over_title == 'local' then + title = mp.get_property('filename'):gsub("\"", "") + elseif o.prefer_filename_over_title == 'all' then + title = mp.get_property('filename'):gsub("\"", "") + end + + return path, title +end + +function bind_keys(keys, name, func, opts) + if not keys then + mp.add_forced_key_binding(keys, name, func, opts) + return + end + + for i = 1, #keys do + if i == 1 then + mp.add_forced_key_binding(keys[i], name, func, opts) + else + mp.add_forced_key_binding(keys[i], name .. i, func, opts) + end + end +end + +function handleres(res, args) + if not res.error and res.status == 0 then + return res.stdout + else + msg.error("There was an error getting "..o.device.." clipboard: ") + msg.error(" Status: "..(res.status or "")) + msg.error(" Error: "..(res.error or "")) + msg.error(" stdout: "..(res.stdout or "")) + msg.error("args: "..utils.to_string(args)) + return '' + end +end + +function os.capture(cmd) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + return s +end + +function make_raw(s) + if not s then return end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +function get_extension(path) + if not path then return end + + match = string.match(path, '%.([^%.]+)$' ) + if match == nil then + return 'nomatch' + else + return match + end +end + + +function get_specific_attribute(target_path) + local pre_attribute = '' + local after_attribute = '' + if not starts_protocol(protocols, target_path) then + pre_attribute = o.local_time_attribute + elseif starts_protocol(protocols, target_path) then + pre_attribute = o.protocols_time_attribute + for i = 1, #o.specific_time_attributes do + if contain_value({o.specific_time_attributes[i][1]}, target_path) then + pre_attribute = o.specific_time_attributes[i][2] + after_attribute = o.specific_time_attributes[i][3] + break + end + end + end + return pre_attribute, after_attribute +end + +function get_time_attribute(target_path) + local pre_attribute = '' + for i = 1, #o.pastable_time_attributes do + if contain_value({o.pastable_time_attributes[i]}, target_path) then + pre_attribute = o.pastable_time_attributes[i] + break + end + end + return pre_attribute +end + + +function get_clipboard() + local clipboard + if o.device == 'linux' then + clipboard = os.capture(o.linux_paste) + return clipboard + elseif o.device == 'windows' then + if o.windows_paste == 'powershell' then + local args = { + 'powershell', '-NoProfile', '-Command', [[& { + Trap { + Write-Error -ErrorRecord $_ + Exit 1 + } + $clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText + if (-not $clip) { + $clip = Get-Clipboard -Raw -Format FileDropList + } + Write-Output $clip + }]] + } + return handleres(utils.subprocess({ args = args, cancellable = false }), args) + else + clipboard = os.capture(o.windows_paste) + return clipboard + end + elseif o.device == 'mac' then + clipboard = os.capture(o.mac_paste) + return clipboard + end + return '' +end + + +function set_clipboard(text) + local pipe + if o.device == 'linux' then + pipe = io.popen(o.linux_copy, 'w') + pipe:write(text) + pipe:close() + elseif o.device == 'windows' then + if o.windows_copy == 'powershell' then + local res = utils.subprocess({ args = { + 'powershell', '-NoProfile', '-Command', string.format([[& { + Trap { + Write-Error -ErrorRecord $_ + Exit 1 + } + Add-Type -AssemblyName PresentationCore + [System.Windows.Clipboard]::SetText('%s') + }]], text) + } }) + else + pipe = io.popen(o.windows_copy,'w') + pipe:write(text) + pipe:close() + end + elseif o.device == 'mac' then + pipe = io.popen(o.mac_copy,'w') + pipe:write(text) + pipe:close() + end + return '' +end + +function parse_clipboard(text) + if not text then return end + + local clip, clip_file, clip_time, pre_attribute + local clip_table = {} + clip = text + + for c in clip:gmatch("[^\n\r+]+") do + local c_pre_attribute, c_clip_file, c_clip_time, c_clip_extension + c = make_raw(c) + + c_pre_attribute = get_time_attribute(c) + if string.match(c, '(.*)'..c_pre_attribute) then + c_clip_file = string.match(c, '(.*)'..c_pre_attribute) + c_clip_time = tonumber(string.match(c, c_pre_attribute..'(%d*%.?%d*)')) + elseif string.match(c, '^\"(.*)\"$') then + c_clip_file = string.match(c, '^\"(.*)\"$') + else + c_clip_file = c + end + + c_clip_extension = get_extension(c_clip_file) + + table.insert(clip_table, {c_clip_file, c_clip_time, c_clip_extension}) + end + + clip = make_raw(clip) + pre_attribute = get_time_attribute(clip) + + if string.match(clip, '(.*)'..pre_attribute) then + clip_file = string.match(clip, '(.*)'..pre_attribute) + clip_time = tonumber(string.match(clip, pre_attribute..'(%d*%.?%d*)')) + elseif string.match(clip, '^\"(.*)\"$') then + clip_file = string.match(clip, '^\"(.*)\"$') + else + clip_file = clip + end + + return clip, clip_file, clip_time, clip_table +end + +function copy() + if filePath ~= nil then + if o.copy_time_method == 'none' or copy_time_method == '' then + copy_specific('path') + return + elseif o.copy_time_method == 'protocols' and not starts_protocol(protocols, filePath) then + copy_specific('path') + return + elseif o.copy_time_method == 'local' and starts_protocol(protocols, filePath) then + copy_specific('path') + return + elseif o.copy_time_method == 'specifics' then + if not starts_protocol(protocols, filePath) then + copy_specific('path') + return + else + for i = 1, #o.specific_time_attributes do + if contain_value({o.specific_time_attributes[i][1]}, filePath) then + copy_specific('path&timestamp') + return + end + end + copy_specific('path') + return + end + else + copy_specific('path&timestamp') + return + end + else + if o.osd_messages == true then + mp.osd_message('Failed to Copy\nNo Video Found') + end + msg.info('Failed to copy, no video found') + end +end + + +function copy_specific(action) + if not action then return end + + if filePath == nil then + if o.osd_messages == true then + mp.osd_message('Failed to Copy\nNo Video Found') + end + msg.info("Failed to copy, no video found") + return + else + if action == 'title' then + if o.osd_messages == true then + mp.osd_message("Copied:\n"..fileTitle) + end + set_clipboard(fileTitle) + msg.info("Copied the below into clipboard:\n"..fileTitle) + end + if action == 'path' then + if o.osd_messages == true then + mp.osd_message("Copied:\n"..filePath) + end + set_clipboard(filePath) + msg.info("Copied the below into clipboard:\n"..filePath) + end + if action == 'timestamp' then + local pre_attribute, after_attribute = get_specific_attribute(filePath) + local video_time = mp.get_property_number('time-pos') + if o.osd_messages == true then + mp.osd_message("Copied"..o.time_seperator..format_time(video_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + end + set_clipboard(pre_attribute..format_time(video_time, o.copy_time_format[3], o.copy_time_format[2], o.copy_time_format[1])..after_attribute) + msg.info('Copied the below into clipboard:\n'..pre_attribute..format_time(video_time, o.copy_time_format[3], o.copy_time_format[2], o.copy_time_format[1])..after_attribute) + end + if action == 'path&timestamp' then + local pre_attribute, after_attribute = get_specific_attribute(filePath) + local video_time = mp.get_property_number('time-pos') + if o.osd_messages == true then + mp.osd_message("Copied:\n" .. fileTitle .. o.time_seperator .. format_time(video_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + end + set_clipboard(filePath..pre_attribute..format_time(video_time, o.copy_time_format[3], o.copy_time_format[2], o.copy_time_format[1])..after_attribute) + msg.info('Copied the below into clipboard:\n'..filePath..pre_attribute..format_time(video_time, o.copy_time_format[3], o.copy_time_format[2], o.copy_time_format[1])..after_attribute) + end + end +end + +function trigger_paste_action(action) + if not action then return end + + if action == 'load-file' then + filePath = clip_file + if o.osd_messages == true then + if clip_time ~= nil then + mp.osd_message("Pasted:\n"..clip_file .. o.time_seperator .. format_time(clip_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + else + mp.osd_message("Pasted:\n"..clip_file) + end + end + mp.commandv('loadfile', clip_file) + clipboard_pasted = true + + if clip_time ~= nil then + msg.info("Pasted the below file into mpv:\n"..clip_file .. format_time(clip_time)) + else + msg.info("Pasted the below file into mpv:\n"..clip_file) + end + end + + if action == 'load-subtitle' then + if o.osd_messages == true then + mp.osd_message("Pasted Subtitle:\n"..clip_file) + end + mp.commandv('sub-add', clip_file, 'select') + msg.info("Pasted the below subtitle into mpv:\n"..clip_file) + end + + if action == 'file-seek' then + local video_duration = mp.get_property_number('duration') + seekTime = clip_time + o.resume_offset + + if seekTime > video_duration then + if o.osd_messages == true then + mp.osd_message('Time Paste Exceeds Video Length' .. o.time_seperator .. format_time(clip_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + end + msg.info("The time pasted exceeds the video length:\n"..format_time(clip_time)) + return + end + + if (seekTime < 0) then + seekTime = 0 + end + + if o.osd_messages == true then + mp.osd_message('Resumed to Pasted Time' .. o.time_seperator .. format_time(clip_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + end + mp.commandv('seek', seekTime, 'absolute', 'exact') + msg.info("Resumed to the pasted time" .. o.time_seperator .. format_time(clip_time)) + end + + if action == 'add-playlist' then + if o.osd_messages == true then + mp.osd_message('Pasted Into Playlist:\n'..clip_file) + end + mp.commandv('loadfile', clip_file, 'append-play') + msg.info("Pasted the below into playlist:\n"..clip_file) + end + + if action == 'error-subtitle' then + if o.osd_messages == true then + mp.osd_message('Subtitle Paste Requires Running Video:\n'..clip_file) + end + msg.info('Subtitles can only be pasted if a video is running:\n'..clip_file) + end + + if action == 'error-unsupported' then + if o.osd_messages == true then + mp.osd_message('Paste of this item is unsupported possibly due to configuration:\n'..clip) + end + msg.info('Failed to paste into mpv, pasted item shown below is unsupported possibly due to configuration:\n'..clip) + end + + if action == 'error-missing' then + if o.osd_messages == true then + mp.osd_message('File Doesn\'t Exist:\n' .. clip_file) + end + msg.info('The file below doesn\'t seem to exist:\n' .. clip_file) + end + + if action == 'error-time' then + if o.osd_messages == true then + if clip_time ~= nil then + mp.osd_message('Time Paste Requires Running Video' .. o.time_seperator .. format_time(clip_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + else + mp.osd_message('Time Paste Requires Running Video') + end + end + + if clip_time ~= nil then + msg.info('Time can only be pasted if a video is running:\n'.. format_time(clip_time)) + else + msg.info('Time can only be pasted if a video is running') + end + end + + if action == 'error-missingtime' then + if o.osd_messages == true then + mp.osd_message('Clipboard does not contain time for seeking:\n'..clip) + end + msg.info("Clipboard does not contain the time attribute and time for seeking:\n"..clip) + end + + if action == 'error-samefile' then + if o.osd_messages == true then + mp.osd_message('Pasted file is already running:\n'..clip) + end + msg.info("Pasted file shown below is already running:\n"..clip) + end + + if action == 'error-unknown' then + if o.osd_messages == true then + mp.osd_message('Paste was ignored due to an error:\n'..clip) + end + msg.info('Paste was ignored due to an error:\n'..clip) + end + +end + +function multipaste() + if #clip_table < 2 then return msg.warn('Single paste should be called instead of multipaste') end + local file_ignored_total = 0 + local file_subtitle_total = 0 + local triggered_multipaste = {} + + if filePath == nil then + for i=1, #clip_table do + if file_exists(clip_table[i][1]) and has_value(o.paste_extensions, clip_table[i][3]) + or starts_protocol(o.paste_protocols, clip_table[i][1]) then + filePath = clip_table[i][1] + mp.commandv('loadfile', clip_table[i][1]) + clipboard_pasted = true + table.remove(clip_table, i) + triggered_multipaste[1] = true + break + end + end + end + + if filePath ~= nil then + for i=1, #clip_table do + if file_exists(clip_table[i][1]) and has_value(o.paste_extensions, clip_table[i][3]) + or starts_protocol(o.paste_protocols, clip_table[i][1]) then + mp.commandv('loadfile', clip_table[i][1], 'append-play') + triggered_multipaste[2] = true + elseif file_exists(clip_table[i][1]) and has_value(o.paste_subtitles, clip_table[i][3]) then + mp.commandv('sub-add', clip_table[i][1]) + file_subtitle_total = file_subtitle_total + 1 + elseif not has_value(o.paste_extensions, clip_table[i][3]) and not has_value(o.paste_subtitles, clip_table[i][3]) then + msg.warn('The below was ignored since it is unsupported possibly due to configuration:\n'..clip_table[i][1]) + file_ignored_total = file_ignored_total + 1 + elseif not file_exists(clip_table[i][1]) then + msg.warn('The below doesn\'t seem to exist:\n' .. clip_table[i][1]) + file_ignored_total = file_ignored_total + 1 + else + msg.warn('The below was ignored due to an error:\n' .. clip_table[i][1]) + file_ignored_total = file_ignored_total + 1 + end + end + end + + local osd_msg = '' + if triggered_multipaste[1] == true then + if osd_msg ~= '' then osd_msg = osd_msg..'\n' end + osd_msg = osd_msg..'Pasted: '..filePath + end + if file_subtitle_total > 0 then + if osd_msg ~= '' then osd_msg = osd_msg..'\n' end + osd_msg = osd_msg..'Added '..file_subtitle_total..' Subtitle/s' + end + if triggered_multipaste[2] == true then + if osd_msg ~= '' then osd_msg = osd_msg..'\n' end + osd_msg = osd_msg..'Added Into Playlist '..#clip_table - file_ignored_total - file_subtitle_total..' item/s' + end + if file_ignored_total > 0 then + if osd_msg ~= '' then osd_msg = osd_msg..'\n' end + osd_msg = osd_msg..'Ignored '..file_ignored_total.. ' Item/s' + end + + if osd_msg == '' then + osd_msg = 'Pasted Items Ignored or Unable To Append Into Video:\n'..clip + end + + if o.osd_messages == true then + mp.osd_message(osd_msg) + end + msg.info(osd_msg) +end + + +function paste() + if o.osd_messages == true then + mp.osd_message("Pasting...") + end + msg.info("Pasting...") + + clip = get_clipboard(clip) + if not clip then msg.error('Error: clip is null' .. clip) return end + clip, clip_file, clip_time, clip_table = parse_clipboard(clip) + + if #clip_table > 1 then + multipaste() + else + local currentVideoExtension = string.lower(get_extension(clip_file)) + if filePath == nil then + if file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('load-file') + elseif file_exists(clip_file) and has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-subtitle') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + else + if file_exists(clip_file) and has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('load-subtitle') + elseif o.running_paste_behavior == 'playlist' then + if filePath ~= clip_file and file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or filePath ~= clip_file and starts_protocol(o.paste_protocols, clip_file) + or filePath == clip_file and file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) and clip_time == nil + or filePath == clip_file and starts_protocol(o.paste_protocols, clip_file) and clip_time == nil then + trigger_paste_action('add-playlist') + elseif clip_time ~= nil then + trigger_paste_action('file-seek') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + elseif o.running_paste_behavior == 'timestamp' then + if clip_time ~= nil then + trigger_paste_action('file-seek') + elseif file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('add-playlist') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + elseif o.running_paste_behavior == 'force' then + if filePath ~= clip_file and file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or filePath ~= clip_file and starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('load-file') + elseif clip_time ~= nil then + trigger_paste_action('file-seek') + elseif file_exists(clip_file) and filePath == clip_file + or filePath == clip_file and starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('add-playlist') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + end + end + end +end + + +function paste_specific(action) + if not action then return end + + if o.osd_messages == true then + mp.osd_message("Pasting...") + end + msg.info("Pasting...") + + clip = get_clipboard(clip) + if not clip then msg.error('Error: clip is null' .. clip) return end + clip, clip_file, clip_time, clip_table = parse_clipboard(clip) + + if #clip_table > 1 then + multipaste() + else + local currentVideoExtension = string.lower(get_extension(clip_file)) + if action == 'playlist' then + if file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('add-playlist') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + end + + if action == 'timestamp' then + if filePath == nil then + trigger_paste_action('error-time') + elseif clip_time ~= nil then + trigger_paste_action('file-seek') + elseif clip_time == nil then + trigger_paste_action('error-missingtime') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + end + + if action == 'force' then + if filePath ~= clip_file and file_exists(clip_file) and has_value(o.paste_extensions, currentVideoExtension) + or filePath ~= clip_file and starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('load-file') + elseif file_exists(clip_file) and filePath == clip_file + or filePath == clip_file and starts_protocol(o.paste_protocols, clip_file) then + trigger_paste_action('error-samefile') + elseif not has_value(o.paste_extensions, currentVideoExtension) and not has_value(o.paste_subtitles, currentVideoExtension) then + trigger_paste_action('error-unsupported') + elseif not file_exists(clip_file) then + trigger_paste_action('error-missing') + else + trigger_paste_action('error-unknown') + end + end + end +end + +mp.register_event('file-loaded', function() + filePath, fileTitle = get_path() + if clipboard_pasted == true then + clip = get_clipboard(clip) + if not clip then msg.error('Error: clip is null' .. clip) return end + clip, clip_file, clip_time, clip_table = parse_clipboard(clip) + + if #clip_table > 1 then + for i=1, #clip_table do + if file_exists(clip_table[i][1]) and has_value(o.paste_extensions, clip_table[i][3]) + or starts_protocol(o.paste_protocols, clip_table[i][1]) then + clip_file = clip_table[i][1] + clip_time = clip_table[i][2] + break + end + end + end + + if filePath == clip_file and clip_time ~= nil then + local video_duration = mp.get_property_number('duration') + seekTime = clip_time + o.resume_offset + + if seekTime > video_duration then + if o.osd_messages == true then + mp.osd_message('Time Paste Exceeds Video Length' .. o.time_seperator .. format_time(clip_time, o.osd_time_format[3], o.osd_time_format[2], o.osd_time_format[1])) + end + msg.info("The time pasted exceeds the video length:\n"..format_time(clip_time)) + return + end + + if seekTime < 0 then + seekTime = 0 + end + + mp.commandv('seek', seekTime, 'absolute', 'exact') + clipboard_pasted = false + end + end +end) + +bind_keys(o.copy_keybind, 'copy', copy) +bind_keys(o.copy_specific_keybind, 'copy-specific', function()copy_specific(o.copy_specific_behavior)end) +bind_keys(o.paste_keybind, 'paste', paste) +bind_keys(o.paste_specific_keybind, 'paste-specific', function()paste_specific(o.paste_specific_behavior)end) diff --git a/.config/mpv/scripts/mpvSockets.lua b/.config/mpv/scripts/mpvSockets.lua @@ -0,0 +1,36 @@ +-- mpvSockets, one socket per instance, removes socket on exit + +local utils = require 'mp.utils' + +local function get_temp_path() + local directory_seperator = package.config:match("([^\n]*)\n?") + local example_temp_file_path = os.tmpname() + + -- remove generated temp file + pcall(os.remove, example_temp_file_path) + + local seperator_idx = example_temp_file_path:reverse():find(directory_seperator) + local temp_path_length = #example_temp_file_path - seperator_idx + + return example_temp_file_path:sub(1, temp_path_length) +end + +tempDir = get_temp_path() + +function join_paths(...) + local arg={...} + path = "" + for i,v in ipairs(arg) do + path = utils.join_path(path, tostring(v)) + end + return path; +end + +ppid = utils.getpid() +os.execute("mkdir " .. join_paths(tempDir, "mpvSockets") .. " 2>/dev/null") +mp.set_property("options/input-ipc-server", join_paths(tempDir, "mpvSockets", ppid)) + +function shutdown_handler() + os.remove(join_paths(tempDir, "mpvSockets", ppid)) +end +mp.register_event("shutdown", shutdown_handler) diff --git a/.config/mutt/alias b/.config/mutt/alias @@ -0,0 +1,18 @@ +alias mahdi-mirzade Mahdi Mirzade <[email protected]> +alias chibby-bromanson Chibby Bromanson <[email protected]> +alias NRK <[email protected]> +alias страхиња-радић Страхиња Радић <[email protected]> +alias robert-winkler Robert Winkler <[email protected]> +alias Wolf <[email protected]> +alias viktor-grigorov Viktor Grigorov <[email protected]> +alias laslo-hunhold Laslo Hunhold <[email protected]> +alias hadrien-lacour Hadrien Lacour <[email protected]> +alias ابر-آروان ابر آروان <[email protected]> +alias guillermo-brandcrowd Guillermo Conde BrandCrowd <[email protected]> +alias oracle-events Oracle Database World Events <[email protected]> +alias internet-club Internet Chess Club <[email protected]> +alias red-hat Red Hat <[email protected]> +alias felix-esq Felix Mazie Esq <[email protected]> +alias quentin-rameau Quentin Rameau <[email protected]> +alias mehdi-sadeghi Mehdi Sadeghi <[email protected]> +alias PussyTorrents.org <[email protected]> diff --git a/.config/mutt/display b/.config/mutt/display @@ -0,0 +1,24 @@ +#!/bin/sh + +MESSAGE=$(cat) + +EMAIL=$(echo "${MESSAGE}" | grep ^"From: " | sed 's/[^<]*<\([^@]*\)@.*/\1/') + +case $EMAIL in + "DO_NOT_REPLY") addalias=no;; + "drive-shares-noreply") addalias=no;; + noreply*|no-reply*|no_reply*) addalias=no;; + artifactory) addalias=no;; + *) addalias=yes;; +esac + +if [ "$addalias" = "yes" ]; then + NEWALIAS=$(echo "${MESSAGE}" | grep ^"From: " | sed s/[\,\"\']//g | awk '{$1=""; if (NF == 3) {print "alias" $0;} else if (NF == 2) {print "alias" $0 $0;} else if (NF > 3) {print "alias", tolower($2)"-"tolower($(NF-1)) $0;}}') + if grep -Fxq "$NEWALIAS" "$HOME"/.config/mutt/alias; then + : + else + echo "$NEWALIAS" >> "$HOME"/.config/mutt/alias + fi +fi + +echo "${MESSAGE}" diff --git a/.config/mutt/mailcap b/.config/mutt/mailcap @@ -0,0 +1,15 @@ +text/plain; $EDITOR %s ; +text/html; openfile %s ; nametemplate=%s.html +text/html; lynx -assume_charset=%{charset} -display_charset=utf-8 -dump -width=1024 %s; nametemplate=%s.html; copiousoutput; +image/*; openfile %s ; +video/*; setsid mpv --quiet %s &; copiousoutput +audio/*; mpv %s ; +application/pdf; openfile %s ; +application/pgp-encrypted; gpg -d '%s'; copiousoutput; +application/pgp-keys; gpg --import '%s'; copiousoutput; +#image/*; fh %s; +#application/*; fh %s; +#application/pdf; fh %s; +#video/*; fh %s; +#audio/*; fh %s; +#text/html; fh %s; diff --git a/.config/mutt/muttrc b/.config/mutt/muttrc @@ -0,0 +1,196 @@ +# Multiple accounts +macro index,pager <f1> '<sync-mailbox><enter-command>source ~/.config/mutt/muttrc<enter><change-folder>!<enter>' +macro index,pager <f2> '<sync-mailbox><enter-command>source ~/.config/mutt/personal<enter><change-folder>!<enter>' +macro index,pager <f3> '<sync-mailbox><enter-command>source ~/.config/mutt/work<enter><change-folder>!<enter>' + +# Personal Details +set realname="Mahdi Mirzade" +set from="[email protected]" +set use_from=yes +set use_envelope_from=yes +set reverse_name=yes + +# Mail Server +set mbox_type=Maildir +set ssl_force_tls = yes + +# imaps://user@domain@imap_domain:port +#set folder="imaps://[email protected]@mail.mahdi.pw:993" +#set imap_pass = `pass email` +set folder="~/.local/share/mail/acct0" + +# smtps://user@domain@smtp_domain:port +set smtp_url = "smtps://[email protected]@mail.mahdi.pw:465" +set smtp_pass = `pass email` + +# Mailboxes +set spoolfile="+Inbox" +set postponed="+Drafts" +set record="+Sent" +set trash="+Trash" +mailboxes "+-- $realname -----------" +mailboxes =Inbox =Drafts =Sent =Junk =Trash + +# Settings +set mailcap_path="~/.config/mutt/mailcap" +macro attach s <save-entry><bol>~/Downloads/<eol> +set date_format="%y/%m/%d %I:%M%p" +set index_format="%2C %Z %?X?A& ? %D %-15.15F %s (%-4.4c)" +set sort = 'reverse-date' +set help = no # Disable help bar +set sleep_time = 0 # Pause 0 seconds for informational messages +set markers = no # Disables the `+` displayed at line wraps +set mark_old = no # Unread mail stay unread until read +set mime_forward = yes # attachments are forwarded with mail +set wait_key = no # mutt won't ask "press key to continue" +set fast_reply # skip to compose when replying +set fcc_attach # save attachments with the body +set forward_format = "Fwd: %s" # format of subject when forwarding +set forward_quote # include message in forwards +set reverse_name # reply as whomever it was to +set include # include message in replies +auto_view text/html # automatically show html (mailcap uses lynx) +auto_view application/pgp-encrypted +alternative_order text/plain text/enriched text/html + +bind index,pager i noop +bind index,pager g noop +bind index \Cf noop +bind index,pager M noop +bind index,pager C noop + +# Bindings +bind index gg first-entry +bind index j next-entry +bind index k previous-entry +bind attach <return> view-mailcap +bind attach l view-mailcap +bind editor <space> noop +bind index G last-entry +bind index gg first-entry +bind pager,attach h exit +bind pager j next-line +bind pager k previous-line +bind pager l view-attachments +bind index D delete-message +bind index U undelete-message +bind index L limit +bind index h noop +bind index l display-message +bind index,query <space> tag-entry +#bind browser h goto-parent +macro browser h '<change-dir><kill-line>..<enter>' "Go to parent folder" +bind browser l select-entry +bind index,pager,browser d half-down +bind index,pager,browser u half-up +bind index,pager S sync-mailbox +bind index,pager R group-reply +bind index \031 previous-undeleted # Mouse wheel +bind index \005 next-undeleted # Mouse wheel +bind pager \031 previous-line # Mouse wheel +bind pager \005 next-line # Mouse wheel +bind editor <Tab> complete-query + +macro index,pager gi "<change-folder>=Inbox<enter>" "go to inbox" +macro index,pager Mi ";<save-message>=Inbox<enter>" "move mail to inbox" +macro index,pager Ci ";<copy-message>=Inbox<enter>" "copy mail to inbox" +macro index,pager gd "<change-folder>=Drafts<enter>" "go to drafts" +macro index,pager Md ";<save-message>=Drafts<enter>" "move mail to drafts" +macro index,pager Cd ";<copy-message>=Drafts<enter>" "copy mail to drafts" +macro index,pager gs "<change-folder>=Sent<enter>" "go to sent" +macro index,pager Ms ";<save-message>=Sent<enter>" "move mail to sent" +macro index,pager Cs ";<copy-message>=Sent<enter>" "copy mail to sent" +macro index,pager gt "<change-folder>=Trash<enter>" "go to trash" +macro index,pager Mt ";<save-message>=Trash<enter>" "move mail to trash" +macro index,pager Ct ";<copy-message>=Trash<enter>" "copy mail to trash" +macro index,pager gj "<change-folder>=Junk<enter>" "go to junk" +macro index,pager Mj ";<save-message>=Junk<enter>" "move mail to junk" +macro index,pager Cj ";<copy-message>=Junk<enter>" "copy mail to junk" + +macro index O "<shell-escape>sync-mail<enter>" "run sync-mail to sync all mails" + +# Sidebar mappings +set mail_check_stats +set sidebar_visible = yes +set sidebar_width = 23 +set sidebar_short_path = yes +set sidebar_next_new_wrap = yes +set sidebar_format = '%B%?F? [%F]?%* %?N?%N/? %?S?%S?' +set sidebar_divider_char = ' │ ' +bind index,pager \Ck sidebar-prev +bind index,pager \Cj sidebar-next +bind index,pager \Co sidebar-open +bind index,pager \Cp sidebar-prev-new +bind index,pager \Cn sidebar-next-new +bind index,pager B sidebar-toggle-visible + +#set crypt_autosign = yes +#set crypt_opportunistic_encrypt = yes +#set pgp_self_encrypt = yes +#set pgp_default_key = '[email protected]' + +# Colors +# Default index colors: +color index yellow default '.*' + +# New mail is boldened: +color index brightyellow black "~N" + +# Tagged mail is highlighted: +color index brightyellow blue "~T" + +# Other colors and aesthetic settings: +mono bold bold +mono underline underline +mono indicator reverse +mono error bold +color normal default default +color indicator brightblack white +color sidebar_highlight yellow default +color sidebar_divider brightblack black +color sidebar_flagged red black +color sidebar_new green black +color normal brightyellow default +color error red default +color tilde black default +color message cyan default +color markers red white +color attachment white default +color search brightmagenta default +color status brightyellow black +color hdrdefault brightgreen default +color quoted green default +color quoted1 blue default +color quoted2 cyan default +color quoted3 yellow default +color quoted4 red default +color quoted5 brightred default +color signature brightgreen default +color bold black default +color underline black default +color normal default default + +# Regex highlighting: +color header brightmagenta default "^From" +color header brightcyan default "^Subject" +color header brightwhite default "^(CC|BCC)" +color header blue default ".*" +color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses +color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL +color body green default "\`[^\`]*\`" # Green text between ` and ` +color body brightblue default "^# \.*" # Headings as bold blue +color body brightcyan default "^## \.*" # Subheadings as bold cyan +color body brightgreen default "^### \.*" # Subsubheadings as bold green +color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow +color body brightcyan default "[;:][-o][)/(|]" # emoticons +color body brightcyan default "[;:][)(|]" # emoticons +color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon? +color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon? +color body red default "(BAD signature)" +color body cyan default "(Good signature)" +color body brightblack default "^gpg: Good signature .*" +color body brightyellow default "^gpg: " +color body brightyellow red "^gpg: BAD signature from.*" +mono body bold "^gpg: Good signature" +mono body bold "^gpg: BAD signature from.*" +color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]" diff --git a/.config/mutt/muttrc.bak b/.config/mutt/muttrc.bak @@ -0,0 +1,170 @@ +# Multiple accounts +macro index,pager <f1> '<sync-mailbox><enter-command>source ~/.config/mutt/muttrc<enter><change-folder>!<enter>' +macro index,pager <f2> '<sync-mailbox><enter-command>source ~/.config/mutt/personal<enter><change-folder>!<enter>' +macro index,pager <f3> '<sync-mailbox><enter-command>source ~/.config/mutt/work<enter><change-folder>!<enter>' + +# Personal Details +set realname="Mahdi Mirzade" +set from="[email protected]" +set use_from=yes +set use_envelope_from=yes +set reverse_name=yes + +# Mail Server +set mbox_type=Maildir +set folder="~/.local/share/mail/acct0" +set smtp_url = "smtps://[email protected]" +set smtp_pass = `pass email` +set ssl_force_tls = yes + +# Mailboxes +set spoolfile="+Inbox" +set postponed="+Drafts" +set record="+Sent" +set trash="+Trash" + +macro index 1 "<change-folder> =Inbox<enter>" +macro index 2 "<change-folder> =Drafts<enter>" +macro index 3 "<change-folder> =Sent<enter>" +macro index 4 "<change-folder> =Trash<enter>" +macro index 5 "<change-folder> =Junk<enter>" + +# Settings +set mailcap_path="~/.config/mutt/mailcap" +set display_filter="sh ~/.config/mutt/display" +macro attach s <save-entry><bol>~/Downloads/<eol> + +set sleep_time = 0 # Pause 0 seconds for informational messages +set mime_forward # attachments are forwarded with mail +set fast_reply # skip to compose when replying +set fcc_attach # save attachments with the body +set forward_format = "Fwd: %s" # format of subject when forwarding +set forward_quote # include message in forwards +set reverse_name # reply as whomever it was to +set include # include message in replies +set delete # Don't ask to confirm purge deleted message on sync +unset recall # Don't ask to recall postponed message when Composing +unset markers # Disables the `+` displayed at line wraps +unset mark_old # Unread mail stay unread until read +unset wait_key # mutt won't ask "press key to continue" +unset help # remove help bar + +# Bindings + +bind index "l" display-message +bind pager "l" view-attachments +bind attach "l" view-mailcap +bind browser "l" select-entry + +bind index,attach g first-entry +bind index,attach G last-entry + +macro index,pager o "<pipe-entry>tee /tmp/muttb<enter><shell-escape>tmux split-window 'fh -e \"$(cat /tmp/muttb)\" && rm -f /tmp/muttb'<enter>" +macro index,pager o "<pipe-message>tee /tmp/muttb<enter><shell-escape>tmux split-window 'fh -e \"$(cat /tmp/muttb)\" && rm -f /tmp/muttb'<enter>" + +bind index d delete-message +bind index D undelete-message + +macro index,pager U <clear-flag>O "Mark as read" +macro index,pager u <set-flag>O "Mark as unread" + +bind index,pager s sync-mailbox +# macro index m "<shell-escape>mirror -m<enter>" "run mbsync to sync all mail" +bind index,pager m imap-fetch-mail + +bind editor <Tab> complete-query + +macro index h "T~U<enter><tag-prefix><clear-flag>N<untag-pattern>.<enter>" "mark all messages as read" + +bind index,pager i mail + +bind index,pager f search +bind index,pager F search-reverse + +# bind index,pager m search-next +# bind index,pager M search-opposite + +bind index,pager ';' quit + +bind index <Space> tag-entry + +# Sidebar mappings +set sidebar_visible = yes +set sidebar_width = 20 +set sidebar_short_path = yes +set sidebar_next_new_wrap = yes +set mail_check_stats +set sidebar_format = '%D%?F? [%F]?%* %?N?%N/? %?S?%S?' +bind index,pager \Ck sidebar-prev +bind index,pager \Cj sidebar-next +bind index,pager \Co sidebar-open +bind index,pager \Cp sidebar-prev-new +bind index,pager \Cn sidebar-next-new +bind index,pager B sidebar-toggle-visible + +#set crypt_autosign = yes +#set crypt_opportunistic_encrypt = yes +#set pgp_self_encrypt = yes +#set pgp_default_key = '[email protected]' + +# Colors +# Default index colors: +color index yellow default '.*' + +# New mail is boldened: +color index brightyellow black "~N" + +# Tagged mail is highlighted: +color index brightyellow blue "~T" + +# Other colors and aesthetic settings: +mono bold bold +mono underline underline +mono indicator reverse +mono error bold +color normal default default +color indicator brightblack white +color normal brightyellow default +color error red default +color tilde black default +color message cyan default +color markers red white +color attachment white default +color search brightmagenta default +color status brightyellow black +color hdrdefault brightgreen default +color quoted green default +color quoted1 blue default +color quoted2 cyan default +color quoted3 yellow default +color quoted4 red default +color quoted5 brightred default +color signature brightgreen default +color bold black default +color underline black default +color normal default default + +# Regex highlighting: +color header brightmagenta default "^From" +color header brightcyan default "^Subject" +color header brightwhite default "^(CC|BCC)" +color header blue default ".*" +color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses +color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL +color body green default "\`[^\`]*\`" # Green text between ` and ` +color body brightblue default "^# \.*" # Headings as bold blue +color body brightcyan default "^## \.*" # Subheadings as bold cyan +color body brightgreen default "^### \.*" # Subsubheadings as bold green +color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow +color body brightcyan default "[;:][-o][)/(|]" # emoticons +color body brightcyan default "[;:][)(|]" # emoticons +color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon? +color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon? +color body red default "(BAD signature)" +color body cyan default "(Good signature)" +color body brightblack default "^gpg: Good signature .*" +color body brightyellow default "^gpg: " +color body brightyellow red "^gpg: BAD signature from.*" +mono body bold "^gpg: Good signature" +mono body bold "^gpg: BAD signature from.*" +color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]" diff --git a/.config/picom/picom.conf b/.config/picom/picom.conf @@ -0,0 +1,82 @@ +################################# +# Shadows # +################################# +shadow = true; +shadow-radius = 7; +shadow-opacity = .75 +shadow-offset-x = -7; +shadow-offset-y = -7; +shadow-exclude = [ + "name = 'Notification'", + "class_g = 'Conky'", + "class_g ?= 'Notify-osd'", + "class_g = 'Cairo-clock'", + "_GTK_FRAME_EXTENTS@:c" +]; + +################################# +# Fading # +################################# +fading = true; +fade-in-step = 0.03; +fade-out-step = 0.03; +fade-delta = 10 + +################################# +# Transparency / Opacity # +################################# +inactive-opacity = 0.95; +frame-opacity = 0.9; +inactive-opacity-override = false; +active-opacity = 1.0 +inactive-dim = 0.0 +focus-exclude = [ "class_g = 'Cairo-clock'" ]; +inactive-dim-fixed = 1.0 +opacity-rule = [] + +################################# +# Corners # +################################# +corner-radius = 0 +rounded-corners-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'" +]; + +################################# +# Background-Blurring # +################################# +#blur-method = "dual_kawase" +#blur-size = 5 +#blur-deviation = true +#blur-strength = 5 +#blur-background = true +#blur-background-frame = false +#blur-background-fixed = false +#blur-kern = "3x3box"; +#blur-background-exclude = [ +# "window_type = 'dock'", +# "window_type = 'desktop'", +# "_GTK_FRAME_EXTENTS@:c" +#]; + +################################# +# General Settings # +################################# +backend = "glx" +vsync = true; +dbus = false +detect-transient = true; +glx-no-stencil = true; +use-damage = true; +log-level = "warn"; + +wintypes: +{ + tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; }; + dock = { shadow = false; clip-shadow-above = true; } + dnd = { shadow = false; } + popup_menu = { opacity = 0.8; shadow = false; } + dropdown_menu = { opacity = 0.8; shadow = false; } + notification = { shadow = false; } +}; diff --git a/.config/qutebrowser/config.py b/.config/qutebrowser/config.py @@ -0,0 +1,348 @@ +# Import dependencies +import subprocess, os + +# Autoconfig Default Settings +config.load_autoconfig() + +# Auto Save Session (useful in Unpredictable Situations) +config.set("auto_save.session", True) + +# Change Default Zoom to 75% +config.set("zoom.default", "80%") + +# Change Downloads tab position +config.set("downloads.position","bottom") + +# Custom keybinds +# This I use if I'm already inside the video page. +config.bind('em', 'spawn $HOME/.local/bin/open {url}') +config.bind('eM', 'hint links spawn $HOME/.local/bin/open {hint-url}') + +# This help to fix youtube scrolling problem +config.bind('j', 'scroll-px 0 30') +config.bind('k', 'scroll-px 0 -30') + +# Do not raise focus on new tab +c.new_instance_open_target = "tab-bg-silent" + +# JS, cookies, encoding, headers, fonts, status-bar +c.content.autoplay = False +c.content.cookies.accept = "all" +c.content.default_encoding = "utf-8" +#c.content.headers.user_agent = ( +# "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)" +# " Chrome/80.0.3987.163 Safari/537.36" +#) +c.fonts.default_family = ['FantasqueSansMono Nerd Font'] +c.fonts.default_size = '10pt' +c.statusbar.widgets = ["keypress", "progress", "url", "scroll"] + +def read_xresources(prefix): + """ + read settings from xresources + """ + props = {} + x = subprocess.run(["xrdb", "-query"], stdout=subprocess.PIPE) + lines = x.stdout.decode().split("\n") + for line in filter(lambda l: l.startswith(prefix), lines): + prop, _, value = line.partition(":\t") + props[prop] = value + return props + +xresources = read_xresources("*") + +# Set Colors +palette = { + 'background': xresources["*.background"], + 'background-alt': xresources["*.background"], + 'background-attention': xresources["*.color8"], + 'border': xresources["*.background"], + 'current-line': xresources["*.color8"], + 'selection': xresources["*.color8"], + 'foreground': xresources["*.foreground"], + 'foreground-alt': xresources["*.color8"], + 'foreground-attention': xresources["*.color15"], + 'comment': xresources["*.color6"], + 'cyan': xresources["*.color6"], + 'green': xresources["*.color2"], + 'orange': xresources["*.color9"], + 'pink': xresources["*.color13"], + 'purple': xresources["*.color5"], + 'red': xresources["*.color1"], + 'yellow': xresources["*.color3"] +} +spacing = { + 'vertical': 4, + 'horizontal': 4 +} +padding = { + 'top': spacing['vertical'], + 'right': spacing['horizontal'], + 'bottom': spacing['vertical'], + 'left': spacing['horizontal'] +} + +# Setting Dark Mode +config.set("colors.webpage.darkmode.enabled", True) +config.set("colors.webpage.preferred_color_scheme","dark") + +# Default Background color of webpages. +c.colors.webpage.bg = palette['background'] + +# Background color of the completion widget category headers. +c.colors.completion.category.bg = palette['background'] + +# Bottom border color of the completion widget category headers. +c.colors.completion.category.border.bottom = palette['border'] + +# Top border color of the completion widget category headers. +c.colors.completion.category.border.top = palette['border'] + +# Foreground color of completion widget category headers. +c.colors.completion.category.fg = palette['foreground'] + +# Background color of the completion widget for even rows. +c.colors.completion.even.bg = palette['background'] + +# Background color of the completion widget for odd rows. +c.colors.completion.odd.bg = palette['background-alt'] + +# Text color of the completion widget. +c.colors.completion.fg = palette['foreground'] + +# Background color of the selected completion item. +c.colors.completion.item.selected.bg = palette['selection'] + +# Bottom border color of the selected completion item. +c.colors.completion.item.selected.border.bottom = palette['selection'] + +# Top border color of the completion widget category headers. +c.colors.completion.item.selected.border.top = palette['selection'] + +# Foreground color of the selected completion item. +c.colors.completion.item.selected.fg = palette['foreground'] + +# Foreground color of the matched text in the completion. +c.colors.completion.match.fg = palette['orange'] + +# Color of the scrollbar in completion view +c.colors.completion.scrollbar.bg = palette['background'] + +# Color of the scrollbar handle in completion view. +c.colors.completion.scrollbar.fg = palette['foreground'] + +# Background color for the download bar. +c.colors.downloads.bar.bg = palette['background'] + +# Background color for downloads with errors. +c.colors.downloads.error.bg = palette['background'] + +# Foreground color for downloads with errors. +c.colors.downloads.error.fg = palette['red'] + +# Color gradient stop for download backgrounds. +c.colors.downloads.stop.bg = palette['background'] + +# Color gradient interpolation system for download backgrounds. +# Type: ColorSystem +# Valid values: +# - rgb: Interpolate in the RGB color system. +# - hsv: Interpolate in the HSV color system. +# - hsl: Interpolate in the HSL color system. +# - none: Don't show a gradient. +c.colors.downloads.system.bg = 'none' + +# Background color for hints. Note that you can use a `rgba(...)` value +# for transparency. +c.colors.hints.bg = palette['background'] + +# Font color for hints. +c.colors.hints.fg = palette['purple'] + +# Hints +c.hints.border = '1px solid ' + palette['background-alt'] + +# Font color for the matched part of hints. +c.colors.hints.match.fg = palette['foreground-alt'] + +# Background color of the keyhint widget. +c.colors.keyhint.bg = palette['background'] + +# Text color for the keyhint widget. +c.colors.keyhint.fg = palette['purple'] + +# Highlight color for keys to complete the current keychain. +c.colors.keyhint.suffix.fg = palette['selection'] + +# Background color of an error message. +c.colors.messages.error.bg = palette['background'] + +# Border color of an error message. +c.colors.messages.error.border = palette['background-alt'] + +# Foreground color of an error message. +c.colors.messages.error.fg = palette['red'] + +# Background color of an info message. +c.colors.messages.info.bg = palette['background'] + +# Border color of an info message. +c.colors.messages.info.border = palette['background-alt'] + +# Foreground color an info message. +c.colors.messages.info.fg = palette['comment'] + +# Background color of a warning message. +c.colors.messages.warning.bg = palette['background'] + +# Border color of a warning message. +c.colors.messages.warning.border = palette['background-alt'] + +# Foreground color a warning message. +c.colors.messages.warning.fg = palette['red'] + +# Background color for prompts. +c.colors.prompts.bg = palette['background'] + +# Border used around UI elements in prompts. +c.colors.prompts.border = '1px solid ' + palette['background-alt'] + +# Foreground color for prompts. +c.colors.prompts.fg = palette['cyan'] + +# Background color for the selected item in filename prompts. +c.colors.prompts.selected.bg = palette['selection'] + +# Background color of the statusbar in caret mode. +c.colors.statusbar.caret.bg = palette['background'] + +# Foreground color of the statusbar in caret mode. +c.colors.statusbar.caret.fg = palette['orange'] + +# Background color of the statusbar in caret mode with a selection. +c.colors.statusbar.caret.selection.bg = palette['background'] + +# Foreground color of the statusbar in caret mode with a selection. +c.colors.statusbar.caret.selection.fg = palette['orange'] + +# Background color of the statusbar in command mode. +c.colors.statusbar.command.bg = palette['background'] + +# Foreground color of the statusbar in command mode. +c.colors.statusbar.command.fg = palette['pink'] + +# Background color of the statusbar in private browsing + command mode. +c.colors.statusbar.command.private.bg = palette['background'] + +# Foreground color of the statusbar in private browsing + command mode. +c.colors.statusbar.command.private.fg = palette['foreground-alt'] + +# Background color of the statusbar in insert mode. +c.colors.statusbar.insert.bg = palette['background-attention'] + +# Foreground color of the statusbar in insert mode. +c.colors.statusbar.insert.fg = palette['foreground-attention'] + +# Background color of the statusbar. +c.colors.statusbar.normal.bg = palette['background'] + +# Foreground color of the statusbar. +c.colors.statusbar.normal.fg = palette['foreground'] + +# Background color of the statusbar in passthrough mode. +c.colors.statusbar.passthrough.bg = palette['background'] + +# Foreground color of the statusbar in passthrough mode. +c.colors.statusbar.passthrough.fg = palette['orange'] + +# Background color of the statusbar in private browsing mode. +c.colors.statusbar.private.bg = palette['background-alt'] + +# Foreground color of the statusbar in private browsing mode. +c.colors.statusbar.private.fg = palette['foreground-alt'] + +# Background color of the progress bar. +c.colors.statusbar.progress.bg = palette['background'] + +# Foreground color of the URL in the statusbar on error. +c.colors.statusbar.url.error.fg = palette['red'] + +# Default foreground color of the URL in the statusbar. +c.colors.statusbar.url.fg = palette['foreground'] + +# Foreground color of the URL in the statusbar for hovered links. +c.colors.statusbar.url.hover.fg = palette['cyan'] + +# Foreground color of the URL in the statusbar on successful load +c.colors.statusbar.url.success.http.fg = palette['green'] + +# Foreground color of the URL in the statusbar on successful load +c.colors.statusbar.url.success.https.fg = palette['green'] + +# Foreground color of the URL in the statusbar when there's a warning. +c.colors.statusbar.url.warn.fg = palette['yellow'] + +# Status bar padding +c.statusbar.padding = padding + +# Background color of the tab bar. +# Type: QtColor +c.colors.tabs.bar.bg = palette['selection'] + +# Background color of unselected even tabs. +# Type: QtColor +c.colors.tabs.even.bg = palette['selection'] + +# Foreground color of unselected even tabs. +# Type: QtColor +c.colors.tabs.even.fg = palette['foreground'] + +# Color for the tab indicator on errors. +# Type: QtColor +c.colors.tabs.indicator.error = palette['red'] + +# Color gradient start for the tab indicator. +# Type: QtColor +c.colors.tabs.indicator.start = palette['orange'] + +# Color gradient end for the tab indicator. +# Type: QtColor +c.colors.tabs.indicator.stop = palette['green'] + +# Color gradient interpolation system for the tab indicator. +# Type: ColorSystem +# Valid values: +# - rgb: Interpolate in the RGB color system. +# - hsv: Interpolate in the HSV color system. +# - hsl: Interpolate in the HSL color system. +# - none: Don't show a gradient. +c.colors.tabs.indicator.system = 'none' + +# Background color of unselected odd tabs. +# Type: QtColor +c.colors.tabs.odd.bg = palette['selection'] + +# Foreground color of unselected odd tabs. +# Type: QtColor +c.colors.tabs.odd.fg = palette['foreground'] + +# Background color of selected even tabs. +# Type: QtColor +c.colors.tabs.selected.even.bg = palette['background'] + +# Foreground color of selected even tabs. +# Type: QtColor +c.colors.tabs.selected.even.fg = palette['foreground'] + +# Background color of selected odd tabs. +# Type: QtColor +c.colors.tabs.selected.odd.bg = palette['background'] + +# Foreground color of selected odd tabs. +# Type: QtColor +c.colors.tabs.selected.odd.fg = palette['foreground'] + +# Tab padding +c.tabs.padding = padding +c.tabs.indicator.width = 1 +c.tabs.favicons.scale = 1 diff --git a/.config/shell/aliasrc b/.config/shell/aliasrc @@ -0,0 +1,37 @@ +#!/bin/sh + +# Run some programs in sudo. +for command in mount umount sv pacman pkg updatedb su; do + alias $command="doas $command" +done; unset command + +alias startx="startx \"$XINITRC\"" +alias vim="vim -i ${XDG_DATA_HOME:-$HOME/.local/share}/viminfo" + + +alias \ + ..='cd ..' \ + ...='cd ../..' \ + ....='cd ../../..' + +# Fix colorizing commands. +alias \ + ls="ls -h --color=always" \ + ip="ip --color=auto" \ + grep="grep --color=auto" + +# Lazy Aliases. +alias \ + c="clear -x" \ + e="$EDITOR" \ + g="git" \ + h="htop" \ + l="ls" \ + p="pacman" \ + v="$EDITOR" \ + x="exit" + +# Suckless now with tabbed. +#alias \ +# surf="surf-open" \ +# st="tabbed -c -r 2 st -w ''" diff --git a/.config/shell/inputrc b/.config/shell/inputrc @@ -0,0 +1,15 @@ +set editing-mode vi + +set show-mode-in-prompt on +set vi-ins-mode-string \1\e[6 q\2 +set vi-cmd-mode-string \1\e[2 q\2 + +set keymap vi-command +# these are for vi-command mode +Control-l: clear-screen +Control-a: beginning-of-line + +set keymap vi-insert +# these are for vi-insert mode +Control-l: clear-screen +Control-a: beginning-of-line diff --git a/.config/shell/profile b/.config/shell/profile @@ -0,0 +1,57 @@ +#!/bin/sh +# Environmental variables are set here. (Runs on login) + +# Adds `~/.local/bin/*` to $PATH +#export PATH="$PATH:${$(find ~/.local/bin -type d -printf %p:)%%:}" +# Adds `~/.local/bin` to $PATH +export PATH="$PATH:$HOME/.local/bin" + +# Default Programs +export BROWSER="surf-open" +export EDITOR="vi" +export TERMINAL="st" + +# XDG_CONFIG +export XDG_CACHE_HOME="$HOME/.cache" +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" +export XDG_STATE_HOME="$HOME/.local/state" +export XDG_RUNTIME_DIR="$HOME/.local/run" + +[ -d "$XDG_CACHE_HOME" ] || mkdir -p "$XDG_CACHE_HOME" +[ -d "$XDG_CONFIG_HOME" ] || mkdir -p "$XDG_CONFIG_HOME" +[ -d "$XDG_DATA_HOME" ] || mkdir -p "$XDG_DATA_HOME" +[ -d "$XDG_STATE_HOME" ] || mkdir -p "$XDG_STATE_HOME" +[ -d "$XDG_RUNTIME_DIR" ] || mkdir -p "$XDG_RUNTIME_DIR" + +# Use $XDG_CONFIG_HOME for disrespectful programs +export GNUPGHOME="${XDG_DATA_HOME:-$HOME/.local/share}/gnupg" +export GTK2_RC_FILES="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-2.0/gtkrc-2.0" +export HISTFILE="${XDG_DATA_HOME:-$HOME/.local/share}/history.$(basename "$(echo "${0:-$SHELL}" | sed 's|-||')")" +export INPUTRC="${XDG_CONFIG_HOME:-$HOME/.config}/shell/inputrc" +export MBSYNCRC="${XDG_CONFIG_HOME:-$HOME/.config}/mbsync/mbsyncrc" +export PASSWORD_STORE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/password-store" +export WGETRC="${XDG_CONFIG_HOME:-$HOME/.config}/wget/wgetrc" +export LESSHISTFILE="${XDG_DATA_HOME:-$HOME/.local/share}/lesshst" +#export XAUTHORITY="${XDG_RUNTIME_DIR}/Xauthority" +export XINITRC="${XDG_CONFIG_HOME:-$HOME/.config}/x11/xinitrc" + +export DOAS_ASKPASS="dmenu -P -p Password:" +export QT_STYLE_OVERRIDE="kvantum" + +if [ "$(tty)" = "/dev/tty1" ] || [ "$(tty)" = "/dev/ttyv0" ]; then + pidof -s Xorg >/dev/null 2>&1 || exec startx "$XINITRC" +fi + +## Start graphics if 'libxft-bgra' was installed and already not running. +#if pacman -Q libxft-bgra >/dev/null 2>&1; then +# [ "$(tty)" = "/dev/tty1" ] && ! pidof -s Xorg >/dev/null 2>&1 && exec startx "$XINITRC" +#else +# printf "\033[31mIMPORTANT\033[0m: Note that \033[32m\`libxft-bgra\`\033[0m must be installed for my build of dwm, st, ...\n" +# printf "Please run:\n" +# printf "\033[32m\tgit clone https://mahdi.pw/git/libxft.git\n\033[0m" +# printf "\033[32m\tcd libxft\n\033[0m" +# printf "\033[32m\tmakepkg -si\n\033[0m" +# printf "and replace 'libxft' (if not replaced by pacman).\n" +# printf "Afterwards enter the graphical server using: \033[34mstartx \"$XINITRC\"\033[0m\n" +#fi diff --git a/.config/surf/script.js b/.config/surf/script.js @@ -0,0 +1 @@ +/* This is cool */ diff --git a/.config/surf/styles/default.css b/.config/surf/styles/default.css @@ -0,0 +1,25 @@ +/*html, img { -webkit-filter: invert(1) hue-rotate(180deg); }*/ +*, *::before, *::after { background-image: none !important; } +/*a,button,col,div,textarea,body,input,form,td,tr,th,p,span,article,svg,header,footer,details,summary { */ +html,head,body,header,footer,a,p,h1,h2,h3,h4,h5,h6,h7,div,ul,li,dl,dt,q,pre,code,blockquote,i,u,input,button,tag,table,thead,tbody,tfoot,td,tr,th,span,article,details,summary,textarea,div,a,svg,label,aside,main { +/*,*, *::before, *::after { */ + background-color: #1E2127 !important; + border-color: #5C6370 !important; + color: #ABB2BF !important; +} +blockquote, pre, code, code>* { + background-color: #1E2127 !important; + border-color: #5C6370 !important; + color: #ABB2BF !important; + padding: 5px; + font-family: monospace; +} + +a:link { color: #56B6C2 !important; } +a:hover { color: #C678DD !important; } +a:visited { color: #C678DD !important; } +input:hover { color: #56B6C2 !important; } +button:hover { color: #56B6C2 !important; } + +img { opacity: .75; } +img:hover { opacity: 1; } diff --git a/.config/surf/styles/default.css.in b/.config/surf/styles/default.css.in @@ -0,0 +1,25 @@ +/*html, img { -webkit-filter: invert(1) hue-rotate(180deg); }*/ +*, *::before, *::after { background-image: none !important; } +/*a,button,col,div,textarea,body,input,form,td,tr,th,p,span,article,svg,header,footer,details,summary { */ +html,head,body,header,footer,a,p,h1,h2,h3,h4,h5,h6,h7,div,ul,li,dl,dt,q,pre,code,blockquote,i,u,input,button,tag,table,thead,tbody,tfoot,td,tr,th,span,article,details,summary,textarea,div,a,svg,label,aside,main { +/*,*, *::before, *::after { */ + background-color: %cl0% !important; + border-color: %cl8% !important; + color: %cl7% !important; +} +blockquote, pre, code, code>* { + background-color: %cl0% !important; + border-color: %cl8% !important; + color: %cl7% !important; + padding: 5px; + font-family: monospace; +} + +a:link { color: %cl6% !important; } +a:hover { color: %cl5% !important; } +a:visited { color: %cl13% !important; } +input:hover { color: %cl14% !important; } +button:hover { color: %cl14% !important; } + +img { opacity: .75; } +img:hover { opacity: 1; } diff --git a/.config/vis/visrc.lua b/.config/vis/visrc.lua @@ -0,0 +1,50 @@ +require('vis') + +vis.events.subscribe(vis.events.INIT, function() + -- Your global configuration options +end) + +vis.events.subscribe(vis.events.WIN_OPEN, function(win) + -- Your per window configuration options e.g. + vis:command('set number') + --vis:command('set relativenumbers') + --vis:command('set expandtab') + vis:command('set tabwidth 4') + vis:command('set escdelay 0') + vis:command('set show-eof off') + vis:command('set theme dark-16') + vis:command('set autoindent on') +end) + +-- Backspace removes 4 spaces if need be +vis:map(vis.modes.INSERT, '<Backspace>', function() + local tabwidth = 4 + local single_selection = false + for selection in vis.win:selections_iterator() do + if single_selection then + single_selection = false + break + end + single_selection = true + end + + local to_stop = (vis.win.selection.col - 1) % tabwidth + if to_stop == 0 then + to_stop = tabwidth + end + + if single_selection and to_stop > 1 and vis.win.file:content(vis.win.selection.pos - to_stop, to_stop) == string.rep(' ', to_stop) then + vis:feedkeys(string.rep('<vis-delete-char-prev>', to_stop)) + else + vis:feedkeys('<vis-delete-char-prev>') + end +end) + +-- Strip trailing spaces +vis:command_register("sts", function(argv, force, win, selection, range) + local lines = win.file.lines + for index=1, #lines do + lines[index] = lines[index]:gsub("%s+$", "") + end + return true +end, "Strip line trailing spaces") diff --git a/.config/wget/wgetrc b/.config/wget/wgetrc @@ -0,0 +1,3 @@ +progress=bar +hsts-file=~/.local/share/wget-hsts +#use-askpass=dmenu-askpass diff --git a/.config/x11/colors b/.config/x11/colors @@ -0,0 +1,31 @@ +! Custom +! Original theme https://github.com/nathanbuchar/atom-one-dark-terminal +*.foreground: #ABB2BF +*.background: #1E2127 +*.cursorColor: #5C6370 +*.highlightColor:#3A3F4B + +! Negro y gris +*.color0: #1E2127 +*.color8: #5C6370 +! Rojos +*.color1: #E06C75 +*.color9: #E06C75 +! Verde +*.color2: #98C379 +*.color10: #98C379 +! Amarillo +*.color3: #D19A66 +*.color11: #D19A66 +! Azul +*.color4: #61AFEF +*.color12: #61AFEF +! Magenta +*.color5: #C678DD +*.color13: #C678DD +! Cyan +*.color6: #56B6C2 +*.color14: #56B6C2 +! Blanco +*.color7: #ABB2BF +*.color15: #FFFFFF diff --git a/.config/x11/fonts b/.config/x11/fonts @@ -0,0 +1,10 @@ +! ---------------------- +! Xft Font Configuration +! ---------------------- +Xft.autohint: 0 +Xft.lcdfilter: lcddefault +Xft.hintstyle: hintslight +Xft.hinting: 1 +Xft.antialias: 1 +Xft.rgba: rgb +!Xft.dpi: 100 diff --git a/.config/x11/themes/dracula b/.config/x11/themes/dracula @@ -0,0 +1,20 @@ +! Dracula Xresources palette +*.foreground: #f8f8f2 +*.background: #282a36 +*.cursorColor: #6272a4 +*.color0: #282a36 +*.color8: #4D4D4D +*.color1: #FF5555 +*.color9: #FF6E67 +*.color2: #50FA7B +*.color10: #5AF78E +*.color3: #F1FA8C +*.color11: #F4F99D +*.color4: #BD93F9 +*.color12: #CAA9FA +*.color5: #FF79C6 +*.color13: #FF92D0 +*.color6: #8BE9FD +*.color14: #9AEDFE +*.color7: #BFBFBF +*.color15: #E6E6E6 diff --git a/.config/x11/themes/gruvbox-dark b/.config/x11/themes/gruvbox-dark @@ -0,0 +1,46 @@ +! ----------------------------------------------------------------------------- +! File: gruvbox-dark.xresources +! Description: Retro groove colorscheme generalized +! Author: morhetz <[email protected]> +! Source: https://github.com/morhetz/gruvbox-generalized +! Last Modified: 6 Sep 2014 +! ----------------------------------------------------------------------------- + +! hard contrast: *.background: #1d2021 +! soft contrast: *.background: #32302f + +*.background: #282828 +*.foreground: #ebdbb2 +*.cursorColor: #928374 + +! Black + DarkGrey +*.color0: #282828 +*.color8: #928374 + +! DarkRed + Red +*.color1: #cc241d +*.color9: #fb4934 + +! DarkGreen + Green +*.color2: #98971a +*.color10: #b8bb26 + +! DarkYellow + Yellow +*.color3: #d79921 +*.color11: #fabd2f + +! DarkBlue + Blue +*.color4: #458588 +*.color12: #83a598 + +! DarkMagenta + Magenta +*.color5: #b16286 +*.color13: #d3869b + +! DarkCyan + Cyan +*.color6: #689d6a +*.color14: #8ec07c + +! LightGrey + White +*.color7: #a89984 +*.color15: #ebdbb2 diff --git a/.config/x11/themes/nord b/.config/x11/themes/nord @@ -0,0 +1,47 @@ +! Copyright (c) 2016-present Arctic Ice Studio <[email protected]> +! Copyright (c) 2016-present Sven Greb <[email protected]> + +! Project: Nord XResources +! Version: 0.1.0 +! Repository: https://github.com/arcticicestudio/nord-xresources +! License: MIT + +#define nord0 #2E3440 +#define nord1 #3B4252 +#define nord2 #434C5E +#define nord3 #4C566A +#define nord4 #D8DEE9 +#define nord5 #E5E9F0 +#define nord6 #ECEFF4 +#define nord7 #8FBCBB +#define nord8 #88C0D0 +#define nord9 #81A1C1 +#define nord10 #5E81AC +#define nord11 #BF616A +#define nord12 #D08770 +#define nord13 #EBCB8B +#define nord14 #A3BE8C +#define nord15 #B48EAD + +*.foreground: nord4 +*.background: nord0 +*.cursorColor: nord4 +*fading: 35 +*fadeColor: nord3 + +*.color0: nord1 +*.color1: nord11 +*.color2: nord14 +*.color3: nord13 +*.color4: nord9 +*.color5: nord15 +*.color6: nord8 +*.color7: nord5 +*.color8: nord3 +*.color9: nord11 +*.color10: nord14 +*.color11: nord13 +*.color12: nord9 +*.color13: nord15 +*.color14: nord7 +*.color15: nord6 diff --git a/.config/x11/themes/oceanic-next b/.config/x11/themes/oceanic-next @@ -0,0 +1,40 @@ +! Base16 OceanicNext +! Scheme: https://github.com/voronianski/oceanic-next-color-scheme + +#define base00 #1B2B34 +#define base01 #343D46 +#define base02 #4F5B66 +#define base03 #65737E +#define base04 #A7ADBA +#define base05 #C0C5CE +#define base06 #CDD3DE +#define base07 #D8DEE9 +#define base08 #EC5f67 +#define base09 #F99157 +#define base0A #FAC863 +#define base0B #99C794 +#define base0C #5FB3B3 +#define base0D #6699CC +#define base0E #C594C5 +#define base0F #AB7967 + +*.foreground: base05 +*.background: base00 +*.cursorColor: base05 + +*.color0: base00 +*.color1: base08 +*.color2: base0B +*.color3: base0A +*.color4: base0D +*.color5: base0E +*.color6: base0C +*.color7: base05 +*.color8: base03 +*.color9: base09 +*.color10: base01 +*.color11: base02 +*.color12: base04 +*.color13: base06 +*.color14: base0F +*.color15: base07 diff --git a/.config/x11/themes/onedark b/.config/x11/themes/onedark @@ -0,0 +1,32 @@ +! Custom +! Original theme https://github.com/nathanbuchar/atom-one-dark-terminal +*.foreground: #ABB2BF +*.background: #1E2127 +*.cursorColor: #5C6370 +*.highlightColor:#3A3F4B + +! Negro y gris +*.color0: #1E2127 +*.color8: #5C6370 +! Rojos +*.color1: #E06C75 +*.color9: #E06C75 +! Verde +*.color2: #98C379 +*.color10: #98C379 +! Amarillo +*.color3: #D19A66 +*.color11: #D19A66 +! Azul +*.color4: #61AFEF +*.color12: #61AFEF +! Magenta +*.color5: #C678DD +*.color13: #C678DD +! Cyan +*.color6: #56B6C2 +*.color14: #56B6C2 +! Blanco +*.color7: #ABB2BF +*.color15: #FFFFFF + diff --git a/.config/x11/themes/solarized-dark b/.config/x11/themes/solarized-dark @@ -0,0 +1,36 @@ +*.foreground: #708284 +*.background: #001e27 +*.cursorColor: #708284 +! +! Black +*.color0: #002831 +*.color8: #001e27 +! +! Red +*.color1: #d11c24 +*.color9: #bd3613 +! +! Green +*.color2: #738a05 +*.color10: #475b62 +! +! Yellow +*.color3: #a57706 +*.color11: #536870 +! +! Blue +*.color4: #2176c7 +*.color12: #708284 +! +! Magenta +*.color5: #c61c6f +*.color13: #5956ba +! +! Cyan +*.color6: #259286 +*.color14: #819090 +! +! White +*.color7: #eae3cb +*.color15: #fcf4dc + diff --git a/.config/x11/themes/tomorrownight b/.config/x11/themes/tomorrownight @@ -0,0 +1,32 @@ +! Hybrid Terminal Colours. Uses the palette from Tomorrow-Night: +! https://github.com/chriskempson/tomorrow-theme/blob/master/vim/colors/Tomorrow-Night.vim +! vim: ft=xdefaults + +*.background: #1D1F21 +*.foreground: #C5C8C6 +*.cursorColor: #373B41 +! black +*.color0: #282A2E +*.color8: #373B41 +! red +*.color1: #A54242 +*.color9: #CC6666 +! green +*.color2: #8C9440 +*.color10: #B5BD68 +! yellow +*.color3: #DE935F +*.color11: #F0C674 +! blue +*.color4: #5F819D +*.color12: #81A2BE +! magenta +*.color5: #85678F +*.color13: #B294BB +! cyan +*.color6: #5E8D87 +*.color14: #8ABEB7 +! white +*.color7: #707880 +*.color15: #C5C8C6 + diff --git a/.config/x11/xinitrc b/.config/x11/xinitrc @@ -0,0 +1,48 @@ +#!/bin/sh +UXR="${XDG_CONFIG_HOME:-$HOME/.config}"/x11/xresources +UMM="${XDG_CONFIG_HOME:-$HOME/.config}"/x11/xmodmap + +[ -f "$UXR" ] && xrdb -merge "$UXR" +[ -f "$UMM" ] && xmodmap "$UMM" + +# Autostart: +setsid -f xsetroot -cursor_name left_ptr +setsid -f xautolock -time 10 -locker slock +[ -f "$HOME/.cache/theme" ] || theme-sel +pidof -x "dunst" || setsid -f "dunst" +pidof -x "picom" || setsid -f "picom" +#pidof -x "picom" || setsid -f "picom --experimental-backends" +pidof -x "bg-gen" || setsid -f "bg-gen" +pidof -x "dwm-bar" || setsid -f "dwm-bar" +pidof -x "pipewire" || setsid -f "pipewire" +pidof -x "pipewire-alsa" || setsid -f "pipewire-alsa" +pidof -x "pipewire-jack" || setsid -f "pipewire-jack" +pidof -x "pipewire-pulse" || setsid -f "pipewire-pulse" +pidof -x "pipewire-media-session" || setsid -f "pipewire-media-session" + +# Monitors: +i=0 +for MONITOR in $(xrandr | awk '$2 == "connected"{print $1}'); do + if [ "$i" -eq 0 ]; then + xrandr --output "$MONITOR" --auto --primary + LAST_MONITOR="$MONITOR" + else + xrandr --output "$MONITOR" --auto + xrandr --output "$LAST_MONITOR" --above "$MONITOR" + LAST_MONITOR="$MONITOR" + fi + i=$((i+1)) +done + +# Keyboard - Fix for my layouts: +setxkbmap -layout us,ir +setxkbmap -option 'grp:caps_toggle' + +# Keyboard - Fix for my laptop's broken keyboard: +xmodmap -e "clear mod1" +xmodmap -e "keycode 108 = p P Arabic_hah bracketleft" +xmodmap -e "add mod1 = Alt_L Meta_L" + +# Add -f after startx to experience dwm in floating mode. +ssh-agent dwm "$@" +ssh-add diff --git a/.config/x11/xresources b/.config/x11/xresources @@ -0,0 +1,2 @@ +#include "colors" +#include "fonts" diff --git a/.config/yt-dlp/config b/.config/yt-dlp/config @@ -0,0 +1,17 @@ +--add-metadata +--embed-thumbnail +-ic + +# Video quality (my default: 480p) +-f bestvideo[height<=480]+bestaudio/best[height<=480] +#-f bestvideo[height<=720]+bestaudio/best[height<=720] +#-f bestvideo[height<=1080]+bestaudio/best[height<=1080] +#-f bestvideo[height<=2160]+bestaudio/best[height<=2160] + +# Add subtitles to video +--sub-lang en +--write-sub +--embed-subs + +# Cookies are good +--cookies ~/.local/share/yt-cookies.txt diff --git a/.config/zathura/zathurarc b/.config/zathura/zathurarc @@ -0,0 +1,41 @@ +# General +set selection-clipboard clipboard # Enable copy to clipboard +set first-page-column 1:1 # Side-by-side mode +set recolor true # Recolor pages +set render-loading true # Render "Loading..." +set statusbar-home-tilde true # Use ~ instead of $HOME in the filename +set window-title-basename true # Use basename of the file in the window title +set adjust-open width # Adjust to when opening file + +# Keybinds +map b toggle_statusbar + +# Theme +set default-bg "#1E2127" +set default-fg "#ABB2BF" +set statusbar-bg "#1E2127" +set statusbar-fg "#ABB2BF" +set inputbar-bg "#1E2127" +set inputbar-fg "#56B6C2" +set completion-bg "#1E2127" +set completion-fg "#ABB2BF" +set completion-group-bg "#1E2127" +set completion-group-fg "#ABB2BF" +set completion-highlight-bg "#5C6370" +set completion-highlight-fg "#ABB2BF" +set notification-bg "#5C6370" +set notification-fg "#FFFFFF" +set notification-error-bg "#E06C75" +set notification-error-fg "#FFFFFF" +set notification-warning-bg "#D19A66" +set notification-warning-fg "#1E2127" +set highlight-color "#56B6C2" +set highlight-active-color "#56B6C2" +set index-bg "#1E2127" +set index-fg "#ABB2BF" +set index-active-bg "#5C6370" +set index-active-fg "#ABB2BF" +set recolor-darkcolor "#ABB2BF" +set recolor-lightcolor "#1E2127" +set render-loading-bg "#1E2127" +set render-loading-fg "#ABB2BF" diff --git a/.config/zathura/zathurarc.in b/.config/zathura/zathurarc.in @@ -0,0 +1,41 @@ +# General +set selection-clipboard clipboard # Enable copy to clipboard +set first-page-column 1:1 # Side-by-side mode +set recolor true # Recolor pages +set render-loading true # Render "Loading..." +set statusbar-home-tilde true # Use ~ instead of $HOME in the filename +set window-title-basename true # Use basename of the file in the window title +set adjust-open width # Adjust to when opening file + +# Keybinds +map b toggle_statusbar + +# Theme +set default-bg "%clbg%" +set default-fg "%clfg%" +set statusbar-bg "%clbg%" +set statusbar-fg "%clfg%" +set inputbar-bg "%clbg%" +set inputbar-fg "%cl6%" +set completion-bg "%clbg%" +set completion-fg "%clfg%" +set completion-group-bg "%clbg%" +set completion-group-fg "%clfg%" +set completion-highlight-bg "%cl8%" +set completion-highlight-fg "%clfg%" +set notification-bg "%cl8%" +set notification-fg "%cl15%" +set notification-error-bg "%cl9%" +set notification-error-fg "%cl15%" +set notification-warning-bg "%cl11%" +set notification-warning-fg "%clbg%" +set highlight-color "%cl14%" +set highlight-active-color "%cl6%" +set index-bg "%clbg%" +set index-fg "%clfg%" +set index-active-bg "%cl8%" +set index-active-fg "%clfg%" +set recolor-darkcolor "%clfg%" +set recolor-lightcolor "%clbg%" +set render-loading-bg "%clbg%" +set render-loading-fg "%clfg%" diff --git a/.kshrc b/.kshrc @@ -0,0 +1,32 @@ +#!/bin/ksh +[ -f "$HOME/.config/shell/profile" ] && . $HOME/.config/shell/profile +[ -f "$HOME/.config/shell/aliasrc" ] && . $HOME/.config/shell/aliasrc +[ -f "$HOME/.config/shell/functions" ] && . $HOME/.config/shell/functions + +hostname(){ cat /etc/hostname; } + +# Prompt +if [ "$(id -u)" -eq 0 ]; then + PS1="$(printf " \033[90m[ \033[35m%s\033[0m\033[94m@\033[34m%s\033[0m \033[36m%s\033[0m\033[90m ]\033[0m # " \ + "$(whoami)" "$(hostname)" '${PWD/#"$HOME"/\~}')" +else + PS1="$(printf " \033[36m[%s]\033[0m " '${PWD/#"$HOME"/\~}')" + #PS1="$(printf " \033[90m[ \033[35m%s\033[0m\033[94m@\033[34m%s\033[0m \033[36m%s\033[0m\033[90m ]\033[0m \$ " \ + # "$(whoami)" "$(hostname)" '${PWD/#"$HOME"/\~}')" + #PS1="$(printf " \033[90m[ \033[1;34m\033[32m%s \033[35m%s\033[0m\033[94m@\033[34m%s\033[0m \033[36m%s\033[0m\033[90m ]\033[0m \$ " \ + # '$(date +%H:%M)' "$(whoami)" "$(hostname)" '${PWD/#"$HOME"/\~}')" +fi + +# Shell options +set -o emacs # Edit mode +set +o histexpand # csh-style history off +set -o multiline # turn on multiline mode +set -o notify # immediate notification from background jobs + +# Binds +alias __A=`echo "\020"` # up arrow = ^p = back a command +alias __B=`echo "\016"` # down arrow = ^n = down a command +alias __C=`echo "\006"` # right arrow = ^f = forward a character +alias __D=`echo "\002"` # left arrow = ^b = back a character +alias __H=`echo "\001"` # home = ^a = start of line +alias __Y=`echo "\005"` # end = ^e = end of line diff --git a/.local/bin/bg-gen b/.local/bin/bg-gen @@ -0,0 +1,22 @@ +#!/bin/sh +bg_set() { xwallpaper --zoom "$1"; } + +CL1="$(xrdb -query | awk '/color0/{print $2;exit}')" +CL2="$(xrdb -query | awk '/color12/{print $2;exit}')" + +IMG="${XDG_CACHE_HOME:-$HOME/.cache}/bg-gen/${CL1}_${CL2}.png" + +if [ ! -f "$IMG" ]; then + #RES="683x384" + RES="1366x768" + #TAGS="xc: -attenuate 0.3 +noise Random" + #TAGS="xc: -attenuate 0.3 -attenuate 0.3 +noise Random" + #TAGS="xc: -attenuate 0.3 -attenuate 0.3 +noise Random -paint 10" + TAGS="plasma:" + magick -size "$RES" $TAGS \ + -channel B -separate +channel \ + +level-colors "$CL1,$CL2" \ + "$IMG" +fi + +bg_set "$IMG" diff --git a/.local/bin/bg-set b/.local/bin/bg-set @@ -0,0 +1,65 @@ +#!/bin/sh +# OLD: I use bg-gen instead. +# +bg_set() { xwallpaper --zoom "$1"; } + +THEME="$(cat "$HOME"/.cache/theme || echo "nord")" +WLPS="$HOME/.local/share/wallpapers/$THEME" + +# Image Preview Configuration +WID="$(xdotool getwindowfocus)" +ID="setbg-preview-ueberzug-${WID}" +IMAGE="/tmp/setbg-image-${WID}.png" +FIFO="/tmp/setbg-preview-ueberzug-fifo-${WID}" +WIDTH=$FZF_PREVIEW_COLUMNS +HEIGHT=$FZF_PREVIEW_LINES +VPAD=$(fzf --version | { + IFS='. ' read -r v1 v2 _ + [ "$v1" = 0 ] && [ "$v2" -le 26 ] && echo 0 || echo 4 +}) + +# Image Preview +start_ueberzug() { + rm -f "$FIFO" "$IMAGE" > /dev/null 2>&1 + mkfifo "$FIFO" || exit 1 + ueberzug layer -p json -s < "$FIFO" & + exec 3> "$FIFO" +} +stop_ueberzug() { + exec 3>&- + printf '{ "action": "remove", "identifier": "%s" }\n' "$ID" > "$FIFO" + rm -f "$FIFO" "$IMAGE" > /dev/null 2>&1 +} +clean_ueberzug() { + printf '{ "action": "remove", "identifier": "%s" }\n' "$ID" > "$FIFO" +} +image_preview() { + printf '{ "action": "add", "identifier": "%s", "path": "%s", "x": %d, "y": %d, "scaler": "fit_contain", "width": %d, "height": %d }\n' \ + "$ID" "$IMG" "$((WIDTH + VPAD))" 4 "$((WIDTH - VPAD))" "$((HEIGHT))" > "$FIFO" \ + || printf '{ "action": "remove", "identifier": "%s" }\n' "$ID" > "$FIFO" + exit 1 +} + +if [ "$SET_BG_SELECT" ]; then + cd "$WLPS" + if [ "$#" = 0 ]; then + trap stop_ueberzug EXIT QUIT INT TERM + start_ueberzug + OUTPUT="$(find -type f -printf '%P\n' | sort | fzf -i -e \ + --layout=reverse --border=sharp --info=inline --preview "sh $0 {}" \ + --preview-window "right:50%:noborder:wrap" --bind "µ:toggle-preview+toggle-preview")" + if [ "$OUTPUT" ]; then + stop_ueberzug + bg_set "$WLPS/$OUTPUT" + fi + elif [ "$#" = 1 ]; then + clean_ueberzug + IMG="/tmp/setbg-thumb-$1" + convert -thumbnail 300x "$1" "$IMG" + image_preview "$IMG" + rm "$IMG" + fi +else + WLPS="${1:-$WLPS}" + [ "${WLPS}" ] && bg_set "${WLPS}" +fi diff --git a/.local/bin/bright b/.local/bin/bright @@ -0,0 +1,96 @@ +#!/bin/sh +# Notes for linux users: +# Add backlight rules to change your card's file permissions to the group `video` +# /etc/udev/rules.d/backlight.rules: +# ---------------------------------- +# RUN+="/bin/chgrp video /sys/class/backlight/amdgpu_bl0/brightness" + +BRIGHTNESS_ACT="get" +BRIGHTNESS_STEPS="10" + +KERNEL=$(uname) + +case "$KERNEL" in + Linux*) + BRIGHTNESS_CARD=$(ls /sys/class/backlight | head -n 1) + BRIGHTNESS_MAX=$(cat "${BRIGHTNESS_CARD}/max_brightness") + BRIGHTNESS=$(cat "${BRIGHTNESS_CARD}/brightness") + BRIGHTNESS=$((BRIGHTNESS*100/BRIGHTNESS_MAX)) + BRIGHTNESS=${BRIGHTNESS%.*} + ;; + FreeBSD*) + BRIGHTNESS_MAX=100 + BRIGHTNESS=$(backlight | cut -d ' ' -f 2) + ;; + OpenBSD*) + BRIGHTNESS_MAX=100 + BRIGHTNESS=$(apm -l) + ;; +esac + +while getopts ':gidos:c:' flag; do + case "${flag}" in + g) BRIGHTNESS_ACT="get" ;; + i) BRIGHTNESS_ACT="inc" ;; + d) BRIGHTNESS_ACT="dec" ;; + o) BRIGHTNESS_ACT="opt" ;; + s) BRIGHTNESS_STEPS="${OPTARG}" ;; + c) BRIGHTNESS_CARD="${OPTARG}" ;; + *) + printf 'Usage: %s [-g] [-d] [-u] [-o] [-c card] [-s brightness steps (in %%)]\n' "$0" + printf ' -g: get brightness\n' + printf ' -i: increase brightness\n' + printf ' -d: decrease brightness\n' + printf ' -o: optimal brightness\n' + exit 2 + ;; + esac +done + +case "$BRIGHTNESS_ACT" in + get) + pkill -SIGUSR1 merbe + merbe "$BRIGHTNESS_ICON $BRIGHTNESS" & + exit + ;; + inc) + BRIGHTNESS_NEW="$((BRIGHTNESS+BRIGHTNESS_STEPS))" + ;; + dec) + BRIGHTNESS_NEW="$((BRIGHTNESS-BRIGHTNESS_STEPS))" + ;; + opt) + TMPFILE=$(mktemp /tmp/backlight-optimal-XXXXXXX.jpg) + ffmpeg -y -loglevel quiet -f v4l2 -i /dev/video0 -frames:v 1 -f image2 "$TMPFILE" + AVG=$(convert "$TMPFILE" -format "%[mean]" info:) + rm "$TMPFILE" + BRIGHTNESS_NEW=$(printf '%s' "$AVG" | awk '{print int($1/65535*100+30)}') + ;; +esac + +BRIGHTNESS_NEW=$((BRIGHTNESS_NEW * BRIGHTNESS_MAX / 100)) +[ "$BRIGHTNESS_NEW" -gt "$BRIGHTNESS_MAX" ] && BRIGHTNESS_NEW=$BRIGHTNESS_MAX +[ "$BRIGHTNESS_NEW" -lt "1" ] && BRIGHTNESS_NEW=1 + +case "$KERNEL" in + Linux*) + echo "$BRIGHTNESS_NEW" > "${BRIGHTNESS_CARD}/brightness" + ;; + FreeBSD*) + backlight "$BRIGHTNESS_NEW" + ;; + OpenBSD*) + apm -s "$BRIGHTNESS_NEW" + ;; +esac + +BRIGHTNESS="$((BRIGHTNESS_NEW*100/BRIGHTNESS_MAX))" +if [ "$BRIGHTNESS" -le 25 ]; then + BRIGHTNESS_ICON="" +elif [ "$BRIGHTNESS" -le 60 ]; then + BRIGHTNESS_ICON="" +else + BRIGHTNESS_ICON="" +fi +pkill -SIGUSR1 merbe +merbe "$BRIGHTNESS_ICON $BRIGHTNESS" & diff --git a/.local/bin/dmenu-archwiki b/.local/bin/dmenu-archwiki @@ -0,0 +1,10 @@ +#!/bin/sh +# Install: arch-wiki-doc +wikipath="/usr/share/doc/arch-wiki/html/en" +wikimenu () { + for file in $wikipath/*; do + [ -f $file ] && printf '%s\n' "${file##*/}" + done +} +wikipage="$(wikimenu | dmenu -i -l 20 -p "Choose Wiki:")" +[ -z "$wikipage" ] || "${BROWSER:-xdg-open}" "$wikipath/$wikipage" diff --git a/.local/bin/dmenu-askpass b/.local/bin/dmenu-askpass @@ -0,0 +1,3 @@ +#!/bin/sh +# Needs password patch for dmenu +dmenu -P -p "${1:-Password: }" <&- && echo diff --git a/.local/bin/dmenu-emoji b/.local/bin/dmenu-emoji @@ -0,0 +1,1831 @@ +#!/bin/sh +active_window="$(xdotool getactivewindow)" +emoji="$(sed '0,/^__DATA__$/d' "$0" | sed -e 's/\ufe0f//g' | dmenu -i -l 20 | sed 's/ .*//')" +xdotool windowactivate "$active_window" +[ "$emoji" ] || exit + +case "$1" in + [Cc]|[Cc][Ll][Ii][Pp][Bb][Oo][Aa][Rr][Dd]) + echo "$emoji" | xclip -selection clipboard + merbe "Emoji" "Copied $emoji to clipboard!" + ;; + *) + xdotool type -delay 100 "$emoji" + ;; +esac + +exit $? + +__DATA__ +😀 grinning face (face, grin) +😃 grinning face with big eyes (face, mouth, open, smile) +😄 grinning face with smiling eyes (eye, face, mouth, open, smile) +😁 beaming face with smiling eyes (eye, face, grin, smile) +😆 grinning squinting face (face, laugh, mouth, satisfied, smile) +😅 grinning face with sweat (cold, face, open, smile, sweat) +🤣 rolling on the floor laughing (face, floor, laugh, rofl, rolling, rotfl) +😂 face with tears of joy (face, joy, laugh, tear) +🙂 slightly smiling face (face, smile) +🙃 upside-down face (face, upside-down) +😉 winking face (face, wink) +😊 smiling face with smiling eyes (blush, eye, face, smile) +😇 smiling face with halo (angel, face, fantasy, halo, innocent) +🥰 smiling face with hearts (adore, crush, hearts, in love) +😍 smiling face with heart-eyes (eye, face, love, smile) +🤩 star-struck (eyes, face, grinning, star) +😘 face blowing a kiss (face, kiss) +😗 kissing face (face, kiss) +☺️ smiling face (face, outlined, relaxed, smile) +😚 kissing face with closed eyes (closed, eye, face, kiss) +😙 kissing face with smiling eyes (eye, face, kiss, smile) +🥲 smiling face with tear (grateful, proud, relieved, smiling, tear, touched) +😋 face savoring food (delicious, face, savouring, smile, yum) +😛 face with tongue (face, tongue) +😜 winking face with tongue (eye, face, joke, tongue, wink) +🤪 zany face (eye, goofy, large, small) +😝 squinting face with tongue (eye, face, horrible, taste, tongue) +🤑 money-mouth face (face, money, mouth) +🤗 hugging face (face, hug, hugging, open hands, smiling face, smiling face with open hands) +🤭 face with hand over mouth (whoops) +🤫 shushing face (quiet, shush) +🤔 thinking face (face, thinking) +🤐 zipper-mouth face (face, mouth, zipper) +🤨 face with raised eyebrow (distrust, skeptic) +😐 neutral face (deadpan, face, meh, neutral) +😑 expressionless face (expressionless, face, inexpressive, meh, unexpressive) +😶 face without mouth (face, mouth, quiet, silent) +😶‍🌫️ face in clouds +😏 smirking face (face, smirk) +😒 unamused face (face, unamused, unhappy) +🙄 face with rolling eyes (eyeroll, eyes, face, rolling) +😬 grimacing face (face, grimace) +😮‍💨 face exhaling +🤥 lying face (face, lie, pinocchio) +😌 relieved face (face, relieved) +😔 pensive face (dejected, face, pensive) +😪 sleepy face (face, good night, sleep) +🤤 drooling face (drooling, face) +😴 sleeping face (face, good night, sleep, ZZZ) +😷 face with medical mask (cold, doctor, face, mask, sick) +🤒 face with thermometer (face, ill, sick, thermometer) +🤕 face with head-bandage (bandage, face, hurt, injury) +🤢 nauseated face (face, nauseated, vomit) +🤮 face vomiting (puke, sick, vomit) +🤧 sneezing face (face, gesundheit, sneeze) +🥵 hot face (feverish, heat stroke, hot, red-faced, sweating) +🥶 cold face (blue-faced, cold, freezing, frostbite, icicles) +🥴 woozy face (dizzy, intoxicated, tipsy, uneven eyes, wavy mouth) +😵 knocked-out face (crossed-out eyes, dead, face, face with crossed-out eyes, knocked out) +😵‍💫 face with spiral eyes +🤯 exploding head (mind blown, shocked) +🤠 cowboy hat face (cowboy, cowgirl, face, hat) +🥳 partying face (celebration, hat, horn, party) +🥸 disguised face (disguise, face, glasses, incognito, nose) +😎 smiling face with sunglasses (bright, cool, face, sun, sunglasses) +🤓 nerd face (face, geek, nerd) +🧐 face with monocle (face, monocle, stuffy) +😕 confused face (confused, face, meh) +😟 worried face (face, worried) +🙁 slightly frowning face (face, frown) +☹️ frowning face (face, frown) +😮 face with open mouth (face, mouth, open, sympathy) +😯 hushed face (face, hushed, stunned, surprised) +😲 astonished face (astonished, face, shocked, totally) +😳 flushed face (dazed, face, flushed) +🥺 pleading face (begging, mercy, puppy eyes) +😦 frowning face with open mouth (face, frown, mouth, open) +😧 anguished face (anguished, face) +😨 fearful face (face, fear, fearful, scared) +😰 anxious face with sweat (blue, cold, face, rushed, sweat) +😥 sad but relieved face (disappointed, face, relieved, whew) +😢 crying face (cry, face, sad, tear) +😭 loudly crying face (cry, face, sad, sob, tear) +😱 face screaming in fear (face, fear, munch, scared, scream) +😖 confounded face (confounded, face) +😣 persevering face (face, persevere) +😞 disappointed face (disappointed, face) +😓 downcast face with sweat (cold, face, sweat) +😩 weary face (face, tired, weary) +😫 tired face (face, tired) +🥱 yawning face (bored, tired, yawn) +😤 face with steam from nose (face, triumph, won) +😡 pouting face (enraged face, angry, enraged, face, mad, pouting, rage, red) +😠 angry face (anger, angry, face, mad) +🤬 face with symbols on mouth (swearing) +😈 smiling face with horns (face, fairy tale, fantasy, horns, smile) +👿 angry face with horns (demon, devil, face, fantasy, imp) +💀 skull (death, face, fairy tale, monster) +☠️ skull and crossbones (crossbones, death, face, monster, skull) +💩 pile of poo (dung, face, monster, poo, poop) +🤡 clown face (clown, face) +👹 ogre (creature, face, fairy tale, fantasy, monster) +👺 goblin (creature, face, fairy tale, fantasy, monster) +👻 ghost (creature, face, fairy tale, fantasy, monster) +👽 alien (creature, extraterrestrial, face, fantasy, ufo) +👾 alien monster (alien, creature, extraterrestrial, face, monster, ufo) +🤖 robot (face, monster) +😺 grinning cat (cat, face, grinning, mouth, open, smile) +😸 grinning cat with smiling eyes (cat, eye, face, grin, smile) +😹 cat with tears of joy (cat, face, joy, tear) +😻 smiling cat with heart-eyes (cat, eye, face, heart, love, smile) +😼 cat with wry smile (cat, face, ironic, smile, wry) +😽 kissing cat (cat, eye, face, kiss) +🙀 weary cat (cat, face, oh, surprised, weary) +😿 crying cat (cat, cry, face, sad, tear) +😾 pouting cat (cat, face, pouting) +🙈 see-no-evil monkey (evil, face, forbidden, monkey, see) +🙉 hear-no-evil monkey (evil, face, forbidden, hear, monkey) +🙊 speak-no-evil monkey (evil, face, forbidden, monkey, speak) +💋 kiss mark (kiss, lips) +💌 love letter (heart, letter, love, mail) +💘 heart with arrow (arrow, cupid) +💝 heart with ribbon (ribbon, valentine) +💖 sparkling heart (excited, sparkle) +💗 growing heart (excited, growing, nervous, pulse) +💓 beating heart (beating, heartbeat, pulsating) +💞 revolving hearts (revolving) +💕 two hearts (love) +💟 heart decoration (heart) +❣️ heart exclamation (exclamation, mark, punctuation) +💔 broken heart (break, broken) +❤️‍🔥 heart on fire +❤️‍🩹 mending heart +❤️ red heart (heart) +🧡 orange heart (orange) +💛 yellow heart (yellow) +💚 green heart (green) +💙 blue heart (blue) +💜 purple heart (purple) +🤎 brown heart (brown, heart) +🖤 black heart (black, evil, wicked) +🤍 white heart (heart, white) +💯 hundred points (100, full, hundred, score) +💢 anger symbol (angry, comic, mad) +💥 collision (boom, comic) +💫 dizzy (comic, star) +💦 sweat droplets (comic, splashing, sweat) +💨 dashing away (comic, dash, running) +🕳️ hole +💣 bomb (comic) +💬 speech balloon (balloon, bubble, comic, dialog, speech) +👁️‍🗨️ eye in speech bubble +🗨️ left speech bubble (balloon, bubble, dialog, speech) +🗯️ right anger bubble (angry, balloon, bubble, mad) +💭 thought balloon (balloon, bubble, comic, thought) +💤 zzz (comic, good night, sleep, ZZZ) +👋 waving hand (hand, wave, waving) +🤚 raised back of hand (backhand, raised) +🖐️ hand with fingers splayed (finger, hand, splayed) +✋ raised hand (hand, high 5, high five) +🖖 vulcan salute (finger, hand, spock, vulcan) +👌 OK hand (hand, OK) +🤌 pinched fingers (fingers, hand gesture, interrogation, pinched, sarcastic) +🤏 pinching hand (small amount) +✌️ victory hand (hand, v, victory) +🤞 crossed fingers (cross, finger, hand, luck) +🤟 love-you gesture (hand, ILY) +🤘 sign of the horns (finger, hand, horns, rock-on) +🤙 call me hand (call, hand, hang loose, Shaka) +👈 backhand index pointing left (backhand, finger, hand, index, point) +👉 backhand index pointing right (backhand, finger, hand, index, point) +👆 backhand index pointing up (backhand, finger, hand, point, up) +🖕 middle finger (finger, hand) +👇 backhand index pointing down (backhand, down, finger, hand, point) +☝️ index pointing up (finger, hand, index, point, up) +👍 thumbs up (+1, hand, thumb, up) +👎 thumbs down (-1, down, hand, thumb) +✊ raised fist (clenched, fist, hand, punch) +👊 oncoming fist (clenched, fist, hand, punch) +🤛 left-facing fist (fist, leftwards) +🤜 right-facing fist (fist, rightwards) +👏 clapping hands (clap, hand) +🙌 raising hands (celebration, gesture, hand, hooray, raised) +👐 open hands (hand, open) +🤲 palms up together (prayer) +🤝 handshake (agreement, hand, meeting, shake) +🙏 folded hands (ask, hand, high 5, high five, please, pray, thanks) +✍️ writing hand (hand, write) +💅 nail polish (care, cosmetics, manicure, nail, polish) +🤳 selfie (camera, phone) +💪 flexed biceps (biceps, comic, flex, muscle) +🦾 mechanical arm (accessibility, prosthetic) +🦿 mechanical leg (accessibility, prosthetic) +🦵 leg (kick, limb) +🦶 foot (kick, stomp) +👂 ear (body) +🦻 ear with hearing aid (accessibility, hard of hearing) +👃 nose (body) +🧠 brain (intelligent) +🫀 anatomical heart (anatomical, cardiology, heart, organ, pulse) +🫁 lungs (breath, exhalation, inhalation, organ, respiration) +🦷 tooth (dentist) +🦴 bone (skeleton) +👀 eyes (eye, face) +👁️ eye (body) +👅 tongue (body) +👄 mouth (lips) +👶 baby (young) +🧒 child (gender-neutral, unspecified gender, young) +👦 boy (young) +👧 girl (Virgo, young, zodiac) +🧑 person (adult, gender-neutral, unspecified gender) +👱 person blond hair (blond, blond-haired person, hair, person: blond hair) +👨 man (adult) +🧔 person beard (beard, person, person: beard) +🧔‍♂️ man beard +🧔‍♀️ woman beard +👨‍🦰 man red hair +👨‍🦱 man curly hair +👨‍🦳 man white hair +👨‍🦲 man bald +👩 woman (adult) +👩‍🦰 woman red hair +🧑‍🦰 person red hair +👩‍🦱 woman curly hair +🧑‍🦱 person curly hair +👩‍🦳 woman white hair +🧑‍🦳 person white hair +👩‍🦲 woman bald +🧑‍🦲 person bald +👱‍♀️ woman blond hair (blond-haired woman, blonde, hair, woman, woman: blond hair) +👱‍♂️ man blond hair (blond, blond-haired man, hair, man, man: blond hair) +🧓 older person (adult, gender-neutral, old, unspecified gender) +👴 old man (adult, man, old) +👵 old woman (adult, old, woman) +🙍 person frowning (frown, gesture) +🙍‍♂️ man frowning (frowning, gesture, man) +🙍‍♀️ woman frowning (frowning, gesture, woman) +🙎 person pouting (gesture, pouting) +🙎‍♂️ man pouting (gesture, man, pouting) +🙎‍♀️ woman pouting (gesture, pouting, woman) +🙅 person gesturing NO (forbidden, gesture, hand, prohibited) +🙅‍♂️ man gesturing NO (forbidden, gesture, hand, man, prohibited) +🙅‍♀️ woman gesturing NO (forbidden, gesture, hand, prohibited, woman) +🙆 person gesturing OK (gesture, hand, OK) +🙆‍♂️ man gesturing OK (gesture, hand, man, OK) +🙆‍♀️ woman gesturing OK (gesture, hand, OK, woman) +💁 person tipping hand (hand, help, information, sassy, tipping) +💁‍♂️ man tipping hand (man, sassy, tipping hand) +💁‍♀️ woman tipping hand (sassy, tipping hand, woman) +🙋 person raising hand (gesture, hand, happy, raised) +🙋‍♂️ man raising hand (gesture, man, raising hand) +🙋‍♀️ woman raising hand (gesture, raising hand, woman) +🧏 deaf person (accessibility, deaf, ear, hear) +🧏‍♂️ deaf man (deaf, man) +🧏‍♀️ deaf woman (deaf, woman) +🙇 person bowing (apology, bow, gesture, sorry) +🙇‍♂️ man bowing (apology, bowing, favor, gesture, man, sorry) +🙇‍♀️ woman bowing (apology, bowing, favor, gesture, sorry, woman) +🤦 person facepalming (disbelief, exasperation, face, palm) +🤦‍♂️ man facepalming (disbelief, exasperation, facepalm, man) +🤦‍♀️ woman facepalming (disbelief, exasperation, facepalm, woman) +🤷 person shrugging (doubt, ignorance, indifference, shrug) +🤷‍♂️ man shrugging (doubt, ignorance, indifference, man, shrug) +🤷‍♀️ woman shrugging (doubt, ignorance, indifference, shrug, woman) +🧑‍⚕️ health worker (doctor, healthcare, nurse, therapist) +👨‍⚕️ man health worker (doctor, healthcare, man, nurse, therapist) +👩‍⚕️ woman health worker (doctor, healthcare, nurse, therapist, woman) +🧑‍🎓 student (graduate) +👨‍🎓 man student (graduate, man, student) +👩‍🎓 woman student (graduate, student, woman) +🧑‍🏫 teacher (instructor, professor) +👨‍🏫 man teacher (instructor, man, professor, teacher) +👩‍🏫 woman teacher (instructor, professor, teacher, woman) +🧑‍⚖️ judge (justice, scales) +👨‍⚖️ man judge (judge, justice, man, scales) +👩‍⚖️ woman judge (judge, justice, scales, woman) +🧑‍🌾 farmer (gardener, rancher) +👨‍🌾 man farmer (farmer, gardener, man, rancher) +👩‍🌾 woman farmer (farmer, gardener, rancher, woman) +🧑‍🍳 cook (chef) +👨‍🍳 man cook (chef, cook, man) +👩‍🍳 woman cook (chef, cook, woman) +🧑‍🔧 mechanic (electrician, plumber, tradesperson) +👨‍🔧 man mechanic (electrician, man, mechanic, plumber, tradesperson) +👩‍🔧 woman mechanic (electrician, mechanic, plumber, tradesperson, woman) +🧑‍🏭 factory worker (assembly, factory, industrial, worker) +👨‍🏭 man factory worker (assembly, factory, industrial, man, worker) +👩‍🏭 woman factory worker (assembly, factory, industrial, woman, worker) +🧑‍💼 office worker (architect, business, manager, white-collar) +👨‍💼 man office worker (architect, business, man, manager, white-collar) +👩‍💼 woman office worker (architect, business, manager, white-collar, woman) +🧑‍🔬 scientist (biologist, chemist, engineer, physicist) +👨‍🔬 man scientist (biologist, chemist, engineer, man, physicist, scientist) +👩‍🔬 woman scientist (biologist, chemist, engineer, physicist, scientist, woman) +🧑‍💻 technologist (coder, developer, inventor, software) +👨‍💻 man technologist (coder, developer, inventor, man, software, technologist) +👩‍💻 woman technologist (coder, developer, inventor, software, technologist, woman) +🧑‍🎤 singer (actor, entertainer, rock, star) +👨‍🎤 man singer (actor, entertainer, man, rock, singer, star) +👩‍🎤 woman singer (actor, entertainer, rock, singer, star, woman) +🧑‍🎨 artist (palette) +👨‍🎨 man artist (artist, man, palette) +👩‍🎨 woman artist (artist, palette, woman) +🧑‍✈️ pilot (plane) +👨‍✈️ man pilot (man, pilot, plane) +👩‍✈️ woman pilot (pilot, plane, woman) +🧑‍🚀 astronaut (rocket) +👨‍🚀 man astronaut (astronaut, man, rocket) +👩‍🚀 woman astronaut (astronaut, rocket, woman) +🧑‍🚒 firefighter (firetruck) +👨‍🚒 man firefighter (firefighter, firetruck, man) +👩‍🚒 woman firefighter (firefighter, firetruck, woman) +👮 police officer (cop, officer, police) +👮‍♂️ man police officer (cop, man, officer, police) +👮‍♀️ woman police officer (cop, officer, police, woman) +🕵️ detective (sleuth, spy) +🕵️‍♂️ man detective +🕵️‍♀️ woman detective +💂 guard +💂‍♂️ man guard (guard, man) +💂‍♀️ woman guard (guard, woman) +🥷 ninja (fighter, hidden, stealth) +👷 construction worker (construction, hat, worker) +👷‍♂️ man construction worker (construction, man, worker) +👷‍♀️ woman construction worker (construction, woman, worker) +🤴 prince +👸 princess (fairy tale, fantasy) +👳 person wearing turban (turban) +👳‍♂️ man wearing turban (man, turban) +👳‍♀️ woman wearing turban (turban, woman) +👲 person with skullcap (cap, gua pi mao, hat, person, skullcap) +🧕 woman with headscarf (headscarf, hijab, mantilla, tichel) +🤵 person in tuxedo (groom, person, tuxedo) +🤵‍♂️ man in tuxedo (man, tuxedo) +🤵‍♀️ woman in tuxedo (tuxedo, woman) +👰 person with veil (bride, person, veil, wedding) +👰‍♂️ man with veil (man, veil) +👰‍♀️ woman with veil (veil, woman) +🤰 pregnant woman (pregnant, woman) +🤱 breast-feeding (baby, breast, nursing) +👩‍🍼 woman feeding baby (baby, feeding, nursing, woman) +👨‍🍼 man feeding baby (baby, feeding, man, nursing) +🧑‍🍼 person feeding baby (baby, feeding, nursing, person) +👼 baby angel (angel, baby, face, fairy tale, fantasy) +🎅 Santa Claus (celebration, Christmas, claus, father, santa) +🤶 Mrs. Claus (celebration, Christmas, claus, mother, Mrs.) +🧑‍🎄 mx claus (Claus, christmas) +🦸 superhero (good, hero, heroine, superpower) +🦸‍♂️ man superhero (good, hero, man, superpower) +🦸‍♀️ woman superhero (good, hero, heroine, superpower, woman) +🦹 supervillain (criminal, evil, superpower, villain) +🦹‍♂️ man supervillain (criminal, evil, man, superpower, villain) +🦹‍♀️ woman supervillain (criminal, evil, superpower, villain, woman) +🧙 mage (sorcerer, sorceress, witch, wizard) +🧙‍♂️ man mage (sorcerer, wizard) +🧙‍♀️ woman mage (sorceress, witch) +🧚 fairy (Oberon, Puck, Titania) +🧚‍♂️ man fairy (Oberon, Puck) +🧚‍♀️ woman fairy (Titania) +🧛 vampire (Dracula, undead) +🧛‍♂️ man vampire (Dracula, undead) +🧛‍♀️ woman vampire (undead) +🧜 merperson (mermaid, merman, merwoman) +🧜‍♂️ merman (Triton) +🧜‍♀️ mermaid (merwoman) +🧝 elf (magical) +🧝‍♂️ man elf (magical) +🧝‍♀️ woman elf (magical) +🧞 genie (djinn) +🧞‍♂️ man genie (djinn) +🧞‍♀️ woman genie (djinn) +🧟 zombie (undead, walking dead) +🧟‍♂️ man zombie (undead, walking dead) +🧟‍♀️ woman zombie (undead, walking dead) +💆 person getting massage (face, massage, salon) +💆‍♂️ man getting massage (face, man, massage) +💆‍♀️ woman getting massage (face, massage, woman) +💇 person getting haircut (barber, beauty, haircut, parlor) +💇‍♂️ man getting haircut (haircut, man) +💇‍♀️ woman getting haircut (haircut, woman) +🚶 person walking (hike, walk, walking) +🚶‍♂️ man walking (hike, man, walk) +🚶‍♀️ woman walking (hike, walk, woman) +🧍 person standing (stand, standing) +🧍‍♂️ man standing (man, standing) +🧍‍♀️ woman standing (standing, woman) +🧎 person kneeling (kneel, kneeling) +🧎‍♂️ man kneeling (kneeling, man) +🧎‍♀️ woman kneeling (kneeling, woman) +🧑‍🦯 person with white cane (accessibility, blind) +👨‍🦯 man with white cane (accessibility, blind, man) +👩‍🦯 woman with white cane (accessibility, blind, woman) +🧑‍🦼 person in motorized wheelchair (accessibility, wheelchair) +👨‍🦼 man in motorized wheelchair (accessibility, man, wheelchair) +👩‍🦼 woman in motorized wheelchair (accessibility, wheelchair, woman) +🧑‍🦽 person in manual wheelchair (accessibility, wheelchair) +👨‍🦽 man in manual wheelchair (accessibility, man, wheelchair) +👩‍🦽 woman in manual wheelchair (accessibility, wheelchair, woman) +🏃 person running (marathon, running) +🏃‍♂️ man running (man, marathon, racing, running) +🏃‍♀️ woman running (marathon, racing, running, woman) +💃 woman dancing (dance, dancing, woman) +🕺 man dancing (dance, dancing, man) +🕴️ person in suit levitating (business, person, suit) +👯 people with bunny ears (bunny ear, dancer, partying) +👯‍♂️ men with bunny ears (bunny ear, dancer, men, partying) +👯‍♀️ women with bunny ears (bunny ear, dancer, partying, women) +🧖 person in steamy room (sauna, steam room) +🧖‍♂️ man in steamy room (sauna, steam room) +🧖‍♀️ woman in steamy room (sauna, steam room) +🧗 person climbing (climber) +🧗‍♂️ man climbing (climber) +🧗‍♀️ woman climbing (climber) +🤺 person fencing (fencer, fencing, sword) +🏇 horse racing (horse, jockey, racehorse, racing) +⛷️ skier (ski, snow) +🏂 snowboarder (ski, snow, snowboard) +🏌️ person golfing (ball, golf) +🏌️‍♂️ man golfing +🏌️‍♀️ woman golfing +🏄 person surfing (surfing) +🏄‍♂️ man surfing (man, surfing) +🏄‍♀️ woman surfing (surfing, woman) +🚣 person rowing boat (boat, rowboat) +🚣‍♂️ man rowing boat (boat, man, rowboat) +🚣‍♀️ woman rowing boat (boat, rowboat, woman) +🏊 person swimming (swim) +🏊‍♂️ man swimming (man, swim) +🏊‍♀️ woman swimming (swim, woman) +⛹️ person bouncing ball (ball) +⛹️‍♂️ man bouncing ball +⛹️‍♀️ woman bouncing ball +🏋️ person lifting weights (lifter, weight) +🏋️‍♂️ man lifting weights +🏋️‍♀️ woman lifting weights +🚴 person biking (bicycle, biking, cyclist) +🚴‍♂️ man biking (bicycle, biking, cyclist, man) +🚴‍♀️ woman biking (bicycle, biking, cyclist, woman) +🚵 person mountain biking (bicycle, bicyclist, bike, cyclist, mountain) +🚵‍♂️ man mountain biking (bicycle, bike, cyclist, man, mountain) +🚵‍♀️ woman mountain biking (bicycle, bike, biking, cyclist, mountain, woman) +🤸 person cartwheeling (cartwheel, gymnastics) +🤸‍♂️ man cartwheeling (cartwheel, gymnastics, man) +🤸‍♀️ woman cartwheeling (cartwheel, gymnastics, woman) +🤼 people wrestling (wrestle, wrestler) +🤼‍♂️ men wrestling (men, wrestle) +🤼‍♀️ women wrestling (women, wrestle) +🤽 person playing water polo (polo, water) +🤽‍♂️ man playing water polo (man, water polo) +🤽‍♀️ woman playing water polo (water polo, woman) +🤾 person playing handball (ball, handball) +🤾‍♂️ man playing handball (handball, man) +🤾‍♀️ woman playing handball (handball, woman) +🤹 person juggling (balance, juggle, multitask, skill) +🤹‍♂️ man juggling (juggling, man, multitask) +🤹‍♀️ woman juggling (juggling, multitask, woman) +🧘 person in lotus position (meditation, yoga) +🧘‍♂️ man in lotus position (meditation, yoga) +🧘‍♀️ woman in lotus position (meditation, yoga) +🛀 person taking bath (bath, bathtub) +🛌 person in bed (good night, hotel, sleep) +🧑‍🤝‍🧑 people holding hands (couple, hand, hold, holding hands, person) +👭 women holding hands (couple, hand, holding hands, women) +👫 woman and man holding hands (couple, hand, hold, holding hands, man, woman) +👬 men holding hands (couple, Gemini, holding hands, man, men, twins, zodiac) +💏 kiss (couple) +👩‍❤️‍💋‍👨 kiss woman, man +👨‍❤️‍💋‍👨 kiss man, man +👩‍❤️‍💋‍👩 kiss woman, woman +💑 couple with heart (couple, love) +👩‍❤️‍👨 couple with heart woman, man +👨‍❤️‍👨 couple with heart man, man +👩‍❤️‍👩 couple with heart woman, woman +👪 family +👨‍👩‍👦 family man, woman, boy +👨‍👩‍👧 family man, woman, girl +👨‍👩‍👧‍👦 family man, woman, girl, boy +👨‍👩‍👦‍👦 family man, woman, boy, boy +👨‍👩‍👧‍👧 family man, woman, girl, girl +👨‍👨‍👦 family man, man, boy +👨‍👨‍👧 family man, man, girl +👨‍👨‍👧‍👦 family man, man, girl, boy +👨‍👨‍👦‍👦 family man, man, boy, boy +👨‍👨‍👧‍👧 family man, man, girl, girl +👩‍👩‍👦 family woman, woman, boy +👩‍👩‍👧 family woman, woman, girl +👩‍👩‍👧‍👦 family woman, woman, girl, boy +👩‍👩‍👦‍👦 family woman, woman, boy, boy +👩‍👩‍👧‍👧 family woman, woman, girl, girl +👨‍👦 family man, boy +👨‍👦‍👦 family man, boy, boy +👨‍👧 family man, girl +👨‍👧‍👦 family man, girl, boy +👨‍👧‍👧 family man, girl, girl +👩‍👦 family woman, boy +👩‍👦‍👦 family woman, boy, boy +👩‍👧 family woman, girl +👩‍👧‍👦 family woman, girl, boy +👩‍👧‍👧 family woman, girl, girl +🗣️ speaking head (face, head, silhouette, speak, speaking) +👤 bust in silhouette (bust, silhouette) +👥 busts in silhouette (bust, silhouette) +🫂 people hugging (goodbye, hello, hug, thanks) +👣 footprints (clothing, footprint, print) +🐵 monkey face (face, monkey) +🐒 monkey +🦍 gorilla +🦧 orangutan (ape) +🐶 dog face (dog, face, pet) +🐕 dog (pet) +🦮 guide dog (accessibility, blind, guide) +🐕‍🦺 service dog (accessibility, assistance, dog, service) +🐩 poodle (dog) +🐺 wolf (face) +🦊 fox (face) +🦝 raccoon (curious, sly) +🐱 cat face (cat, face, pet) +🐈 cat (pet) +🐈‍⬛ black cat (black, cat, unlucky) +🦁 lion (face, Leo, zodiac) +🐯 tiger face (face, tiger) +🐅 tiger +🐆 leopard +🐴 horse face (face, horse) +🐎 horse (equestrian, racehorse, racing) +🦄 unicorn (face) +🦓 zebra (stripe) +🦌 deer +🦬 bison (buffalo, herd, wisent) +🐮 cow face (cow, face) +🐂 ox (bull, Taurus, zodiac) +🐃 water buffalo (buffalo, water) +🐄 cow +🐷 pig face (face, pig) +🐖 pig (sow) +🐗 boar (pig) +🐽 pig nose (face, nose, pig) +🐏 ram (Aries, male, sheep, zodiac) +🐑 ewe (female, sheep) +🐐 goat (Capricorn, zodiac) +🐪 camel (dromedary, hump) +🐫 two-hump camel (bactrian, camel, hump) +🦙 llama (alpaca, guanaco, vicuña, wool) +🦒 giraffe (spots) +🐘 elephant +🦣 mammoth (extinction, large, tusk, woolly) +🦏 rhinoceros +🦛 hippopotamus (hippo) +🐭 mouse face (face, mouse) +🐁 mouse +🐀 rat +🐹 hamster (face, pet) +🐰 rabbit face (bunny, face, pet, rabbit) +🐇 rabbit (bunny, pet) +🐿️ chipmunk (squirrel) +🦫 beaver (dam) +🦔 hedgehog (spiny) +🦇 bat (vampire) +🐻 bear (face) +🐻‍❄️ polar bear (arctic, bear, white) +🐨 koala (face, marsupial) +🐼 panda (face) +🦥 sloth (lazy, slow) +🦦 otter (fishing, playful) +🦨 skunk (stink) +🦘 kangaroo (Australia, joey, jump, marsupial) +🦡 badger (honey badger, pester) +🐾 paw prints (feet, paw, print) +🦃 turkey (bird) +🐔 chicken (bird) +🐓 rooster (bird) +🐣 hatching chick (baby, bird, chick, hatching) +🐤 baby chick (baby, bird, chick) +🐥 front-facing baby chick (baby, bird, chick) +🐦 bird +🐧 penguin (bird) +🕊️ dove (bird, fly, peace) +🦅 eagle (bird) +🦆 duck (bird) +🦢 swan (bird, cygnet, ugly duckling) +🦉 owl (bird, wise) +🦤 dodo (extinction, large, Mauritius) +🪶 feather (bird, flight, light, plumage) +🦩 flamingo (flamboyant, tropical) +🦚 peacock (bird, ostentatious, peahen, proud) +🦜 parrot (bird, pirate, talk) +🐸 frog (face) +🐊 crocodile +🐢 turtle (terrapin, tortoise) +🦎 lizard (reptile) +🐍 snake (bearer, Ophiuchus, serpent, zodiac) +🐲 dragon face (dragon, face, fairy tale) +🐉 dragon (fairy tale) +🦕 sauropod (brachiosaurus, brontosaurus, diplodocus) +🦖 T-Rex (Tyrannosaurus Rex) +🐳 spouting whale (face, spouting, whale) +🐋 whale +🐬 dolphin (flipper) +🦭 seal (sea lion) +🐟 fish (Pisces, zodiac) +🐠 tropical fish (fish, tropical) +🐡 blowfish (fish) +🦈 shark (fish) +🐙 octopus +🐚 spiral shell (shell, spiral) +🐌 snail +🦋 butterfly (insect, pretty) +🐛 bug (insect) +🐜 ant (insect) +🐝 honeybee (bee, insect) +🪲 beetle (bug, insect) +🐞 lady beetle (beetle, insect, ladybird, ladybug) +🦗 cricket (grasshopper) +🪳 cockroach (insect, pest, roach) +🕷️ spider (insect) +🕸️ spider web (spider, web) +🦂 scorpion (scorpio, Scorpio, zodiac) +🦟 mosquito (disease, fever, malaria, pest, virus) +🪰 fly (disease, maggot, pest, rotting) +🪱 worm (annelid, earthworm, parasite) +🦠 microbe (amoeba, bacteria, virus) +💐 bouquet (flower) +🌸 cherry blossom (blossom, cherry, flower) +💮 white flower (flower) +🏵️ rosette (plant) +🌹 rose (flower) +🥀 wilted flower (flower, wilted) +🌺 hibiscus (flower) +🌻 sunflower (flower, sun) +🌼 blossom (flower) +🌷 tulip (flower) +🌱 seedling (young) +🪴 potted plant (boring, grow, house, nurturing, plant, useless) +🌲 evergreen tree (tree) +🌳 deciduous tree (deciduous, shedding, tree) +🌴 palm tree (palm, tree) +🌵 cactus (plant) +🌾 sheaf of rice (ear, grain, rice) +🌿 herb (leaf) +☘️ shamrock (plant) +🍀 four leaf clover (4, clover, four, four-leaf clover, leaf) +🍁 maple leaf (falling, leaf, maple) +🍂 fallen leaf (falling, leaf) +🍃 leaf fluttering in wind (blow, flutter, leaf, wind) +🍇 grapes (fruit, grape) +🍈 melon (fruit) +🍉 watermelon (fruit) +🍊 tangerine (fruit, orange) +🍋 lemon (citrus, fruit) +🍌 banana (fruit) +🍍 pineapple (fruit) +🥭 mango (fruit, tropical) +🍎 red apple (apple, fruit, red) +🍏 green apple (apple, fruit, green) +🍐 pear (fruit) +🍑 peach (fruit) +🍒 cherries (berries, cherry, fruit, red) +🍓 strawberry (berry, fruit) +🫐 blueberries (berry, bilberry, blue, blueberry) +🥝 kiwi fruit (food, fruit, kiwi) +🍅 tomato (fruit, vegetable) +🫒 olive (food) +🥥 coconut (palm, piña colada) +🥑 avocado (food, fruit) +🍆 eggplant (aubergine, vegetable) +🥔 potato (food, vegetable) +🥕 carrot (food, vegetable) +🌽 ear of corn (corn, ear, maize, maze) +🌶️ hot pepper (hot, pepper) +🫑 bell pepper (capsicum, pepper, vegetable) +🥒 cucumber (food, pickle, vegetable) +🥬 leafy green (bok choy, cabbage, kale, lettuce) +🥦 broccoli (wild cabbage) +🧄 garlic (flavoring) +🧅 onion (flavoring) +🍄 mushroom (toadstool) +🥜 peanuts (food, nut, peanut, vegetable) +🌰 chestnut (plant) +🍞 bread (loaf) +🥐 croissant (bread, breakfast, food, french, roll) +🥖 baguette bread (baguette, bread, food, french) +🫓 flatbread (arepa, lavash, naan, pita) +🥨 pretzel (twisted) +🥯 bagel (bakery, breakfast, schmear) +🥞 pancakes (breakfast, crêpe, food, hotcake, pancake) +🧇 waffle (breakfast, indecisive, iron) +🧀 cheese wedge (cheese) +🍖 meat on bone (bone, meat) +🍗 poultry leg (bone, chicken, drumstick, leg, poultry) +🥩 cut of meat (chop, lambchop, porkchop, steak) +🥓 bacon (breakfast, food, meat) +🍔 hamburger (burger) +🍟 french fries (french, fries) +🍕 pizza (cheese, slice) +🌭 hot dog (frankfurter, hotdog, sausage) +🥪 sandwich (bread) +🌮 taco (mexican) +🌯 burrito (mexican, wrap) +🫔 tamale (mexican, wrapped) +🥙 stuffed flatbread (falafel, flatbread, food, gyro, kebab, stuffed) +🧆 falafel (chickpea, meatball) +🥚 egg (breakfast, food) +🍳 cooking (breakfast, egg, frying, pan) +🥘 shallow pan of food (casserole, food, paella, pan, shallow) +🍲 pot of food (pot, stew) +🫕 fondue (cheese, chocolate, melted, pot, Swiss) +🥣 bowl with spoon (breakfast, cereal, congee) +🥗 green salad (food, green, salad) +🍿 popcorn +🧈 butter (dairy) +🧂 salt (condiment, shaker) +🥫 canned food (can) +🍱 bento box (bento, box) +🍘 rice cracker (cracker, rice) +🍙 rice ball (ball, Japanese, rice) +🍚 cooked rice (cooked, rice) +🍛 curry rice (curry, rice) +🍜 steaming bowl (bowl, noodle, ramen, steaming) +🍝 spaghetti (pasta) +🍠 roasted sweet potato (potato, roasted, sweet) +🍢 oden (kebab, seafood, skewer, stick) +🍣 sushi +🍤 fried shrimp (fried, prawn, shrimp, tempura) +🍥 fish cake with swirl (cake, fish, pastry, swirl) +🥮 moon cake (autumn, festival, yuèbǐng) +🍡 dango (dessert, Japanese, skewer, stick, sweet) +🥟 dumpling (empanada, gyōza, jiaozi, pierogi, potsticker) +🥠 fortune cookie (prophecy) +🥡 takeout box (oyster pail) +🦀 crab (Cancer, zodiac) +🦞 lobster (bisque, claws, seafood) +🦐 shrimp (food, shellfish, small) +🦑 squid (food, molusc) +🦪 oyster (diving, pearl) +🍦 soft ice cream (cream, dessert, ice, icecream, soft, sweet) +🍧 shaved ice (dessert, ice, shaved, sweet) +🍨 ice cream (cream, dessert, ice, sweet) +🍩 doughnut (breakfast, dessert, donut, sweet) +🍪 cookie (dessert, sweet) +🎂 birthday cake (birthday, cake, celebration, dessert, pastry, sweet) +🍰 shortcake (cake, dessert, pastry, slice, sweet) +🧁 cupcake (bakery, sweet) +🥧 pie (filling, pastry) +🍫 chocolate bar (bar, chocolate, dessert, sweet) +🍬 candy (dessert, sweet) +🍭 lollipop (candy, dessert, sweet) +🍮 custard (dessert, pudding, sweet) +🍯 honey pot (honey, honeypot, pot, sweet) +🍼 baby bottle (baby, bottle, drink, milk) +🥛 glass of milk (drink, glass, milk) +☕ hot beverage (beverage, coffee, drink, hot, steaming, tea) +🫖 teapot (drink, pot, tea) +🍵 teacup without handle (beverage, cup, drink, tea, teacup) +🍶 sake (bar, beverage, bottle, cup, drink) +🍾 bottle with popping cork (bar, bottle, cork, drink, popping) +🍷 wine glass (bar, beverage, drink, glass, wine) +🍸 cocktail glass (bar, cocktail, drink, glass) +🍹 tropical drink (bar, drink, tropical) +🍺 beer mug (bar, beer, drink, mug) +🍻 clinking beer mugs (bar, beer, clink, drink, mug) +🥂 clinking glasses (celebrate, clink, drink, glass) +🥃 tumbler glass (glass, liquor, shot, tumbler, whisky) +🥤 cup with straw (juice, soda) +🧋 bubble tea (bubble, milk, pearl, tea) +🧃 beverage box (beverage, box, juice, straw, sweet) +🧉 mate (drink) +🧊 ice (cold, ice cube, iceberg) +🥢 chopsticks (hashi) +🍽️ fork and knife with plate (cooking, fork, knife, plate) +🍴 fork and knife (cooking, cutlery, fork, knife) +🥄 spoon (tableware) +🔪 kitchen knife (cooking, hocho, knife, tool, weapon) +🏺 amphora (Aquarius, cooking, drink, jug, zodiac) +🌍 globe showing Europe-Africa (Africa, earth, Europe, globe, world) +🌎 globe showing Americas (Americas, earth, globe, world) +🌏 globe showing Asia-Australia (Asia, Australia, earth, globe, world) +🌐 globe with meridians (earth, globe, meridians, world) +🗺️ world map (map, world) +🗾 map of Japan (Japan, map) +🧭 compass (magnetic, navigation, orienteering) +🏔️ snow-capped mountain (cold, mountain, snow) +⛰️ mountain +🌋 volcano (eruption, mountain) +🗻 mount fuji (fuji, mountain) +🏕️ camping +🏖️ beach with umbrella (beach, umbrella) +🏜️ desert +🏝️ desert island (desert, island) +🏞️ national park (park) +🏟️ stadium +🏛️ classical building (classical) +🏗️ building construction (construction) +🧱 brick (bricks, clay, mortar, wall) +🪨 rock (boulder, heavy, solid, stone) +🪵 wood (log, lumber, timber) +🛖 hut (house, roundhouse, yurt) +🏘️ houses +🏚️ derelict house (derelict, house) +🏠 house (home) +🏡 house with garden (garden, home, house) +🏢 office building (building) +🏣 Japanese post office (Japanese, post) +🏤 post office (European, post) +🏥 hospital (doctor, medicine) +🏦 bank (building) +🏨 hotel (building) +🏩 love hotel (hotel, love) +🏪 convenience store (convenience, store) +🏫 school (building) +🏬 department store (department, store) +🏭 factory (building) +🏯 Japanese castle (castle, Japanese) +🏰 castle (European) +💒 wedding (chapel, romance) +🗼 Tokyo tower (Tokyo, tower) +🗽 Statue of Liberty (liberty, statue) +⛪ church (Christian, cross, religion) +🕌 mosque (islam, Muslim, religion) +🛕 hindu temple (hindu, temple) +🕍 synagogue (Jew, Jewish, religion, temple) +⛩️ shinto shrine (religion, shinto, shrine) +🕋 kaaba (islam, Muslim, religion) +⛲ fountain +⛺ tent (camping) +🌁 foggy (fog) +🌃 night with stars (night, star) +🏙️ cityscape (city) +🌄 sunrise over mountains (morning, mountain, sun, sunrise) +🌅 sunrise (morning, sun) +🌆 cityscape at dusk (city, dusk, evening, landscape, sunset) +🌇 sunset (dusk, sun) +🌉 bridge at night (bridge, night) +♨️ hot springs (hot, hotsprings, springs, steaming) +🎠 carousel horse (carousel, horse) +🎡 ferris wheel (amusement park, ferris, wheel) +🎢 roller coaster (amusement park, coaster, roller) +💈 barber pole (barber, haircut, pole) +🎪 circus tent (circus, tent) +🚂 locomotive (engine, railway, steam, train) +🚃 railway car (car, electric, railway, train, tram, trolleybus) +🚄 high-speed train (railway, shinkansen, speed, train) +🚅 bullet train (bullet, railway, shinkansen, speed, train) +🚆 train (railway) +🚇 metro (subway) +🚈 light rail (railway) +🚉 station (railway, train) +🚊 tram (trolleybus) +🚝 monorail (vehicle) +🚞 mountain railway (car, mountain, railway) +🚋 tram car (car, tram, trolleybus) +🚌 bus (vehicle) +🚍 oncoming bus (bus, oncoming) +🚎 trolleybus (bus, tram, trolley) +🚐 minibus (bus) +🚑 ambulance (vehicle) +🚒 fire engine (engine, fire, truck) +🚓 police car (car, patrol, police) +🚔 oncoming police car (car, oncoming, police) +🚕 taxi (vehicle) +🚖 oncoming taxi (oncoming, taxi) +🚗 automobile (car) +🚘 oncoming automobile (automobile, car, oncoming) +🚙 sport utility vehicle (recreational, sport utility) +🛻 pickup truck (pick-up, pickup, truck) +🚚 delivery truck (delivery, truck) +🚛 articulated lorry (lorry, semi, truck) +🚜 tractor (vehicle) +🏎️ racing car (car, racing) +🏍️ motorcycle (racing) +🛵 motor scooter (motor, scooter) +🦽 manual wheelchair (accessibility) +🦼 motorized wheelchair (accessibility) +🛺 auto rickshaw (tuk tuk) +🚲 bicycle (bike) +🛴 kick scooter (kick, scooter) +🛹 skateboard (board) +🛼 roller skate (roller, skate) +🚏 bus stop (bus, stop) +🛣️ motorway (highway, road) +🛤️ railway track (railway, train) +🛢️ oil drum (drum, oil) +⛽ fuel pump (diesel, fuel, fuelpump, gas, pump, station) +🚨 police car light (beacon, car, light, police, revolving) +🚥 horizontal traffic light (light, signal, traffic) +🚦 vertical traffic light (light, signal, traffic) +🛑 stop sign (octagonal, sign, stop) +🚧 construction (barrier) +⚓ anchor (ship, tool) +⛵ sailboat (boat, resort, sea, yacht) +🛶 canoe (boat) +🚤 speedboat (boat) +🛳️ passenger ship (passenger, ship) +⛴️ ferry (boat, passenger) +🛥️ motor boat (boat, motorboat) +🚢 ship (boat, passenger) +✈️ airplane (aeroplane) +🛩️ small airplane (aeroplane, airplane) +🛫 airplane departure (aeroplane, airplane, check-in, departure, departures) +🛬 airplane arrival (aeroplane, airplane, arrivals, arriving, landing) +🪂 parachute (hang-glide, parasail, skydive) +💺 seat (chair) +🚁 helicopter (vehicle) +🚟 suspension railway (railway, suspension) +🚠 mountain cableway (cable, gondola, mountain) +🚡 aerial tramway (aerial, cable, car, gondola, tramway) +🛰️ satellite (space) +🚀 rocket (space) +🛸 flying saucer (UFO) +🛎️ bellhop bell (bell, bellhop, hotel) +🧳 luggage (packing, travel) +⌛ hourglass done (sand, timer) +⏳ hourglass not done (hourglass, sand, timer) +⌚ watch (clock) +⏰ alarm clock (alarm, clock) +⏱️ stopwatch (clock) +⏲️ timer clock (clock, timer) +🕰️ mantelpiece clock (clock) +🕛 twelve o’clock (00, 12, 12:00, clock, o’clock, twelve) +🕧 twelve-thirty (12, 12:30, clock, thirty, twelve) +🕐 one o’clock (00, 1, 1:00, clock, o’clock, one) +🕜 one-thirty (1, 1:30, clock, one, thirty) +🕑 two o’clock (00, 2, 2:00, clock, o’clock, two) +🕝 two-thirty (2, 2:30, clock, thirty, two) +🕒 three o’clock (00, 3, 3:00, clock, o’clock, three) +🕞 three-thirty (3, 3:30, clock, thirty, three) +🕓 four o’clock (00, 4, 4:00, clock, four, o’clock) +🕟 four-thirty (4, 4:30, clock, four, thirty) +🕔 five o’clock (00, 5, 5:00, clock, five, o’clock) +🕠 five-thirty (5, 5:30, clock, five, thirty) +🕕 six o’clock (00, 6, 6:00, clock, o’clock, six) +🕡 six-thirty (6, 6:30, clock, six, thirty) +🕖 seven o’clock (00, 7, 7:00, clock, o’clock, seven) +🕢 seven-thirty (7, 7:30, clock, seven, thirty) +🕗 eight o’clock (00, 8, 8:00, clock, eight, o’clock) +🕣 eight-thirty (8, 8:30, clock, eight, thirty) +🕘 nine o’clock (00, 9, 9:00, clock, nine, o’clock) +🕤 nine-thirty (9, 9:30, clock, nine, thirty) +🕙 ten o’clock (00, 10, 10:00, clock, o’clock, ten) +🕥 ten-thirty (10, 10:30, clock, ten, thirty) +🕚 eleven o’clock (00, 11, 11:00, clock, eleven, o’clock) +🕦 eleven-thirty (11, 11:30, clock, eleven, thirty) +🌑 new moon (dark, moon) +🌒 waxing crescent moon (crescent, moon, waxing) +🌓 first quarter moon (moon, quarter) +🌔 waxing gibbous moon (gibbous, moon, waxing) +🌕 full moon (full, moon) +🌖 waning gibbous moon (gibbous, moon, waning) +🌗 last quarter moon (moon, quarter) +🌘 waning crescent moon (crescent, moon, waning) +🌙 crescent moon (crescent, moon) +🌚 new moon face (face, moon) +🌛 first quarter moon face (face, moon, quarter) +🌜 last quarter moon face (face, moon, quarter) +🌡️ thermometer (weather) +☀️ sun (bright, rays, sunny) +🌝 full moon face (bright, face, full, moon) +🌞 sun with face (bright, face, sun) +🪐 ringed planet (saturn, saturnine) +⭐ star +🌟 glowing star (glittery, glow, shining, sparkle, star) +🌠 shooting star (falling, shooting, star) +🌌 milky way (space) +☁️ cloud (weather) +⛅ sun behind cloud (cloud, sun) +⛈️ cloud with lightning and rain (cloud, rain, thunder) +🌤️ sun behind small cloud (cloud, sun) +🌥️ sun behind large cloud (cloud, sun) +🌦️ sun behind rain cloud (cloud, rain, sun) +🌧️ cloud with rain (cloud, rain) +🌨️ cloud with snow (cloud, cold, snow) +🌩️ cloud with lightning (cloud, lightning) +🌪️ tornado (cloud, whirlwind) +🌫️ fog (cloud) +🌬️ wind face (blow, cloud, face, wind) +🌀 cyclone (dizzy, hurricane, twister, typhoon) +🌈 rainbow (rain) +🌂 closed umbrella (clothing, rain, umbrella) +☂️ umbrella (clothing, rain) +☔ umbrella with rain drops (clothing, drop, rain, umbrella) +⛱️ umbrella on ground (rain, sun, umbrella) +⚡ high voltage (danger, electric, lightning, voltage, zap) +❄️ snowflake (cold, snow) +☃️ snowman (cold, snow) +⛄ snowman without snow (cold, snow, snowman) +☄️ comet (space) +🔥 fire (flame, tool) +💧 droplet (cold, comic, drop, sweat) +🌊 water wave (ocean, water, wave) +🎃 jack-o-lantern (celebration, halloween, jack, lantern) +🎄 Christmas tree (celebration, Christmas, tree) +🎆 fireworks (celebration) +🎇 sparkler (celebration, fireworks, sparkle) +🧨 firecracker (dynamite, explosive, fireworks) +✨ sparkles (*, sparkle, star) +🎈 balloon (celebration) +🎉 party popper (celebration, party, popper, tada) +🎊 confetti ball (ball, celebration, confetti) +🎋 tanabata tree (banner, celebration, Japanese, tree) +🎍 pine decoration (bamboo, celebration, Japanese, pine) +🎎 Japanese dolls (celebration, doll, festival, Japanese) +🎏 carp streamer (carp, celebration, streamer) +🎐 wind chime (bell, celebration, chime, wind) +🎑 moon viewing ceremony (celebration, ceremony, moon) +🧧 red envelope (gift, good luck, hóngbāo, lai see, money) +🎀 ribbon (celebration) +🎁 wrapped gift (box, celebration, gift, present, wrapped) +🎗️ reminder ribbon (celebration, reminder, ribbon) +🎟️ admission tickets (admission, ticket) +🎫 ticket (admission) +🎖️ military medal (celebration, medal, military) +🏆 trophy (prize) +🏅 sports medal (medal) +🥇 1st place medal (first, gold, medal) +🥈 2nd place medal (medal, second, silver) +🥉 3rd place medal (bronze, medal, third) +⚽ soccer ball (ball, football, soccer) +⚾ baseball (ball) +🥎 softball (ball, glove, underarm) +🏀 basketball (ball, hoop) +🏐 volleyball (ball, game) +🏈 american football (american, ball, football) +🏉 rugby football (ball, football, rugby) +🎾 tennis (ball, racquet) +🥏 flying disc (ultimate) +🎳 bowling (ball, game) +🏏 cricket game (ball, bat, game) +🏑 field hockey (ball, field, game, hockey, stick) +🏒 ice hockey (game, hockey, ice, puck, stick) +🥍 lacrosse (ball, goal, stick) +🏓 ping pong (ball, bat, game, paddle, table tennis) +🏸 badminton (birdie, game, racquet, shuttlecock) +🥊 boxing glove (boxing, glove) +🥋 martial arts uniform (judo, karate, martial arts, taekwondo, uniform) +🥅 goal net (goal, net) +⛳ flag in hole (golf, hole) +⛸️ ice skate (ice, skate) +🎣 fishing pole (fish, pole) +🤿 diving mask (diving, scuba, snorkeling) +🎽 running shirt (athletics, running, sash, shirt) +🎿 skis (ski, snow) +🛷 sled (sledge, sleigh) +🥌 curling stone (game, rock) +🎯 bullseye (dart, direct hit, game, hit, target) +🪀 yo-yo (fluctuate, toy) +🪁 kite (fly, soar) +🎱 pool 8 ball (8, ball, billiard, eight, game) +🔮 crystal ball (ball, crystal, fairy tale, fantasy, fortune, tool) +🪄 magic wand (magic, witch, wizard) +🧿 nazar amulet (bead, charm, evil-eye, nazar, talisman) +🎮 video game (controller, game) +🕹️ joystick (game, video game) +🎰 slot machine (game, slot) +🎲 game die (dice, die, game) +🧩 puzzle piece (clue, interlocking, jigsaw, piece, puzzle) +🧸 teddy bear (plaything, plush, stuffed, toy) +🪅 piñata (celebration, party) +🪆 nesting dolls (doll, nesting, russia) +♠️ spade suit (card, game) +♥️ heart suit (card, game) +♦️ diamond suit (card, game) +♣️ club suit (card, game) +♟️ chess pawn (chess, dupe, expendable) +🃏 joker (card, game, wildcard) +🀄 mahjong red dragon (game, mahjong, red) +🎴 flower playing cards (card, flower, game, Japanese, playing) +🎭 performing arts (art, mask, performing, theater, theatre) +🖼️ framed picture (art, frame, museum, painting, picture) +🎨 artist palette (art, museum, painting, palette) +🧵 thread (needle, sewing, spool, string) +🪡 sewing needle (embroidery, needle, sewing, stitches, sutures, tailoring) +🧶 yarn (ball, crochet, knit) +🪢 knot (rope, tangled, tie, twine, twist) +👓 glasses (clothing, eye, eyeglasses, eyewear) +🕶️ sunglasses (dark, eye, eyewear, glasses) +🥽 goggles (eye protection, swimming, welding) +🥼 lab coat (doctor, experiment, scientist) +🦺 safety vest (emergency, safety, vest) +👔 necktie (clothing, tie) +👕 t-shirt (clothing, shirt, tshirt) +👖 jeans (clothing, pants, trousers) +🧣 scarf (neck) +🧤 gloves (hand) +🧥 coat (jacket) +🧦 socks (stocking) +👗 dress (clothing) +👘 kimono (clothing) +🥻 sari (clothing, dress) +🩱 one-piece swimsuit (bathing suit) +🩲 briefs (bathing suit, one-piece, swimsuit, underwear) +🩳 shorts (bathing suit, pants, underwear) +👙 bikini (clothing, swim) +👚 woman’s clothes (clothing, woman) +👛 purse (clothing, coin) +👜 handbag (bag, clothing, purse) +👝 clutch bag (bag, clothing, pouch) +🛍️ shopping bags (bag, hotel, shopping) +🎒 backpack (bag, rucksack, satchel, school) +🩴 thong sandal (beach sandals, sandals, thong sandals, thongs, zōri) +👞 man’s shoe (clothing, man, shoe) +👟 running shoe (athletic, clothing, shoe, sneaker) +🥾 hiking boot (backpacking, boot, camping, hiking) +🥿 flat shoe (ballet flat, slip-on, slipper) +👠 high-heeled shoe (clothing, heel, shoe, woman) +👡 woman’s sandal (clothing, sandal, shoe, woman) +🩰 ballet shoes (ballet, dance) +👢 woman’s boot (boot, clothing, shoe, woman) +👑 crown (clothing, king, queen) +👒 woman’s hat (clothing, hat, woman) +🎩 top hat (clothing, hat, top, tophat) +🎓 graduation cap (cap, celebration, clothing, graduation, hat) +🧢 billed cap (baseball cap) +🪖 military helmet (army, helmet, military, soldier, warrior) +⛑️ rescue worker’s helmet (aid, cross, face, hat, helmet) +📿 prayer beads (beads, clothing, necklace, prayer, religion) +💄 lipstick (cosmetics, makeup) +💍 ring (diamond) +💎 gem stone (diamond, gem, jewel) +🔇 muted speaker (mute, quiet, silent, speaker) +🔈 speaker low volume (soft) +🔉 speaker medium volume (medium) +🔊 speaker high volume (loud) +📢 loudspeaker (loud, public address) +📣 megaphone (cheering) +📯 postal horn (horn, post, postal) +🔔 bell +🔕 bell with slash (bell, forbidden, mute, quiet, silent) +🎼 musical score (music, score) +🎵 musical note (music, note) +🎶 musical notes (music, note, notes) +🎙️ studio microphone (mic, microphone, music, studio) +🎚️ level slider (level, music, slider) +🎛️ control knobs (control, knobs, music) +🎤 microphone (karaoke, mic) +🎧 headphone (earbud) +📻 radio (video) +🎷 saxophone (instrument, music, sax) +🪗 accordion (concertina, squeeze box) +🎸 guitar (instrument, music) +🎹 musical keyboard (instrument, keyboard, music, piano) +🎺 trumpet (instrument, music) +🎻 violin (instrument, music) +🪕 banjo (music, stringed) +🥁 drum (drumsticks, music) +🪘 long drum (beat, conga, drum, rhythm) +📱 mobile phone (cell, mobile, phone, telephone) +📲 mobile phone with arrow (arrow, cell, mobile, phone, receive) +☎️ telephone (phone) +📞 telephone receiver (phone, receiver, telephone) +📟 pager +📠 fax machine (fax) +🔋 battery +🔌 electric plug (electric, electricity, plug) +💻 laptop (computer, pc, personal) +🖥️ desktop computer (computer, desktop) +🖨️ printer (computer) +⌨️ keyboard (computer) +🖱️ computer mouse (computer) +🖲️ trackball (computer) +💽 computer disk (computer, disk, minidisk, optical) +💾 floppy disk (computer, disk, floppy) +💿 optical disk (CD, computer, disk, optical) +📀 dvd (Blu-ray, computer, disk, DVD, optical) +🧮 abacus (calculation) +🎥 movie camera (camera, cinema, movie) +🎞️ film frames (cinema, film, frames, movie) +📽️ film projector (cinema, film, movie, projector, video) +🎬 clapper board (clapper, movie) +📺 television (tv, video) +📷 camera (video) +📸 camera with flash (camera, flash, video) +📹 video camera (camera, video) +📼 videocassette (tape, vhs, video) +🔍 magnifying glass tilted left (glass, magnifying, search, tool) +🔎 magnifying glass tilted right (glass, magnifying, search, tool) +🕯️ candle (light) +💡 light bulb (bulb, comic, electric, idea, light) +🔦 flashlight (electric, light, tool, torch) +🏮 red paper lantern (bar, lantern, light, red) +🪔 diya lamp (diya, lamp, oil) +📔 notebook with decorative cover (book, cover, decorated, notebook) +📕 closed book (book, closed) +📖 open book (book, open) +📗 green book (book, green) +📘 blue book (blue, book) +📙 orange book (book, orange) +📚 books (book) +📓 notebook +📒 ledger (notebook) +📃 page with curl (curl, document, page) +📜 scroll (paper) +📄 page facing up (document, page) +📰 newspaper (news, paper) +🗞️ rolled-up newspaper (news, newspaper, paper, rolled) +📑 bookmark tabs (bookmark, mark, marker, tabs) +🔖 bookmark (mark) +🏷️ label +💰 money bag (bag, dollar, money, moneybag) +🪙 coin (gold, metal, money, silver, treasure) +💴 yen banknote (banknote, bill, currency, money, note, yen) +💵 dollar banknote (banknote, bill, currency, dollar, money, note) +💶 euro banknote (banknote, bill, currency, euro, money, note) +💷 pound banknote (banknote, bill, currency, money, note, pound) +💸 money with wings (banknote, bill, fly, money, wings) +💳 credit card (card, credit, money) +🧾 receipt (accounting, bookkeeping, evidence, proof) +💹 chart increasing with yen (chart, graph, growth, money, yen) +✉️ envelope (email, letter) +📧 e-mail (email, letter, mail) +📨 incoming envelope (e-mail, email, envelope, incoming, letter, receive) +📩 envelope with arrow (arrow, e-mail, email, envelope, outgoing) +📤 outbox tray (box, letter, mail, outbox, sent, tray) +📥 inbox tray (box, inbox, letter, mail, receive, tray) +📦 package (box, parcel) +📫 closed mailbox with raised flag (closed, mail, mailbox, postbox) +📪 closed mailbox with lowered flag (closed, lowered, mail, mailbox, postbox) +📬 open mailbox with raised flag (mail, mailbox, open, postbox) +📭 open mailbox with lowered flag (lowered, mail, mailbox, open, postbox) +📮 postbox (mail, mailbox) +🗳️ ballot box with ballot (ballot, box) +✏️ pencil +✒️ black nib (nib, pen) +🖋️ fountain pen (fountain, pen) +🖊️ pen (ballpoint) +🖌️ paintbrush (painting) +🖍️ crayon +📝 memo (pencil) +💼 briefcase +📁 file folder (file, folder) +📂 open file folder (file, folder, open) +🗂️ card index dividers (card, dividers, index) +📅 calendar (date) +📆 tear-off calendar (calendar) +🗒️ spiral notepad (note, pad, spiral) +🗓️ spiral calendar (calendar, pad, spiral) +📇 card index (card, index, rolodex) +📈 chart increasing (chart, graph, growth, trend, upward) +📉 chart decreasing (chart, down, graph, trend) +📊 bar chart (bar, chart, graph) +📋 clipboard +📌 pushpin (pin) +📍 round pushpin (pin, pushpin) +📎 paperclip +🖇️ linked paperclips (link, paperclip) +📏 straight ruler (ruler, straight edge) +📐 triangular ruler (ruler, set, triangle) +✂️ scissors (cutting, tool) +🗃️ card file box (box, card, file) +🗄️ file cabinet (cabinet, file, filing) +🗑️ wastebasket +🔒 locked (closed) +🔓 unlocked (lock, open, unlock) +🔏 locked with pen (ink, lock, nib, pen, privacy) +🔐 locked with key (closed, key, lock, secure) +🔑 key (lock, password) +🗝️ old key (clue, key, lock, old) +🔨 hammer (tool) +🪓 axe (chop, hatchet, split, wood) +⛏️ pick (mining, tool) +⚒️ hammer and pick (hammer, pick, tool) +🛠️ hammer and wrench (hammer, spanner, tool, wrench) +🗡️ dagger (knife, weapon) +⚔️ crossed swords (crossed, swords, weapon) +🔫 water pistol (gun, handgun, pistol, revolver, tool, water, weapon) +🪃 boomerang (australia, rebound, repercussion) +🏹 bow and arrow (archer, arrow, bow, Sagittarius, zodiac) +🛡️ shield (weapon) +🪚 carpentry saw (carpenter, lumber, saw, tool) +🔧 wrench (spanner, tool) +🪛 screwdriver (screw, tool) +🔩 nut and bolt (bolt, nut, tool) +⚙️ gear (cog, cogwheel, tool) +🗜️ clamp (compress, tool, vice) +⚖️ balance scale (balance, justice, Libra, scale, zodiac) +🦯 white cane (accessibility, blind) +🔗 link +⛓️ chains (chain) +🪝 hook (catch, crook, curve, ensnare, selling point) +🧰 toolbox (chest, mechanic, tool) +🧲 magnet (attraction, horseshoe, magnetic) +🪜 ladder (climb, rung, step) +⚗️ alembic (chemistry, tool) +🧪 test tube (chemist, chemistry, experiment, lab, science) +🧫 petri dish (bacteria, biologist, biology, culture, lab) +🧬 dna (biologist, evolution, gene, genetics, life) +🔬 microscope (science, tool) +🔭 telescope (science, tool) +📡 satellite antenna (antenna, dish, satellite) +💉 syringe (medicine, needle, shot, sick) +🩸 drop of blood (bleed, blood donation, injury, medicine, menstruation) +💊 pill (doctor, medicine, sick) +🩹 adhesive bandage (bandage) +🩺 stethoscope (doctor, heart, medicine) +🚪 door +🛗 elevator (accessibility, hoist, lift) +🪞 mirror (reflection, reflector, speculum) +🪟 window (frame, fresh air, opening, transparent, view) +🛏️ bed (hotel, sleep) +🛋️ couch and lamp (couch, hotel, lamp) +🪑 chair (seat, sit) +🚽 toilet +🪠 plunger (force cup, plumber, suction, toilet) +🚿 shower (water) +🛁 bathtub (bath) +🪤 mouse trap (bait, mousetrap, snare, trap) +🪒 razor (sharp, shave) +🧴 lotion bottle (lotion, moisturizer, shampoo, sunscreen) +🧷 safety pin (diaper, punk rock) +🧹 broom (cleaning, sweeping, witch) +🧺 basket (farming, laundry, picnic) +🧻 roll of paper (paper towels, toilet paper) +🪣 bucket (cask, pail, vat) +🧼 soap (bar, bathing, cleaning, lather, soapdish) +🪥 toothbrush (bathroom, brush, clean, dental, hygiene, teeth) +🧽 sponge (absorbing, cleaning, porous) +🧯 fire extinguisher (extinguish, fire, quench) +🛒 shopping cart (cart, shopping, trolley) +🚬 cigarette (smoking) +⚰️ coffin (death) +🪦 headstone (cemetery, grave, graveyard, tombstone) +⚱️ funeral urn (ashes, death, funeral, urn) +🗿 moai (face, moyai, statue) +🪧 placard (demonstration, picket, protest, sign) +🏧 ATM sign (ATM, automated, bank, teller) +🚮 litter in bin sign (litter, litter bin) +🚰 potable water (drinking, potable, water) +♿ wheelchair symbol (access) +🚹 men’s room (bathroom, lavatory, man, restroom, toilet, WC) +🚺 women’s room (bathroom, lavatory, restroom, toilet, WC, woman) +🚻 restroom (bathroom, lavatory, toilet, WC) +🚼 baby symbol (baby, changing) +🚾 water closet (bathroom, closet, lavatory, restroom, toilet, water, WC) +🛂 passport control (control, passport) +🛃 customs +🛄 baggage claim (baggage, claim) +🛅 left luggage (baggage, locker, luggage) +⚠️ warning +🚸 children crossing (child, crossing, pedestrian, traffic) +⛔ no entry (entry, forbidden, no, not, prohibited, traffic) +🚫 prohibited (entry, forbidden, no, not) +🚳 no bicycles (bicycle, bike, forbidden, no, prohibited) +🚭 no smoking (forbidden, no, not, prohibited, smoking) +🚯 no littering (forbidden, litter, no, not, prohibited) +🚱 non-potable water (non-drinking, non-potable, water) +🚷 no pedestrians (forbidden, no, not, pedestrian, prohibited) +📵 no mobile phones (cell, forbidden, mobile, no, phone) +🔞 no one under eighteen (18, age restriction, eighteen, prohibited, underage) +☢️ radioactive (sign) +☣️ biohazard (sign) +⬆️ up arrow (arrow, cardinal, direction, north) +↗️ up-right arrow (arrow, direction, intercardinal, northeast) +➡️ right arrow (arrow, cardinal, direction, east) +↘️ down-right arrow (arrow, direction, intercardinal, southeast) +⬇️ down arrow (arrow, cardinal, direction, down, south) +↙️ down-left arrow (arrow, direction, intercardinal, southwest) +⬅️ left arrow (arrow, cardinal, direction, west) +↖️ up-left arrow (arrow, direction, intercardinal, northwest) +↕️ up-down arrow (arrow) +↔️ left-right arrow (arrow) +↩️ right arrow curving left (arrow) +↪️ left arrow curving right (arrow) +⤴️ right arrow curving up (arrow) +⤵️ right arrow curving down (arrow, down) +🔃 clockwise vertical arrows (arrow, clockwise, reload) +🔄 counterclockwise arrows button (anticlockwise, arrow, counterclockwise, withershins) +🔙 BACK arrow (arrow, BACK) +🔚 END arrow (arrow, END) +🔛 ON! arrow (arrow, mark, ON, ON!) +🔜 SOON arrow (arrow, SOON) +🔝 TOP arrow (arrow, TOP, up) +🛐 place of worship (religion, worship) +⚛️ atom symbol (atheist, atom) +🕉️ om (Hindu, religion) +✡️ star of David (David, Jew, Jewish, religion, star) +☸️ wheel of dharma (Buddhist, dharma, religion, wheel) +☯️ yin yang (religion, tao, taoist, yang, yin) +✝️ latin cross (Christian, cross, religion) +☦️ orthodox cross (Christian, cross, religion) +☪️ star and crescent (islam, Muslim, religion) +☮️ peace symbol (peace) +🕎 menorah (candelabrum, candlestick, religion) +🔯 dotted six-pointed star (fortune, star) +♈ Aries (ram, zodiac) +♉ Taurus (bull, ox, zodiac) +♊ Gemini (twins, zodiac) +♋ Cancer (crab, zodiac) +♌ Leo (lion, zodiac) +♍ Virgo (zodiac) +♎ Libra (balance, justice, scales, zodiac) +♏ Scorpio (scorpion, scorpius, zodiac) +♐ Sagittarius (archer, zodiac) +♑ Capricorn (goat, zodiac) +♒ Aquarius (bearer, water, zodiac) +♓ Pisces (fish, zodiac) +⛎ Ophiuchus (bearer, serpent, snake, zodiac) +🔀 shuffle tracks button (arrow, crossed) +🔁 repeat button (arrow, clockwise, repeat) +🔂 repeat single button (arrow, clockwise, once) +▶️ play button (arrow, play, right, triangle) +⏩ fast-forward button (arrow, double, fast, forward) +⏭️ next track button (arrow, next scene, next track, triangle) +⏯️ play or pause button (arrow, pause, play, right, triangle) +◀️ reverse button (arrow, left, reverse, triangle) +⏪ fast reverse button (arrow, double, rewind) +⏮️ last track button (arrow, previous scene, previous track, triangle) +🔼 upwards button (arrow, button, red) +⏫ fast up button (arrow, double) +🔽 downwards button (arrow, button, down, red) +⏬ fast down button (arrow, double, down) +⏸️ pause button (bar, double, pause, vertical) +⏹️ stop button (square, stop) +⏺️ record button (circle, record) +⏏️ eject button (eject) +🎦 cinema (camera, film, movie) +🔅 dim button (brightness, dim, low) +🔆 bright button (bright, brightness) +📶 antenna bars (antenna, bar, cell, mobile, phone) +📳 vibration mode (cell, mobile, mode, phone, telephone, vibration) +📴 mobile phone off (cell, mobile, off, phone, telephone) +♀️ female sign (woman) +♂️ male sign (man) +⚧️ transgender symbol (transgender) +✖️ multiply (×, cancel, multiplication, sign, x) +➕ plus (+, math, sign) +➖ minus (-, −, math, sign) +➗ divide (÷, division, math, sign) +♾️ infinity (forever, unbounded, universal) +‼️ double exclamation mark (!, !!, bangbang, exclamation, mark) +⁉️ exclamation question mark (!, !?, ?, exclamation, interrobang, mark, punctuation, question) +❓ red question mark (?, mark, punctuation, question) +❔ white question mark (?, mark, outlined, punctuation, question) +❕ white exclamation mark (!, exclamation, mark, outlined, punctuation) +❗ red exclamation mark (!, exclamation, mark, punctuation) +〰️ wavy dash (dash, punctuation, wavy) +💱 currency exchange (bank, currency, exchange, money) +💲 heavy dollar sign (currency, dollar, money) +⚕️ medical symbol (aesculapius, medicine, staff) +♻️ recycling symbol (recycle) +⚜️ fleur-de-lis +🔱 trident emblem (anchor, emblem, ship, tool, trident) +📛 name badge (badge, name) +🔰 Japanese symbol for beginner (beginner, chevron, Japanese, leaf) +⭕ hollow red circle (circle, large, o, red) +✅ check mark button (✓, button, check, mark) +☑️ check box with check (✓, box, check) +✔️ check mark (✓, check, mark) +❌ cross mark (×, cancel, cross, mark, multiplication, multiply, x) +❎ cross mark button (×, mark, square, x) +➰ curly loop (curl, loop) +➿ double curly loop (curl, double, loop) +〽️ part alternation mark (mark, part) +✳️ eight-spoked asterisk (*, asterisk) +✴️ eight-pointed star (*, star) +❇️ sparkle (*) +©️ copyright (C) +®️ registered (R) +™️ trade mark (mark, TM, trademark) +#️⃣ keycap # +*️⃣ keycap * +0️⃣ keycap 0 +1️⃣ keycap 1 +2️⃣ keycap 2 +3️⃣ keycap 3 +4️⃣ keycap 4 +5️⃣ keycap 5 +6️⃣ keycap 6 +7️⃣ keycap 7 +8️⃣ keycap 8 +9️⃣ keycap 9 +🔟 keycap 10 +🔠 input latin uppercase (ABCD, input, latin, letters, uppercase) +🔡 input latin lowercase (abcd, input, latin, letters, lowercase) +🔢 input numbers (1234, input, numbers) +🔣 input symbols (〒♪&%, input) +🔤 input latin letters (abc, alphabet, input, latin, letters) +🅰️ A button (blood type) (A, blood type) +🆎 AB button (blood type) (AB, blood type) +🅱️ B button (blood type) (B, blood type) +🆑 CL button (CL) +🆒 COOL button (COOL) +🆓 FREE button (FREE) +ℹ️ information (i) +🆔 ID button (ID, identity) +Ⓜ️ circled M (circle, M) +🆕 NEW button (NEW) +🆖 NG button (NG) +🅾️ O button (blood type) (blood type, O) +🆗 OK button (OK) +🅿️ P button (P, parking) +🆘 SOS button (help, SOS) +🆙 UP! button (mark, UP, UP!) +🆚 VS button (versus, VS) +🈁 Japanese “here” button (“here”, Japanese, katakana, ココ) +🈂️ Japanese “service charge” button (“service charge”, Japanese, katakana, サ) +🈷️ Japanese “monthly amount” button (“monthly amount”, ideograph, Japanese, 月) +🈶 Japanese “not free of charge” button (“not free of charge”, ideograph, Japanese, 有) +🈯 Japanese “reserved” button (“reserved”, ideograph, Japanese, 指) +🉐 Japanese “bargain” button (“bargain”, ideograph, Japanese, 得) +🈹 Japanese “discount” button (“discount”, ideograph, Japanese, 割) +🈚 Japanese “free of charge” button (“free of charge”, ideograph, Japanese, 無) +🈲 Japanese “prohibited” button (“prohibited”, ideograph, Japanese, 禁) +🉑 Japanese “acceptable” button (“acceptable”, ideograph, Japanese, 可) +🈸 Japanese “application” button (“application”, ideograph, Japanese, 申) +🈴 Japanese “passing grade” button (“passing grade”, ideograph, Japanese, 合) +🈳 Japanese “vacancy” button (“vacancy”, ideograph, Japanese, 空) +㊗️ Japanese “congratulations” button (“congratulations”, ideograph, Japanese, 祝) +㊙️ Japanese “secret” button (“secret”, ideograph, Japanese, 秘) +🈺 Japanese “open for business” button (“open for business”, ideograph, Japanese, 営) +🈵 Japanese “no vacancy” button (“no vacancy”, ideograph, Japanese, 満) +🔴 red circle (circle, geometric, red) +🟠 orange circle (circle, orange) +🟡 yellow circle (circle, yellow) +🟢 green circle (circle, green) +🔵 blue circle (blue, circle, geometric) +🟣 purple circle (circle, purple) +🟤 brown circle (brown, circle) +⚫ black circle (circle, geometric) +⚪ white circle (circle, geometric) +🟥 red square (red, square) +🟧 orange square (orange, square) +🟨 yellow square (square, yellow) +🟩 green square (green, square) +🟦 blue square (blue, square) +🟪 purple square (purple, square) +🟫 brown square (brown, square) +⬛ black large square (geometric, square) +⬜ white large square (geometric, square) +◼️ black medium square (geometric, square) +◻️ white medium square (geometric, square) +◾ black medium-small square (geometric, square) +◽ white medium-small square (geometric, square) +▪️ black small square (geometric, square) +▫️ white small square (geometric, square) +🔶 large orange diamond (diamond, geometric, orange) +🔷 large blue diamond (blue, diamond, geometric) +🔸 small orange diamond (diamond, geometric, orange) +🔹 small blue diamond (blue, diamond, geometric) +🔺 red triangle pointed up (geometric, red) +🔻 red triangle pointed down (down, geometric, red) +💠 diamond with a dot (comic, diamond, geometric, inside) +🔘 radio button (button, geometric, radio) +🔳 white square button (button, geometric, outlined, square) +🔲 black square button (button, geometric, square) +🏁 chequered flag (checkered, chequered, racing) +🚩 triangular flag (post) +🎌 crossed flags (celebration, cross, crossed, Japanese) +🏴 black flag (waving) +🏳️ white flag (waving) +🏳️‍🌈 rainbow flag +🏳️‍⚧️ transgender flag +🏴‍☠️ pirate flag (Jolly Roger, pirate, plunder, treasure) +🇦🇨 flag Ascension Island +🇦🇩 flag Andorra +🇦🇪 flag United Arab Emirates +🇦🇫 flag Afghanistan +🇦🇬 flag Antigua & Barbuda +🇦🇮 flag Anguilla +🇦🇱 flag Albania +🇦🇲 flag Armenia +🇦🇴 flag Angola +🇦🇶 flag Antarctica +🇦🇷 flag Argentina +🇦🇸 flag American Samoa +🇦🇹 flag Austria +🇦🇺 flag Australia +🇦🇼 flag Aruba +🇦🇽 flag Åland Islands +🇦🇿 flag Azerbaijan +🇧🇦 flag Bosnia & Herzegovina +🇧🇧 flag Barbados +🇧🇩 flag Bangladesh +🇧🇪 flag Belgium +🇧🇫 flag Burkina Faso +🇧🇬 flag Bulgaria +🇧🇭 flag Bahrain +🇧🇮 flag Burundi +🇧🇯 flag Benin +🇧🇱 flag St. Barthélemy +🇧🇲 flag Bermuda +🇧🇳 flag Brunei +🇧🇴 flag Bolivia +🇧🇶 flag Caribbean Netherlands +🇧🇷 flag Brazil +🇧🇸 flag Bahamas +🇧🇹 flag Bhutan +🇧🇻 flag Bouvet Island +🇧🇼 flag Botswana +🇧🇾 flag Belarus +🇧🇿 flag Belize +🇨🇦 flag Canada +🇨🇨 flag Cocos (Keeling) Islands +🇨🇩 flag Congo - Kinshasa +🇨🇫 flag Central African Republic +🇨🇬 flag Congo - Brazzaville +🇨🇭 flag Switzerland +🇨🇮 flag Côte d’Ivoire +🇨🇰 flag Cook Islands +🇨🇱 flag Chile +🇨🇲 flag Cameroon +🇨🇳 flag China +🇨🇴 flag Colombia +🇨🇵 flag Clipperton Island +🇨🇷 flag Costa Rica +🇨🇺 flag Cuba +🇨🇻 flag Cape Verde +🇨🇼 flag Curaçao +🇨🇽 flag Christmas Island +🇨🇾 flag Cyprus +🇨🇿 flag Czechia +🇩🇪 flag Germany +🇩🇬 flag Diego Garcia +🇩🇯 flag Djibouti +🇩🇰 flag Denmark +🇩🇲 flag Dominica +🇩🇴 flag Dominican Republic +🇩🇿 flag Algeria +🇪🇦 flag Ceuta & Melilla +🇪🇨 flag Ecuador +🇪🇪 flag Estonia +🇪🇬 flag Egypt +🇪🇭 flag Western Sahara +🇪🇷 flag Eritrea +🇪🇸 flag Spain +🇪🇹 flag Ethiopia +🇪🇺 flag European Union +🇫🇮 flag Finland +🇫🇯 flag Fiji +🇫🇰 flag Falkland Islands +🇫🇲 flag Micronesia +🇫🇴 flag Faroe Islands +🇫🇷 flag France +🇬🇦 flag Gabon +🇬🇧 flag United Kingdom +🇬🇩 flag Grenada +🇬🇪 flag Georgia +🇬🇫 flag French Guiana +🇬🇬 flag Guernsey +🇬🇭 flag Ghana +🇬🇮 flag Gibraltar +🇬🇱 flag Greenland +🇬🇲 flag Gambia +🇬🇳 flag Guinea +🇬🇵 flag Guadeloupe +🇬🇶 flag Equatorial Guinea +🇬🇷 flag Greece +🇬🇸 flag South Georgia & South Sandwich Islands +🇬🇹 flag Guatemala +🇬🇺 flag Guam +🇬🇼 flag Guinea-Bissau +🇬🇾 flag Guyana +🇭🇰 flag Hong Kong SAR China +🇭🇲 flag Heard & McDonald Islands +🇭🇳 flag Honduras +🇭🇷 flag Croatia +🇭🇹 flag Haiti +🇭🇺 flag Hungary +🇮🇨 flag Canary Islands +🇮🇩 flag Indonesia +🇮🇪 flag Ireland +🇮🇱 flag Israel +🇮🇲 flag Isle of Man +🇮🇳 flag India +🇮🇴 flag British Indian Ocean Territory +🇮🇶 flag Iraq +🇮🇷 flag Iran +🇮🇸 flag Iceland +🇮🇹 flag Italy +🇯🇪 flag Jersey +🇯🇲 flag Jamaica +🇯🇴 flag Jordan +🇯🇵 flag Japan +🇰🇪 flag Kenya +🇰🇬 flag Kyrgyzstan +🇰🇭 flag Cambodia +🇰🇮 flag Kiribati +🇰🇲 flag Comoros +🇰🇳 flag St. Kitts & Nevis +🇰🇵 flag North Korea +🇰🇷 flag South Korea +🇰🇼 flag Kuwait +🇰🇾 flag Cayman Islands +🇰🇿 flag Kazakhstan +🇱🇦 flag Laos +🇱🇧 flag Lebanon +🇱🇨 flag St. Lucia +🇱🇮 flag Liechtenstein +🇱🇰 flag Sri Lanka +🇱🇷 flag Liberia +🇱🇸 flag Lesotho +🇱🇹 flag Lithuania +🇱🇺 flag Luxembourg +🇱🇻 flag Latvia +🇱🇾 flag Libya +🇲🇦 flag Morocco +🇲🇨 flag Monaco +🇲🇩 flag Moldova +🇲🇪 flag Montenegro +🇲🇫 flag St. Martin +🇲🇬 flag Madagascar +🇲🇭 flag Marshall Islands +🇲🇰 flag North Macedonia +🇲🇱 flag Mali +🇲🇲 flag Myanmar (Burma) +🇲🇳 flag Mongolia +🇲🇴 flag Macao SAR China +🇲🇵 flag Northern Mariana Islands +🇲🇶 flag Martinique +🇲🇷 flag Mauritania +🇲🇸 flag Montserrat +🇲🇹 flag Malta +🇲🇺 flag Mauritius +🇲🇻 flag Maldives +🇲🇼 flag Malawi +🇲🇽 flag Mexico +🇲🇾 flag Malaysia +🇲🇿 flag Mozambique +🇳🇦 flag Namibia +🇳🇨 flag New Caledonia +🇳🇪 flag Niger +🇳🇫 flag Norfolk Island +🇳🇬 flag Nigeria +🇳🇮 flag Nicaragua +🇳🇱 flag Netherlands +🇳🇴 flag Norway +🇳🇵 flag Nepal +🇳🇷 flag Nauru +🇳🇺 flag Niue +🇳🇿 flag New Zealand +🇴🇲 flag Oman +🇵🇦 flag Panama +🇵🇪 flag Peru +🇵🇫 flag French Polynesia +🇵🇬 flag Papua New Guinea +🇵🇭 flag Philippines +🇵🇰 flag Pakistan +🇵🇱 flag Poland +🇵🇲 flag St. Pierre & Miquelon +🇵🇳 flag Pitcairn Islands +🇵🇷 flag Puerto Rico +🇵🇸 flag Palestinian Territories +🇵🇹 flag Portugal +🇵🇼 flag Palau +🇵🇾 flag Paraguay +🇶🇦 flag Qatar +🇷🇪 flag Réunion +🇷🇴 flag Romania +🇷🇸 flag Serbia +🇷🇺 flag Russia +🇷🇼 flag Rwanda +🇸🇦 flag Saudi Arabia +🇸🇧 flag Solomon Islands +🇸🇨 flag Seychelles +🇸🇩 flag Sudan +🇸🇪 flag Sweden +🇸🇬 flag Singapore +🇸🇭 flag St. Helena +🇸🇮 flag Slovenia +🇸🇯 flag Svalbard & Jan Mayen +🇸🇰 flag Slovakia +🇸🇱 flag Sierra Leone +🇸🇲 flag San Marino +🇸🇳 flag Senegal +🇸🇴 flag Somalia +🇸🇷 flag Suriname +🇸🇸 flag South Sudan +🇸🇹 flag São Tomé & Príncipe +🇸🇻 flag El Salvador +🇸🇽 flag Sint Maarten +🇸🇾 flag Syria +🇸🇿 flag Eswatini +🇹🇦 flag Tristan da Cunha +🇹🇨 flag Turks & Caicos Islands +🇹🇩 flag Chad +🇹🇫 flag French Southern Territories +🇹🇬 flag Togo +🇹🇭 flag Thailand +🇹🇯 flag Tajikistan +🇹🇰 flag Tokelau +🇹🇱 flag Timor-Leste +🇹🇲 flag Turkmenistan +🇹🇳 flag Tunisia +🇹🇴 flag Tonga +🇹🇷 flag Turkey +🇹🇹 flag Trinidad & Tobago +🇹🇻 flag Tuvalu +🇹🇼 flag Taiwan +🇹🇿 flag Tanzania +🇺🇦 flag Ukraine +🇺🇬 flag Uganda +🇺🇲 flag U.S. Outlying Islands +🇺🇳 flag United Nations +🇺🇸 flag United States +🇺🇾 flag Uruguay +🇺🇿 flag Uzbekistan +🇻🇦 flag Vatican City +🇻🇨 flag St. Vincent & Grenadines +🇻🇪 flag Venezuela +🇻🇬 flag British Virgin Islands +🇻🇮 flag U.S. Virgin Islands +🇻🇳 flag Vietnam +🇻🇺 flag Vanuatu +🇼🇫 flag Wallis & Futuna +🇼🇸 flag Samoa +🇽🇰 flag Kosovo +🇾🇪 flag Yemen +🇾🇹 flag Mayotte +🇿🇦 flag South Africa +🇿🇲 flag Zambia +🇿🇼 flag Zimbabwe +🏴󠁧󠁢󠁥󠁮󠁧󠁿 flag England +🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag Scotland +🏴󠁧󠁢󠁷󠁬󠁳󠁿 flag Wales diff --git a/.local/bin/dmenu-fix-sheet b/.local/bin/dmenu-fix-sheet @@ -0,0 +1,21 @@ +#!/bin/sh +# Some cheatsheet for some fast fixes wouldn't be bad. +CHOICE="$(printf '%s\n' "background noise in pulse" \ + | dmenu -p "Get Help For Some Quick Fix:" -l 20)" +case "$CHOICE" in + "background noise in pulse") + printf '# My fix for background noise in pulse.\n' + printf '#\n' + printf '# 1. Run privilaged:\n' + printf '# doas ./fix.mic.sh\n' + printf '# 2. Restart Audio Server:\n' + printf '# pulseaudio -k\n' + printf '#\n' + printf 'doas cp /etc/pulse/default.pa /etc/pulse/default.pa.bak\n' + printf 'doas cat << EOT >> /etc/pulse/default.pa\n' + printf 'load-module module-echo-cancel source_name=noechosource sink_name=noechosink\n' + printf 'set-default-source noechosource\n' + printf 'set-default-sink noechosink\n' + printf 'EOT\n' + ;; +esac diff --git a/.local/bin/dmenu-man b/.local/bin/dmenu-man @@ -0,0 +1,3 @@ +#!/bin/sh +CHOICE="$(man -k . | dmenu -p 'Choose Manual:' -l 20 | awk '{print $1"."$2}' | sed 's/(//;s/)//')" +[ "$CHOICE" ] && man -Tpdf "$CHOICE" | zathura - diff --git a/.local/bin/dmenu-mpd b/.local/bin/dmenu-mpd @@ -0,0 +1,41 @@ +#!/bin/sh +# Needs preselect patch for dmenu to preselect item. +pgrep -x mpd || mpd +export CURRENT_PLAYER="mpd" + +next_song="$(mpc queued)" +prev_song="$(($(mpc | awk '/#/{sub(/\/.*/, "", $2);sub(/#/, "", $2);print $2}')-1))" +prev_song="$(mpc playlist | sed -n ${prev_song}p)" +curr_song="$(mpc --format '[%title%|%file%]' current)" +n=0 + +[ ! "$next_song" ] || btn_next="⏭️ Next Song (\"$next_song\")" +[ ! "$prev_song" ] || btn_prev="⏮️ Prev Song (\"$prev_song\")" +[ ! "$curr_song" ] || btn_play="⏯️ Play (\"$curr_song\")" \ + && btn_pause="⏸️ Pause (\"$curr_song\")" && mpc status | grep -q 'playing' \ + && btn_curr="$btn_pause" || btn_curr="$btn_play" +([ "$btn_curr" ] || [ "$btn_next" ] || [ "$btn_prev" ]) && \ +seperator="-----------------------------------------------------------------------------------" + +[ ! "$btn_next" ] || n="$((n+1))" +[ ! "$btn_prev" ] || n="$((n+1))" +[ ! "$btn_curr" ] || n="$((n+1))" +[ ! "$seperator" ] || n="$((n+1))" + +menu="$btn_prev +$btn_curr +$btn_next +$seperator +$(mpc listall | sort)" +menu="$(printf "%s" "${menu}" | sed '/^\s*$/d')" + +choice="$(printf "%s" "${menu}" | dmenu -i -n "$n" -l 20)" + +if [ "$choice" ]; then + case "$choice" in + "$btn_play"|"$btn_pause") mpc -q toggle ;; + "$btn_next") mpc -q next ;; + "$btn_prev") mpc -q prev ;; + *) mpc add "$choice" && mpc play $(mpc playlist | wc -l);; + esac +fi diff --git a/.local/bin/dmenu-power b/.local/bin/dmenu-power @@ -0,0 +1,20 @@ +#!/bin/sh +ask() { + prompt="Do you really want to $1?" + answer="$(printf 'Yes\nNo' | dmenu -i -p "$prompt")" + [ "$answer" = "Yes" ] && doas-askpass "$2" +} + +btn_power="📴 Poweroff" +btn_reboot="🔄 Reboot" +btn_logout="🚪 Logout" + +CHOICE="$(printf '%s\n' "$btn_logout" "$btn_reboot" "$btn_power" | dmenu -i -p "🔌 Powermenu:")" +[ "$CHOICE" ] || exit 2 + +case "$CHOICE" in + #"$btn_logout") ask "logout from \"$(logname)\"" "pkill -KILL -u \"$(logname)\"" ;; + "$btn_logout") ask "logout from \"$(logname)\"" "kill -9 -1" ;; + "$btn_reboot") ask "reboot this machine" "reboot" ;; + "$btn_power") ask "this computer to shutdown" "shutdown now";; +esac diff --git a/.local/bin/dmenu-record b/.local/bin/dmenu-record @@ -0,0 +1,128 @@ +#!/bin/sh +# TODO: REWRITE THIS +dunstify "FIX THIS" "$0" +exit $? + +# Audio server and webcam configuration. +AUDIO_HANDLER="${AUDIO_HANDLER:-alsa}" +WEBCAM_DRIVER="${WEBCAM_DRIVER:-v4l2}" +WEBCAM_DEVICE="${WEBCAM_DEVICE:-/dev/video0}" + +# Get recorder settings. +SR_DIR="{SR_DIR:-$(xdg-user-dir VIDEOS)}" +SR_VIDEO_DIR="${SR_VIDEO_DIR:-$SR_DIR/video-$(date '+%y%m%d-%H%M-%S').mkv}" +SR_GIF_DIR="${SR_GIF_DIR:-$SR_DIR/gif-$(date '+%y%m%d-%H%M-%S').gif}" +SR_AUDIO_DIR="${SR_AUDIO_DIR:-$SR_DIR/audio-$(date '+%y%m%d-%H%M-%S').flac}" +SR_WEBCAM_DIR="${SR_WEBCAM_DIR:-$SR_DIR/webcam-$(date '+%y%m%d-%H%M-%S').mkv}" +SR_AUDIO_TAGS="${SR_AUDIO_TAGS:--f ${AUDIO_HANDLER} -i default -c:a flac}" +SR_PID="${SR_PID:-/tmp/recordingpid}" + +# Get the options +while getopts ":ast:" option; do + case "$option" in + a) ENABLE_AUDIO="TRUE" ;; + s) ENABLE_SELECTION="TRUE" ;; + t) TYPE="$OPTARG" ;; + *) usage ;; + esac +done +[ "$ENABLE_AUDIO" = "TRUE" ] || SR_AUDIO_TAGS="" + +select_window() { + if type slop >/dev/null; then + window="$(slop -qf "%x %y %w %h")" + [ "$window" ] || exit 2 + LEFT="$(echo "$window" | awk -F' ' '{print $1}')" + TOP="$(echo "$window" | awk -F' ' '{print $2}')" + WIDTH="$(echo "$window" | awk -F' ' '{print $3}')" + HEIGHT="$(echo "$window" | awk -F' ' '{print $4}')" + else + window="$(xwininfo)" + LEFT="$(echo "$window" | grep -o "Absolute upper-left X:[[:space:]]*[0-9]*" | grep -o "[0-9]*")" + TOP="$(echo "$window" | grep -o "Absolute upper-left Y:[[:space:]]*[0-9]*" | grep -o "[0-9]*")" + WIDTH="$(echo "$window" | grep -o "Width:[[:space:]]*[0-9]*" | grep -o "[0-9]*")" + HEIGHT="$(echo "$window" | grep -o "Height:[[:space:]]*[0-9]*" | grep -o "[0-9]*")" + fi +} + +video() { + [ "$ENABLE_SELECTION" = "TRUE" ] && select_window + ffmpeg -f x11grab \ + -s "$(xdpyinfo | awk '/dimensions/ {print $2;}')" \ + -i "$DISPLAY" \ + "$SR_AUDIO_TAGS" \ + -framerate 30 \ + -c:v h264 -crf 0 -preset ultrafast -c:a aac \ + "$SR_VIDEO_DIR" & + echo $! > "$SR_PID" + dunstify -u low -h string:x-dunst-stack-tag:recorder -t 700 -i "window" "壘 Recording screen" \ + "Saving to <span size='small'><u>$SR_VIDEO_DIR</u></span>..." +} +gif() { # NEEDS FIX + WIDTHxHEIGHT="$(xdpyinfo | awk '/dimensions/ {print $2}')" + WIDTH="${WIDTHxHEIGHT%x*}" ; HEIGHT="${WIDTHxHEIGHT#*x}" + LEFT=0 ; TOP=0 + [ "$ENABLE_SELECTION" = "TRUE" ] && select_window + ffmpeg -f x11grab \ + -framerate 30 \ + -s "${WIDTH}x${HEIGHT}" \ + -i "$DISPLAY+$LEFT,$TOP" \ + "$SR_GIF_DIR" & + echo $! > "$SR_PID" + dunstify -u low -h string:x-dunst-stack-tag:recorder -t 700 -i "window" "壘 Recording screen" \ + "Saving to <span size='small'><u>$SR_VIDEO_DIR</u></span>..." +} +webcam() { + WEBCAM_WIDTHxHEIGHT=$(ffmpeg -f "$WEBCAM_DRIVER" -list_formats all -i "$WEBCAM_DEVICE" 2>&1 \ + | head -1 | awk -F' ' '{print $NF}') + ffmpeg "${SR_AUDIO_TAGS}" \ + -f "${WEBCAM_DRIVER}" \ + -i "${WEBCAM_DEVICE}" \ + -video_size "${WEBCAM_WIDTHxHEIGHT}" \ + "${SR_WEBCAM_DIR}" & + echo $! > "$SR_PID" + dunstify -u low -h string:x-dunst-stack-tag:recorder -t 700 -i "camera" "壘 Recording webcam" \ + "Saving to <span size='small'><u>$SR_WEBCAM_DIR</u></span>..." +} +audio() { + ffmpeg -f "${AUDIO_HANDLER}" \ + -i default \ + -c:a flac \ + "${SR_AUDIO_DIR}" & + echo $! > "$SR_PID" + dunstify -u low -h string:x-dunst-stack-tag:recorder -t 700 -i "mic-ready" "壘 Recording audio" \ + "Saving to <span size='small'><u>$SR_AUDIO_DIR</u></span>..." +} +endrec() { + PID="$(cat "$SR_PID")" + if ps -p "$PID" >/dev/null; then + COMM="$(ps -p "$PID" -o command=)" + NAME="$(echo "$COMM" | awk '{print $NF}')" + kill "$PID" + while kill -0 "$PID"; do sleep 1; kill "$PID"; done + rm -f "$SR_PID" + dunstify -u low -h string:x-dunst-stack-tag:recorder -t 3000 -i "record" "壘 Recording acquired!" "Saved to <span size='small'><u>$NAME</u></span>!" + echo "Recording stopped." + else + echo "No recording found to stop..." + fi +} +askendrec() { + [ -e "$SR_PID" ] || return + PID=$(cat "$SR_PID") + if ps -p "$PID" >/dev/null; then + printf "You are already recording, would you like to end the last one? [y/N] "; read -r ASK + case "$ASK" in + [Yy][Ee][Ss]|[Yy]) endrec ;; + [Nn][Oo]|[Nn]|*) exit ;; + esac + fi +} + +case "$TYPE" in + video) askendrec ; video ; exit ;; + gif) askendrec ; gif ; exit ;; + audio) askendrec ; audio ; exit ;; + webcam) askendrec ; webcam ; exit ;; + end) endrec ; exit ;; +esac diff --git a/.local/bin/doas-askpass b/.local/bin/doas-askpass @@ -0,0 +1,36 @@ +#!/usr/local/bin/expect -- + +# askpass implementation for doas +# /home/mahdi/.local/bin/doas-askpass +# Example: +# DOAS_ASKPASS="dmenu -P -p Password:" doas-askpass echo doas + +# don’t mind the man behind the curtain +log_user 0 + +# no command, then nothing to do +if { $argc == 0 } { exit 0 } + +# treat all arguments as command input +set cmd [lrange $argv 0 end]; + +# read askpass from env or fallback to dmanu_pass () +if {[info exists ::env(DOAS_ASKPASS)]} { + set askpass "$::env(DOAS_ASKPASS)" +} else { + set askpass "dmenu-askpass Password:" +} + +# read password from user +set pwd [exec {*}$askpass] + +# spawn doas operation +spawn doas {*}$cmd + +# send password and execute command +expect "doas*password:" { + send -- "$pwd\r" + expect \r + log_user 1 + expect eof +} diff --git a/.local/bin/dwm-bar b/.local/bin/dwm-bar @@ -0,0 +1,391 @@ +#!/bin/sh +# TODO: Add OpenBSD support for Volume, Battery Modules + +# ------------------ # +# ----- Config ----- # +# ------------------ # + +# Colorful status: change to 1 if you want your modules colored. (Xresources) +COLORFUL=0 + +# Colorful background: Change to 1 if you want your modules' +# backgrounds to be set to your Xresources background colors, +# But darkened for each module to a certain number from left to right. +# Note: *REQUIRES COLORFUL=1* +COLORFUL_BACKGROUND=0 + +# The location for weather module, the necessary information is parsed from: +# v2d.wttr.in/${WEATHER_LOC} +WEATHER_LOC="Babol" + +# The keyboard layouts you want to use in "Keyboard" module. +# You can modify your own layouts, +# *:%; +# Where: +# * -> The order of the layout you've set from setxkbmap (starting from 0) +# % -> The name you want the module to return for the layout. +KBD_LAYOUTS="0:English;1:Persian;" + +KERNEL=$(uname) + +# ------------------ # +# ---- Modules ----- # +# ------------------ # +Weather(){ + find "$HOME/.cache/weather" -mmin +59 -delete + if [ ! -f "$HOME/.cache/weather" ] || [ -z "$(cat "$HOME/.cache/weather" >/dev/null 2>&1)" ] ; then + weather=$(curl -s "v2d.wttr.in/${WEATHER_LOC}" \ + | sed "/Weather:/!d;s/Weather://;s/,//g;s/+//g;s/°C.*//;s/.*m//;s/ //;s/ //;s/ //") + [ "$weather" ] && echo "${weather}°C" > "$HOME/.cache/weather" + fi + weather=$(cat "$HOME/.cache/weather") + printf "%s" "$weather" +} + +Keyboard(){ + KBD=$(xset -q | grep LED | awk '{ print substr($10,5,1) }') + KBD=$(echo "$KBD_LAYOUTS" | sed "s/;/\n/g" | sed "/$KBD:/!d;s/.*://") + printf " %s" "${KBD}" +} + +Battery() { + CHARGING_ICON='' + WARNING_ICON='' + BATTERY_FULL_ICON='' + BATTERY_2_ICON='' + BATTERY_3_ICON='' + BATTERY_4_ICON='' + + FULL_AT=98 + + BAT_ICON="" + ICON="" + + case "$KERNEL" in + Linux*) + BAT=$(ls /sys/class/power_supply/ | head -n 1) + if [ -d "$BAT" ]; then + CAPACITY=$(ls "${BAT}/capacity") + CHARGING=$(ls "${BAT}/status") + fi + [ "$CHARGING" = "Charging" ] && ICON=$CHARGING_ICON + ;; + FreeBSD*) + CAPACITY=$(sysctl -n hw.acpi.battery.life) + CHARGING=$(sysctl -n hw.acpi.battery.state) + [ $CHARGING -eq 2 ] && ICON=$CHARGING_ICON + ;; + esac + + [ -z "$ICON" ] && [ $CAPACITY -le 25 ] && ICON=$WARNING_ICON + + if [ "$CAPACITY" -ge "$FULL_AT" ]; then + BAT_ICON=$BATTERY_FULL_ICON + CAPACITY=100 + elif [ "$CAPACITY" -le 25 ]; then + BAT_ICON=$BATTERY_4_ICON + elif [ "$CAPACITY" -le 60 ]; then + BAT_ICON=$BATTERY_3_ICON + elif [ "$CAPACITY" -le "$FULL_AT" ]; then + BAT_ICON=$BATTERY_2_ICON + fi + + [ "$ICON" ] && printf "%s " "$ICON" + [ "$BAT_ICON" ] && printf "%s " "$BAT_ICON" + [ "$CAPACITY" ] && printf "%s%%" "$CAPACITY" +} + +Brightness() { + case "$KERNEL" in + Linux*) + BRIGHTNESS_CARD=$(ls /sys/class/backlight/ | head -n 1) + [ -d "$BRIGHTNESS_CARD" ] && BRIGHTNESS=$(($(cat "${BRIGHTNESS_CARD}/brightness") \ + * 100 / $(cat "${BRIGHTNESS_CARD}/max_brightness"))) + ;; + FreeBSD*) + BRIGHTNESS=$(backlight | cut -d ' ' -f 2) + ;; + OpenBSD*) + BRIGHTNESS=$(apm -l) + ;; + esac + if [ "$BRIGHTNESS" -le 25 ]; then + ICON="" + elif [ "$BRIGHTNESS" -le 60 ]; then + ICON="" + else + ICON="" + fi + [ "$BRIGHTNESS" ] && printf "%s %s%%" "$ICON" "$BRIGHTNESS" +} + +Volume() { + VOLUME=$(mixer vol | cut -d':' -f2) + case "$KERNEL" in + Linux*) + VOLUME=$(pactl get-sink-volume @DEFAULT_SOURCE@ | \ + awk '/%/{sub(/%/, "", $5);print $5}') + ;; + FreeBSD*) + VOLUME=$(mixer -s vol | cut -d ':' -f 2) + ;; + esac + if [ "$VOLUME" -le 25 ]; then + ICON="" + elif [ "$VOLUME" -le 60 ]; then + ICON="" + else + ICON="" + fi + [ "$VOLUME" ] && printf "%s %s%%" "$ICON" "$VOLUME" +} + +CPU() { + USAGE=$(ps aux | awk 'BEGIN {sum=0} {sum+=$3}; END {print sum}' | sed 's/\..*//') + case "$KERNEL" in + Linux) + USAGE=$((USAGE/$(grep -c "^processor" /proc/cpuinfo))) + ;; + esac + printf " %s%%" "$USAGE" +} + +CPUtemp() { + case "$KERNEL" in + Linux*) + TEMP=$(sensors | awk '/temp1/ {sub(/^\+/, "", $2);print $2}') + ;; + FreeBSD*) + TEMP=$(sysctl -n dev.cpu.0.temperature | sed 's/\..*//') + ;; + OpenBSD*) + TEMP=$(sysctl hw.sensors | \ + awk -F '=| degC' '/lm0.temp|cpu0.temp/ {print $2; exit}' | \ + sed 's/00/0/') + ;; + esac + printf " %s°C" "$TEMP" +} + +Uptime() { + case "$KERNEL" in + Linux) + SECS=$(cat /proc/uptime | sed 's/\ .*//g') + ;; + *BSD*) + SECS=$(($(date +%s)-$(sysctl -n kern.boottime | \ + cut -d ',' -f 1 | cut -d '=' -f 2))) + ;; + esac + D=$((SECS / 60 / 60 / 24)) + H=$((SECS / 60/ 60 % 24)) + M=$((SECS / 60 % 60)) + S=$((SECS % 60)) + [ "$D" = 0 ] || UPTIME="${UPTIME} ${D}d" + [ "$H" = 0 ] || UPTIME="${UPTIME} ${H}h" + [ "$M" = 0 ] || UPTIME="${UPTIME} ${M}m" + printf "%s" "$UPTIME" +} + +Memory() { + case "$KERNEL" in + Linux) + free=$(awk '/^MemFree/{free=$2} + /^Buffers/{buff=$2} + /^Cached/{cached=$2} + /^SReclaimable/{rec=$2} + /^MemTotal/{total=$2} + END{print (free+buff+cached+rec)}' /proc/meminfo) + total=$(awk '/^MemTotal/ {print $2}' /proc/meminfo) + ;; + FreeBSD*) + total=$(sysctl -n hw.physmem) + pagesize=$(sysctl -n hw.pagesize) + inactive=$(($(sysctl -n vm.stats.vm.v_inactive_count) * pagesize)) + unused=$(($(sysctl -n vm.stats.vm.v_free_count) * pagesize)) + cache=$(($(sysctl -n vm.stats.vm.v_cache_count) * pagesize)) + free=$((inactive+unused+cache)) + ;; + OpenBSD*) + total=$(sysctl -n hw.physmem) + free=$(vmstat | awk 'END {printf $5}') + ;; + esac + USAGE=$(((total-free)*100/total)) + printf " %s%%" "${USAGE%.*}" +} + +DTime() { + DAY=$(date +%d | sed -e 's/^0//g') + day_suffix() { + case "$DAY" in + 1|01|21|31) echo "st";; + 2|02|22) echo "nd";; + 3|03|23) echo "rd";; + *) echo "th";; + esac + } + printf " %s" "$(date "+$DAY$(day_suffix) %b %I:%M %p")" +} + +# ------------------ # +# --- Functions ---- # +# ------------------ # +darken_hex(){ + C=${1:-FFFFFF} + V=${2:-10} + if [ "$(printf '%s' "$C" | cut -c1-1)" = "#" ]; then + C=$(printf '%s' "$C" | cut -c2-8) + else + C=$1 + fi + R=$(printf '%s' "$C" | awk '{print substr($0, 0, 2)}') + G=$(printf '%s' "$C" | awk '{print substr($0, 3, 2)}') + B=$(printf '%s' "$C" | awk '{print substr($0, 5, 2)}') + R=$(printf '%d' 0x"$R") + G=$(printf '%d' 0x"$G") + B=$(printf '%d' 0x"$B") + R=$((R+V)) + G=$((G+V)) + B=$((B+V)) + if [ "$R" -lt 0 ]; then + R=0 + elif [ "$R" -gt 255 ]; then + R=255 + fi + if [ "$G" -lt 0 ]; then + G=0 + elif [ "$G" -gt 255 ]; then + G=255 + fi + if [ "$B" -lt 0 ]; then + B=0 + elif [ "$B" -gt 255 ]; then + B=255 + fi + printf "#%02X%02X%02X\n" "$R" "$G" "$B" +} +usage() { + printf "$0 [-m modules] [-M] [-h]\n" + exit 2 +} +stopbar() { + for pid in $(ps ax | grep "/bin/sh.*dwm-bar" | awk '{print $1}'); do + [ "$pid" = "$$" ] && continue + kill -9 "$pid" > /dev/null 2>&1 + wait + done +} +startbar() { + c=1 + while ! pgrep -x dwm >/dev/null; do + sleep 1; + c=$((c+1)) + [ "$c" = 10 ] && exit 2 + done + [ -r "$HOME/.cache/bar_modules" ] && mods_list=$(cat "$HOME/.cache/bar_modules") + mods_list=${mods_list:-Weather Keyboard Battery Brightness Volume CPU CPUtemp Uptime Memory DTime} + mods=${1:-$mods_list} + mods_count=$(echo "$mods" | wc -w) + c=1 + for mod in $mods; do + if [ "$COLORFUL" -eq 1 ]; then + XRDB=$(xrdb -query) + fgColor=$(printf "$XRDB" | awk "/color$c/ {print \$2;exit}") + bgcolor=$(printf "$XRDB" | awk "/background/ {print \$2;exit}") + bgcolor_off=$(((c-1)*$((40/$mods_count)))) + bgColor=$(darken_hex "$bgcolor" "-$bgcolor_off") + [ "$c" -eq 1 ] && bgColor=$bgcolor + [ "$c" -ge 8 ] && fgColor=$(echo "$XRDB" | awk "/color$((c+1))/ {print \$2;exit}") + if [ "$COLORFUL_BACKGROUND" -eq 1 ]; then + mod_prefix="^c$fgColor^^b$bgColor^ " + mod_suffix="" + mod_sep=" " + else + mod_prefix="^c$fgColor^ " + mod_suffix="" + mod_sep=" " + fi + else + mod_prefix=" " + mod_suffix="" + mod_sep=" |" + #mod_prefix=" [ " + #mod_suffix=" ]" + #mod_sep="" + fi + if [ "$c" = 1 ]; then + output="$mod_prefix%$mod%$mod_suffix" + else + output="$output$mod_sep$mod_prefix%$mod%$mod_suffix" + fi + c=$((c+1)) + done + output="$output " + while true; do + unset out + out=$output + for mod in $mods; do + unset mod_output + mod_output=$($mod) + [ -z "$mod_output" ] && continue + out=$(printf "%s" "${out}" | sed "s/%$mod%/$mod_output/g") + done + dwm -s "$out" + sleep 1 + done +} + +main() { + while getopts "m:M" flag; do + case "${flag}" in + M) + full_text="[All Modules]" + full="Weather Keyboard Battery Brightness Volume CPU CPUtemp Uptime Memory DTime" + rest="[Restart Modules]" + cust="[Custom Modules]" + opts=" + Volume CPU Memory DTime + Volume CPU CPUtemp Uptime DTime + Keyboard Battery Brightness DTime + Weather Battery Brightness DTime + Weather Keyboard Battery Brightness DTime + " + opts=$(printf "%s" "${opts}" | sed 's/^[ \t]*//g;/^ *$/d') + choice=$(printf "%s\n" "${full_text}" "${rest}" "${cust}" "${opts}" | dmenu -i -l 20) + [ -z "$choice" ] && choice=$(cat $HOME/.cache/bar_modules) + case "$choice" in + "$cust") + HEIGHT=$(($(echo "$full" | wc -w)+2)) + WIDTH=$(($(echo "$full" | tr ' ' '\n' | wc -L)*2)) + [ "$WIDTH" -lt 30 ] && WIDTH="30" + "$TERMINAL" -c "st-float" -g "${WIDTH}x${HEIGHT}+400+150" \ + -e sh -c "echo \"$full\" | tr ' ' '\n' | smenu -m \"Select Modules:\" -l -P -n 100 -q | tr '\n' ' ' > $HOME/.cache/bar_modules.tmp" + mods=$(cat "$HOME/.cache/bar_modules.tmp") + [ -z "$mods" ] && mods=$(cat "$HOME/.cache/bar_modules") + rm "$HOME/.cache/bar_modules.tmp" + ;; + "$rest") + mods=$(cat $HOME/.cache/bar_modules) + ;; + "$full_text") + mods=$full + ;; + *) + mods=$choice + ;; + esac + echo "$mods" > "$HOME/.cache/bar_modules" + ;; + m) + mods=${OPTARG} + echo "$mods" > "$HOME/.cache/bar_modules" + ;; + *) usage ;; + esac + done + stopbar + startbar "$mods" & +} + +main "$@" diff --git a/.local/bin/email b/.local/bin/email @@ -0,0 +1,38 @@ +#!/bin/sh +# Easy Mail +MBSYNCRC="${MBSYNCRC:-${XDG_CONFIG_HOME:-$HOME/.config}/mbsync/mbsyncrc}" +MBSYNC_ACCS="${XDG_DATA_HOME:-$HOME/.local/share}/mail" +sync_mail() { + mbsync -c "$MBSYNCRC" -a + for ACC in $MBSYNC_ACCS/*; do + LAST_RUN="$ACC/.sync_mail.lastrun" + NEW_MAILS="$(find \ + "$ACC/INBOX/new" \ + "$ACC/Inbox/new" \ + "$ACC/inbox/new" \ + -type f -newer "$LAST_RUN" 2>/dev/null | wc -l | sed 's/ //g')" + if [ "$NEW_MAILS" -ge 1 ]; then + [ "$NEW_MAILS" -gt 1 ] && SUF="s" || SUF="" + ACC_SHOW="${ACC##*/}" + merbe " New Mail" "You have ${NEW_MAILS} new mail${SUF} in '${ACC_SHOW}'." & + fi + touch "$LAST_RUN" + done +} + +case "$1" in + -n) + sync_mail + ;; + -s) + while :; do + sync_mail + sleep 3600 + done + ;; + *) + sync_mail + mutt + sync_mail + ;; +esac diff --git a/.local/bin/ix b/.local/bin/ix @@ -0,0 +1,29 @@ +#!/bin/sh + +# Examples: +# ix hello.txt # paste file (name/ext will be set). +# echo Hello world. | ix # read from STDIN (won't set name/ext). +# ix -n 1 self_destruct.txt # paste will be deleted after one read. +# ix -i ID hello.txt # replace ID, if you have permission. +# ix -d ID + +ix() { + while getopts ":hd:i:n:" x; do + case $x in + h) echo "ix [-d ID] [-i ID] [-n N] [opts]"; return;; + d) $echo curl $opts -X DELETE ix.io/$OPTARG; return;; + i) opts="$opts -X PUT"; local id="$OPTARG";; + n) opts="$opts -F read:1=$OPTARG";; + esac + done + if [ -t 0 ]; then + if [ -f "$1" ]; then + curl $opts -F f:1=@"$1" $* ix.io/$id + return + fi + echo "^C to cancel, ^D to send." + fi + curl $opts -F f:1='<-' $* ix.io/$id +} + +ix $* diff --git a/.local/bin/lock b/.local/bin/lock @@ -0,0 +1,10 @@ +#!/bin/sh +dunstctl set-paused true +pidof -x mpd >/dev/null 2>&1 && mpc -q pause +if pidof -x mpv >/dev/null 2>&1; then + find "/tmp/mpvSockets" -type s | while read -r i; do + echo "set pause yes" | socat - "$i" + done +fi +slock +dunstctl set-paused false diff --git a/.local/bin/media-controller b/.local/bin/media-controller @@ -0,0 +1,92 @@ +#!/bin/sh +# TODO: REWRITE THIS +dunstify "FIX THIS" "$0" +exit $? + +VIDEO_PLAYER="mpv" +MUSIC_PLAYER="mpd" +[ "$CURRENT_PLAYER" ] || CURRENT_PLAYER="$(pgrep -f "$VIDEO_PLAYER" > /dev/null && echo "$VIDEO_PLAYER" || echo "$MUSIC_PLAYER")" + +if [[ "$CURRENT_PLAYER" = "mpd" ]]; then + prev="mpc -q prev" + next="mpc -q next" + stop="mpc -q stop" + togg="mpc -q toggle" + skfw="mpc -q seek +5" + skbw="mpc -q seek -5" + stat="mpc status" + titl="mpc --format '[%title%|%file%]' current" + +elif [[ "$CURRENT_PLAYER" = "mpv" ]]; then + LAST_MPV_SOCKET="$(find /tmp/mpvSockets -type s -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" ")" + next="echo 'playlist-next' | socat - ${LAST_MPV_SOCKET}" + prev="echo 'playlist-prev' | socat - ${LAST_MPV_SOCKET}" + stop="echo 'stop' | socat - ${LAST_MPV_SOCKET}" + togg="echo 'cycle pause' | socat - ${LAST_MPV_SOCKET}" + skfw="echo 'seek +5' | socat - ${LAST_MPV_SOCKET}" + skbw="echo 'seek -5' | socat - ${LAST_MPV_SOCKET}" + stat="echo \"{ \\\"command\\\": [\\\"get_property\\\", \\\"core-idle\\\"] }\" | socat - \"$LAST_MPV_SOCKET\" | grep -Eiq '\"data\":false' && echo \"Playing\" || echo \"Paused\"" + titl="echo \"{ \\\"command\\\": [\\\"get_property\\\", \\\"media-title\\\"] }\" | socat - \"$LAST_MPV_SOCKET\" | sed 's/{.*data\":\"*\(.*\)\",\"*.*}/\1/'" + +elif [[ "$CURRENT_PLAYER" = "spotify" ]]; then + prev="playerctl -p spotify previous" + next="playerctl -p spotify next" + stop="playerctl -p spotify stop" + togg="playerctl -p spotify play-pause" + skfw="playerctl -p spotify position 5+" + skbw="playerctl -p spotify position 5-" + stat="playerctl -p spotify status" + titl="playerctl -p spotify metadata -f '{{title}}'" +else + prev="" togg="" stop="" next="" stat="" + titl="There's no $MUSIC_PLAYER or $VIDEO_PLAYER installed" +fi + +case ${1} in + pause-all) + find "/tmp/mpvSockets" -type s | while read -r i; do echo "set pause yes" | socat - "$i"; done + playerctl -p spotify pause + mpc -q pause + ;; + icon) if [[ "$(eval $stat)" = *"laying"* ]]; then + exec echo "" + else + exec echo "" + fi + ;; + seek-bwd) eval "$skbw" + ;; + prev) eval "$prev"; + dunstify -u low -r 100003 -t 2000 -i "player_rew" "Media Controller" "Playing previous: $(eval $titl)" + ;; + toggle) eval "$togg"; + if [[ "$(eval $stat)" =~ "laying" ]]; then + dunstify -u low -r 100003 -t 2000 -i "player_play" "Media Controller" "Playing: $(eval $titl)" + else + dunstify -u low -r 100003 -t 2000 -i "player_pause" "Media Controller" "Paused: $(eval $titl)" + fi + ;; + stop) eval "$stop"; + ;; + next) eval "$next"; + dunstify -u low -r 100003 -t 2000 -i "player_fwd" "Media Controller" "Playing next: $(eval $titl)" + ;; + seek-fwd) eval "$skfw" + ;; + status) eval "$stat" + ;; + title) eval "$titl" + ;; + switchpl) if [[ "$(eval $stat)" = *"laying"* ]]; then + eval "$togg" + fi + if [[ "$CURRENT_MUSICPL" != "mpd" ]]; then + sed -i '/musicpl=/s/".*"/"mpd"/' "$DEFAPPS_FILE" + elif [[ "$CURRENT_MUSICPL" != "spotify" ]]; then + sed -i '/musicpl=/s/".*"/"spotify"/' "$DEFAPPS_FILE" + fi + dunstify -u low -r 100003 -t 2000 -i "$NOTIF_MUSIC_ICON" "Media Controller" "<span size='small'><u>$("$DEFAPPS_EXEC" -g musicpl)</u></span>\nSuccessfully set as default" + ;; +esac + +exit $? diff --git a/.local/bin/metch b/.local/bin/metch @@ -0,0 +1,89 @@ +#!/bin/sh + +# Import info +. /etc/os-release + +# Get info functions +Name() { + read -r host < /etc/hostname + printf "%s@%s" "$USER" "$host" +} +Os() { + printf "%s" "$NAME" +} +Kernel() { + read -r _ _ kern _ < /proc/version + kern="$(printf '%s' "$kern" | sed 's|-.*||')" + printf "%s" "$kern" +} +Uptime() { + IFS=. read -r up _ < /proc/uptime + DAYS="$((up/60/60/24))" + HOURS="$((up/60/60%24))" + MINS="$((up/60%60))" + SECS="$((up%60))" + if [ "$DAYS" -gt 0 ]; then + printf "%dD %dH %dM" "$DAYS" "$HOURS" "$MINS" + elif [ "$HOURS" -gt 0 ]; then + printf "%dH %dM" "$HOURS" "$MINS" + elif [ "$MINS" -gt 0 ]; then + printf "%dM" "$MINS" + else + printf "%dS" "$SECS" + fi +} +Shell() { + printf "%s" "${SHELL##*/}" +} +Desktop() { + if [ "$DESKTOP_SESSION" != "" ]; then + printf "%s\n" "$DESKTOP_SESSION" + elif [ "$XDG_CURRENT_DESKTOP" != "" ]; then + printf "%s\n" "$XDG_CURRENT_DESKTOP" + elif [ "$DISPLAY" != "" ]; then + id="$(xprop -root -notype | awk '$1=="_NET_SUPPORTING_WM_CHECK:"{print $5}')" + xprop -id "${id}" -notype -f _NET_WM_NAME 8t | grep "_NET_WM_NAME = " | \ + cut -d ' ' -f3 | cut -d '"' -f 2 + else + printf "%s\n" "Unknown" + fi +} +Memory() { + mem_total="$(awk '/MemTotal/ {print $2}' /proc/meminfo)" + mem_used="$(awk '/MemFree/{free=$2} /Buffers/{buff=$2} /^Cached/{cached=$2} /SReclaimable/{rec=$2} /MemTotal/{total=$2} END{print (total-free-buff-cached-rec)}' /proc/meminfo)" + printf "%dMiB / %dMiB" "$((mem_used/1024))" "$((mem_total/1024))" +} + +printf '\033[1;35m%s\033[0m' " _____ " +printf '\033[34m OS\033[0m \033[35m~\033[0m %s\n' "$(Os)" +printf '\033[1;35m%s\033[0m' " .' \`. " +printf '\033[34m Shell\033[0m \033[35m~\033[0m %s\n' "$(Shell)" +printf '\033[1;35m%s\033[0m' " / .-=-. \ \ __ " +printf '\033[34m DE/WM\033[0m \033[35m~\033[0m %s\n' "$(Desktop)" +printf '\033[1;35m%s\033[0m' " | ( C\ \ \_.'') " +printf '\033[34m Kernel\033[0m \033[35m~\033[0m %s\n' "$(Kernel)" +printf '\033[1;35m%s\033[0m' " _\ \`--' |,' _/ " +printf '\033[34m Uptime\033[0m \033[35m~\033[0m %s\n' "$(Uptime)" +printf '\033[1;35m%s\033[0m' "/__\`.____.'__.-' " +printf '\033[34m Memory\033[0m \033[35m~\033[0m %s\n' "$(Memory)" +printf '\t\t\t' +for i in 0 1 2 3 4 5 6 7; do + printf '\033[3%sm%s\033[0m' "$i" "  " +done +printf '\n\t\t\t' +for i in 0 1 2 3 4 5 6 7; do + printf '\033[1;9%sm%s\033[0m' "$i" "  " +done +printf '\n' + +#printf "%s _____ %sOs:%s\t%s\n" "$(c 1 97)" "$(c 0 31)" "$(c 1 91)" "$(Os)$(c 0 0)" +#printf "%s .' \`. %sKernel:%s\t%s\n" "$(c 1 97)" "$(c 0 32)" "$(c 1 92)" "$(Kernel)$(c 0 0)" +#printf "%s / .-=-. \ \ __ %sUptime:%s\t%s\n" "$(c 1 97)" "$(c 0 33)" "$(c 1 93)" "$(Uptime)$(c 0 0)" +#printf "%s | ( C\ \ \_.'') %sShell:%s\t%s\n" "$(c 1 97)" "$(c 0 34)" "$(c 1 94)" "$(Shell)$(c 0 0)" +#printf "%s _\ \`--' |,' _/ %sDE/WM:%s\t%s\n" "$(c 1 97)" "$(c 0 35)" "$(c 1 95)" "$(Desktop)$(c 0 0)" +#printf "%s/__\`.____.'__.-' %sMemory:%s\t%s\n" "$(c 1 97)" "$(c 0 36)" "$(c 1 96)" "$(Memory)$(c 0 0)" +#printf "\n" +#printf "\t\t\t$(c 0 30)● $(c 0 0) $(c 0 31)● $(c 0 0) $(c 0 32)● $(c 0 0) $(c 0 33)● $(c 0 0) $(c 0 34)● $(c 0 0) $(c 0 35)● $(c 0 0) $(c 0 36)● $(c 0 0) $(c 0 37)● $(c 0 0)" +#printf "\n" +#printf "\t\t\t$(c 1 90)● $(c 0 0) $(c 1 91)● $(c 0 0) $(c 1 92)● $(c 0 0) $(c 1 93)● $(c 0 0) $(c 1 94)● $(c 0 0) $(c 1 95)● $(c 0 0) $(c 1 96)● $(c 0 0) $(c 1 97)● $(c 0 0)" +#[ "$1" = "eof" ] || printf "\n" diff --git a/.local/bin/pacman-rm b/.local/bin/pacman-rm @@ -0,0 +1,6 @@ +#!/bin/sh +alias fzf="fzf -i -m -e --layout=reverse --border=sharp --inline-info --cycle --preview=\"pacman --color=always -Si {3}\" --bind 'Ctrl-p:toggle-preview+toggle-preview' --bind='Ctrl-a:toggle-all'" +packages="$(pacman -Qi | awk '/^Name/{name=$3} /^Installed Size/{print $4$5, name}' | sort -hr | tr ' ' '\t' | sed -e "s/MiB/ MiB/g" -e "s/KiB/ KiB/g")" +pkgs="$(printf "%s" "$packages" | fzf | awk '{print $3}' | tr '\n' ' ')" + +[ "$pkgs" ] && doas pacman -Rcusn $pkgs diff --git a/.local/bin/pacman-up b/.local/bin/pacman-up @@ -0,0 +1,34 @@ +#!/bin/sh +notif() { + merbe " Updater" "$1" & +} +notifnq() { + TEXT="${1}" + [ "$TEXT" ] || TEXT="Didn't update anything." + notif "$TEXT" + exit 2 +} + +doas-askpass pacman -Sy || notifnq +PKG_LIST="$(pacman -Su --print-format "%r/%n %s" | sort -r -n -k 2)" + +[ -z "$PKG_LIST" ] && notifnq "System is up-to-date." && rm ~/.cache/pkg_updates + +PKG_LIST_H="$(printf '%s\n' "$PKG_LIST" | awk '{printf("%s %.1fMiB\n",$1,$2/1024/1024)}')" +PKG_COUNT="$(printf '%s\n' "$PKG_LIST" | wc -l)" +PKG_SIZE="$(printf '%s\n' "$PKG_LIST" | awk '{SUM+=$2} END {printf("%.1fMiB",SUM/1024/1024)}')" + +[ "$PKG_COUNT" -gt 1 ] && SUFFIX="s" +merbe "$(printf "Packages:\n$PKG_LIST_H" | head)" & +CHOICE="$(printf '%s\n' "Yes" "No" | dmenu -p "Update $PKG_COUNT Package$SUFFIX ($PKG_SIZE)?")" +case "$CHOICE" in + [Yy][Ee][Ss]|[Yy]) + notif "Updating $PKG_COUNT Package$SUFFIX..." + "$TERMINAL" -c "st-float" -g "120x26" -e sh -c "doas pacman -Syu --noconfirm || (merbe \" Updater\" \"Didn't update anything.\" && exit 2)" + rm ~/.cache/pkg_updates + notifnq "Updated $PKG_COUNT Package$SUFFIX." + ;; + *) + notifnq + ;; +esac diff --git a/.local/bin/screenshot b/.local/bin/screenshot @@ -0,0 +1,47 @@ +#!/bin/sh +TIMER=0 +ACTIVE=0 +SELECT=0 +QUALITY=5 +COPY_SS=0 +SAVE_SS=0 +NAME_SS="$(date '+%Y%m%d-%H%M%S').png" +SAVE_SS_DIR="$HOME/pics" + +while getopts :wscxt:q:n:p: flag; do + case "${flag}" in + w) ACTIVE=1;; + s) SELECT=1;; + c) COPY_SS=1;; + x) SAVE_SS=1;; + t) TIMER=${OPTARG};; + q) QUALITY=${OPTARG};; + n) NAME_SS=${OPTARG};; + p) SAVE_SS_DIR=${OPTARG};; + *) echo "usage: $0 [-wxsc] [-t time(s)] [-q quality(1-10)] [-n name.png] [-p path/to/picture]"; exit 2 ;; + esac +done + +[ $SAVE_SS -eq 0 ] && [ $COPY_SS -eq 0 ] && COPY_SS=1 +[ $SAVE_SS -eq 1 ] && [ ! -d "${SAVE_SS_DIR}" ] && mkdir -p "${SAVE_SS_DIR}" +if [ $SELECT -eq 1 ]; then + TAGS="-s" +elif [ $ACTIVE -eq 1 ]; then + TAGS="-i $(xdotool getactivewindow)" +fi + +sleep "$TIMER" + +maim $TAGS -m "$QUALITY" "${SAVE_SS_DIR}/${NAME_SS}" || exit 2 + +if [ $SAVE_SS -eq 1 ] && [ $COPY_SS -eq 1 ]; then + xclip -selection clipboard -target image/png -i "${SAVE_SS_DIR}/${NAME_SS}" + SHOW="$(echo "${SAVE_SS_DIR}" | sed -e "s|${HOME}|~|g")/${NAME_SS} (+CLIPBOARD)" +elif [ $SAVE_SS -eq 0 ] && [ $COPY_SS -eq 1 ]; then + rm "${SAVE_SS_DIR}/${NAME_SS}" + SHOW="CLIPBOARD" +elif [ $SAVE_SS -eq 1 ] && [ $COPY_SS -eq 0 ]; then + SHOW="$(echo "${SAVE_SS_DIR}" | sed -e "s|${HOME}|~|g")/${NAME_SS}" +fi + +merbe " Picture acquired!" "${SHOW}" diff --git a/.local/bin/theme-sel b/.local/bin/theme-sel @@ -0,0 +1,138 @@ +#!/bin/sh +OLDTHEME="$(cat "$HOME"/.cache/theme || echo "nord")" +XRES="${XRES:-${XDG_CONFIG_HOME:-$HOME/.config}/x11}" +XRES_SRC="${XRES}/xresources" +XRES_COLORS_DST="${XRES}/colors" +XRES_COLORS_SRC="${XRES}/themes" + +find_themes() { + find "${XRES_COLORS_SRC}" -type f -exec basename {} \; | sort +} + +generate_theme() { + SRC="$1" + DST="$2" + [ -f "${DST}.tmp" ] && rm "${DST}.tmp" + cp "${SRC}" "${DST}.tmp" + + XRDB="$(xrdb -query)" + background="$(printf '%s\n' "$XRDB" | awk '/background/ {print $2;exit}')" + foreground="$(printf '%s\n' "$XRDB" | awk '/foreground/ {print $2;exit}')" + cursorColor="$(printf '%s\n' "$XRDB" | awk '/cursorColor/ {print $2;exit}')" + + sed -i "" "s|%clfg%|$foreground|g" "${DST}.tmp" + sed -i "" "s|%clbg%|$background|g" "${DST}.tmp" + sed -i "" "s|%clcr%|$cursorcolor|g" "${DST}.tmp" + sed -i "" "s|%HOME%|$HOME|g" "${DST}.tmp" + + for i in $(seq 0 15); do + v="$(echo "$XRDB" | awk "/color$i/ {print \$2;exit}")" + sed -i "" "s|%cl${i}%|$v|g" "${DST}.tmp" + done + + [ -f "${DST}" ] && rm "${DST}" + mv "${DST}.tmp" "${DST}" +} + +apply_theme() { + THEME="$1" + XRES_COLORS_SRC="${XRES}/themes/$THEME" + cp -f "${XRES_COLORS_SRC}" "${XRES_COLORS_DST}" + xrdb "${XRES_SRC}" + generate_theme "${HOME}/.config/surf/styles/default.css.in" "${HOME}/.config/surf/styles/default.css" + generate_theme "${HOME}/.config/zathura/zathurarc.in" "${HOME}/.config/zathura/zathurarc" + echo "$THEME" > "$HOME"/.cache/theme +} + +reload_theme() { + pidof -x tabbed >/dev/null 2>&1 && for PID in $(pidof tabbed); do kill -s USR1 "$PID"; done + pidof -x st >/dev/null 2>&1 && for PID in $(pidof st); do kill -s USR1 "$PID"; done + # Remove urgency mark for st, tabbed instances: + xdotool search --class st set_window --urgency 0 "%@" + xdotool search --class tabbed set_window --urgency 0 "%@" + pidof -x dwm >/dev/null 2>&1 && xdotool key "Super+F5" + #pidof -x bspwm && bspc wm -r + #pidof -x openbox && openbox --restart + setsid -f dwm-bar + + case "$OLDTHEME" in + "${THEME}") NOTIF_TEXT="Reloaded ${THEME} theme." ;; + *) NOTIF_TEXT="Set the theme from ${OLDTHEME} to ${THEME}!" ;; + esac + pkill -SIGUSR1 merbe + merbe " Theme Selector" "$NOTIF_TEXT" & + #dunstify -t 10000 -h string:x-dunst-stack-tag:theme "Set Theme" "$NOTIF_TEXT" +} + +case "$1" in + -l) + find_themes + exit + ;; + -x) + THEME="$(find_themes | shuf -n 1)" + THEME="${THEME%% *}" + [ "$THEME" ] || exit + ;; + -s) + THEME="$(find_themes | sed "s/$OLDTHEME/$OLDTHEME */g" | dmenu -i -p "Set Theme:")" + THEME="${THEME%% *}" + [ "$THEME" ] || exit + ;; + *) + THEME="${1:-$(cat "$HOME"/.cache/theme || echo "nord")}" + ;; +esac +apply_theme "$THEME" +if [ "$DISPLAY" ]; then + #bg-set + bg-gen + reload_theme +fi + +# Old: +apply_theme_gtk() { + # Maps for themes + [ -d "$HOME/.themes" ] \ + && THEME_SEARCH+="$HOME/.themes " + [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/themes" ] \ + && THEME_SEARCH+="${XDG_DATA_HOME:-$HOME/.local/share}/themes " + [ -d "/usr/share/themes" ] \ + && THEME_SEARCH+="/usr/share/themes " + [ -d "/usr/local/share/themes" ] \ + && THEME_SEARCH+="/usr/local/share/themes " + GTK_THEME="$(find $THEME_SEARCH -type d -iname "*${THEME}*" | head -1)" + [ -n "$GTK_THEME" ] && GTK_THEME="$(basename $GTK_THEME)" + + [ -d "$HOME/.icons" ] \ + && ICONS_SEARCH+="$HOME/.icons " + [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/icons" ] \ + && ICONS_SEARCH+="${XDG_DATA_HOME:-$HOME/.local/share}/icons " + [ -d "/usr/share/icons" ] \ + && ICONS_SEARCH+="/usr/share/icons" + [ -d "/usr/local/share/icons" ] \ + && ICONS_SEARCH+="/usr/local/share/icons" + GTK_ICONS="$(find $ICONS_SEARCH -type d -iname "*${THEME}*" | head -1)" + [ -n "$GTK_ICONES" ] && GTK_ICONS="$(basename $GTK_ICONS)" + + _get_ini(){ awk '/\[/{prefix=$0; next} $1{print prefix $0}' "$1" | grep "$2" | sed 's/.*=[ "]//'; } + THEMES_MAPS="${XDG_CONFIG_HOME:-$HOME/.config}/themes.ini" + #GTK_THEME="$(_get_ini "$THEMES_MAPS" "\[${THEME}\]GTK_THEME")" + #GTK_ICONS="$(_get_ini "$THEMES_MAPS" "\[${THEME}\]GTK_ICONS")" + GTK_THEME="${GTK_THEME:-Adwaita-dark}" + GTK_ICONS="${GTK_THEME:-Adwaita}" + + # set gtk theme, icons and cursor + if [ "$(pidof xsettingsd)" ]; then + sed -i -e "s|Net/ThemeName .*|Net/ThemeName \"${GTK_THEME}\"|g" "${HOME}/.config/xsettingsd/xsettingsd.conf" + sed -i -e "s|Net/IconThemeName .*|Net/IconThemeName \"${GTK_ICONS}\"|g" "${HOME}/.config/xsettingsd/xsettingsd.conf" + sed -i -e "s|Gtk/CursorThemeName .*|Gtk/CursorThemeName \"${THEME}\"|g" "${HOME}/.config/xsettingsd/xsettingsd.conf" + else + sed -i -e "s/gtk-theme-name=.*/gtk-theme-name=\"${GTK_THEME}\"/g" "${HOME}/.gtkrc-2.0" + sed -i -e "s/gtk-icon-theme-name=.*/gtk-icon-theme-name=\"${GTK_ICONS}\"/g" "${HOME}/.gtkrc-2.0" + sed -i -e "s/gtk-cursor-theme-name=.*/gtk-cursor-theme-name=\"${THEME}\"/g" "${HOME}/.gtkrc-2.0" + sed -i -e "s/gtk-theme-name=.*/gtk-theme-name=${GTK_THEME}/g" "${CFG}/gtk-3.0/settings.ini" + sed -i -e "s/gtk-icon-theme-name=.*/gtk-icon-theme-name=${GTK_ICONS}/g" "${CFG}/gtk-3.0/settings.ini" + sed -i -e "s/gtk-cursor-theme-name=.*/gtk-cursor-theme-name=${THEME}/g" "${CFG}/gtk-3.0/settings.ini" + fi +} diff --git a/.local/bin/toggle-touch b/.local/bin/toggle-touch @@ -0,0 +1,16 @@ +#!/bin/sh +# Toggle touchpad between enabled and disabled. +TOUCHPAD_ID="$(xinput list | grep -Eo '(Touchpad|Synaptics).*id=[0-9]*' | sed -e "s|.*id=||")" +TOUCHPAD_MODE="$(echo "$TOUCHPAD_ID" | xargs -I % xinput --list-props % | grep "Device Enabled.*:.*[0|1]" | sed -e 's|.*: *||')" + +if [ "$TOUCHPAD_MODE" -eq "1" ]; then + xinput set-prop "$TOUCHPAD_ID" "Device Enabled" 0 + echo "Device disabled." + dunstify -h string:x-dunst-stack-tag:touchpad-toggle -t 700 \ + -i "touchpad-disabled-symbolic" "Touchpad" "Touchpad has been disabled" +else + xinput set-prop "$TOUCHPAD_ID" "Device Enabled" 1 + echo "Device enabled." + dunstify -h string:x-dunst-stack-tag:touchpad-toggle -t 700 \ + -i "touchpad-enabled-symbolic" "Touchpad" "Touchpad has been enabled" +fi diff --git a/.local/bin/upload b/.local/bin/upload @@ -0,0 +1,34 @@ +#!/bin/sh +# Upload files using `transfer.sh`. +if [ "$#" -eq 0 ]; then + filename="$(basename "$0")" + printf "No arguments specified.\nUsage:\n %s <file|directory>\n ... | %s <file_name>\n" "$filename" "$filename" + exit 2 +fi + +if tty -s; then + file="$1" + file_name=$(basename "$file") + if [ ! -e "$file" ]; then + echo "$file: No such file or directory">&2 + exit 2 + fi + if [ -d "$file" ]; then + file_name="$file.zip" + tree -C --noreport "$file" + printf "\nAre you sure you want to upload the %s (as %s) directory? [y/N] " "$file" "$file_name" + read -r ASK; case "$ASK" in + [Yy][Ee][Ss]|[Yy]) (cd "$file"&&zip -r -q - .) | curl --progress-bar --upload-file "-" "https://transfer.sh/$file_name" | tee /dev/null ;; + *) exit 2 ;; + esac + else + printf "Are you sure you want to upload %s? [y/N] " "$file_name" + read -r ASK; case "$ASK" in + [Yy][Ee][Ss]|[Yy]) curl --progress-bar --upload-file "$file" "https://transfer.sh/$file_name" | tee /dev/null ;; + *) exit 2 ;; + esac + fi +else + file_name="$1" + curl --progress-bar --upload-file "-" "https://transfer.sh/$file_name" | tee /dev/null +fi diff --git a/.local/bin/volume b/.local/bin/volume @@ -0,0 +1,127 @@ +#!/bin/sh +AUDIO_STEPS="5" +AUDIO_ACT="get" + +while getopts ':gidmGIDMs:' flag; do + case "${flag}" in + g) AUDIO_ACT="get" ;; + i) AUDIO_ACT="inc" ;; + d) AUDIO_ACT="dec" ;; + m) AUDIO_ACT="mute" ;; + G) AUDIO_ACT="mic-get" ;; + I) AUDIO_ACT="mic-inc" ;; + D) AUDIO_ACT="mic-dec" ;; + M) AUDIO_ACT="mic-mute" ;; + s) AUDIO_STEPS="${OPTARG}" ;; + *) + printf 'Usage: %s [-g] [-d] [-i] [-m] [-G] [-D] [-I] [-M] [-s audio steps (in %%)]\n' "$0" + printf ' -g: get volume\n' + printf ' -i: increase volume\n' + printf ' -d: decrease volume\n' + printf ' -m: mute volume\n' + printf ' -G: get mic volume\n' + printf ' -I: increase mic volume\n' + printf ' -D: decrease mic volume\n' + printf ' -M: mute mic volume\n' + exit 2 + ;; + esac +done + +vol() { + case "$(uname)" in + "Linux"*) + case "$1" in + get) pactl get-sink-volume @DEFAULT_SOURCE@ | awk '/%/{sub(/%/, "", $5);print $5}' ;; + inc) pactl set-sink-volume @DEFAULT_SINK@ "+$2%" ;; + dec) pactl set-sink-volume @DEFAULT_SINK@ "-$2%" ;; + mute) pactl set-sink-mute @DEFAULT_SINK@ toggle ;; + ismuted) pactl get-sink-mute @DEFAULT_SOURCE@ | grep -o 'yes' ;; + mic-get) pactl get-source-volume @DEFAULT_SOURCE@ | awk '/%/{sub(/%/, "", $5);print $5}' ;; + mic-inc) pactl set-source-volume @DEFAULT_SINK@ "+$2%" ;; + mic-dec) pactl set-source-volume @DEFAULT_SINK@ "-$2%" ;; + mic-mute) pactl set-source-mute @DEFAULT_SINK@ toggle ;; + mic-ismuted) pactl get-source-mute @DEFAULT_SOURCE@ | grep -o 'yes' ;; + esac + ;; + "FreeBSD"*) + case "$1" in + get) mixer -s vol | cut -d ':' -f 2 ;; + inc) mixer -s vol "+$2%" ;; + dec) mixer -s vol "-$2%" ;; + mute) [ "$(vol get)" -eq 0 ] && mixer -s vol 75 || mixer -s vol 0 ;; + ismuted) [ "$(vol get)" -eq 0 ] && echo yes ;; + mic-get) mixer -s mic | cut -d ':' -f 2 ;; + mic-inc) mixer -s mic "+$2%" ;; + mic-dec) mixer -s mic "-$2%" ;; + mic-mute) [ "$(vol mic-get)" -eq 0 ] && mixer -s mic 35 || mixer -s mic 0 ;; + mic-ismuted) [ "$(vol mic-get)" -eq 0 ] && echo yes ;; + esac + ;; + esac +} + +notify() { + case "$1" in + mic) VOLUME=$(vol mic-get) ; IS_MUTED=$(vol mic-ismuted) ;; + *) VOLUME=$(vol get) ; IS_MUTED=$(vol ismuted) ;; + esac + if [ "$IS_MUTED" ] || [ "$VOLUME" -eq 0 ]; then + VOLUME="Muted" + VOLUME_ICON="ﱝ" + elif [ "$VOLUME" -lt 30 ]; then + VOLUME_ICON="" + elif [ "$VOLUME" -lt 70 ]; then + VOLUME_ICON="" + else + VOLUME_ICON="" + fi + pkill -SIGUSR1 merbe + merbe "$VOLUME_ICON $VOLUME" & +} + +case "$AUDIO_ACT" in + inc|dec) + CURRENT_VOLUME="$(vol get)" + REMAINDER="$((CURRENT_VOLUME%AUDIO_STEPS))" + AUDIO_STEPS="$((AUDIO_STEPS-REMAINDER))" + ;; + mic-inc|mic-dec) + CURRENT_VOLUME="$(vol mic-get)" + REMAINDER="$((CURRENT_VOLUME%AUDIO_STEPS))" + AUDIO_STEPS="$((AUDIO_STEPS-REMAINDER))" + ;; +esac + +case "$AUDIO_ACT" in + get) + notify + ;; + inc) + vol inc "$AUDIO_STEPS" + notify + ;; + dec) + vol dec "$AUDIO_STEPS" + notify + ;; + mute) + vol mute + notify + ;; + mic-get) + notify "mic" + ;; + mic-inc) + vol mic-inc "$AUDIO_STEPS" + notify "mic" + ;; + mic-dec) + vol mic-dec "$AUDIO_STEPS" + notify "mic" + ;; + mic-mute) + vol mic-mute + notify "mic" + ;; +esac diff --git a/.local/bin/vpn b/.local/bin/vpn @@ -0,0 +1,11 @@ +#!/bin/sh +printf '\033[90m' +dhclient ue0 +echo "nameserver 1.1.1.1" > /etc/resolv.conf +for pid in $(ps ax | grep "openvpn" | awk '{print $1}'); do + [ "$pid" = "$$" ] && continue + kill -9 "$pid" > /dev/null 2>&1 + wait +done +openvpn /home/mahdi/Mahdi.ovpn +printf '\033[0m' diff --git a/.local/bin/webcam b/.local/bin/webcam @@ -0,0 +1,23 @@ +#!/bin/sh +WEBCAM_DRIVER="v4l2" +WEBCAM_DEVICE="/dev/video0" + +if [ ! -f "${WEBCAM_DEVICE}" ]; then + merbe "Webcam" "Install a webcam first!" & + exit 2 +fi + +case "$1" in + shot) + ffmpeg -y -loglevel quiet -f "$WEBCAM_DRIVER" -i "$WEBCAM_DEVICE" \ + -frames:v 1 -f image2 -strftime 1 "$HOME/webcam-%Y-%m-%d-%H%M%S.jpg" + ;; + *) + ps ax | grep "mpv*av://$WEBCAM_DRIVER:$WEBCAM_DEVICE*" | \ + awk '{print $1}' | while read PID; do kill -9 "$PID"; wait; done + merbe " Webcam" "$WEBCAM_DEVICE is open now." & + mpv "av://$WEBCAM_DRIVER:$WEBCAM_DEVICE" --title=webcam \ + --profile=low-latency --untimed --load-scripts=no --no-osc + merbe "﫞 Webcam" "$WEBCAM_DEVICE has been closed." & + ;; +esac diff --git a/.local/src/dmenu/LICENSE b/.local/src/dmenu/LICENSE @@ -0,0 +1,30 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe <[email protected]> +© 2006-2008 Sander van Dijk <[email protected]> +© 2006-2007 Michał Janeczek <[email protected]> +© 2007 Kris Maglione <[email protected]> +© 2009 Gottox <[email protected]> +© 2009 Markus Schnalke <[email protected]> +© 2009 Evan Gates <[email protected]> +© 2010-2012 Connor Lane Smith <[email protected]> +© 2014-2022 Hiltjo Posthuma <[email protected]> +© 2015-2019 Quentin Rameau <[email protected]> + +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/.local/src/dmenu/Makefile b/.local/src/dmenu/Makefile @@ -0,0 +1,64 @@ +# 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: options dmenu stest + +options: + @echo dmenu build options: + @echo "CFLAGS = $(CFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "CC = $(CC)" + +.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 options clean dist install uninstall diff --git a/.local/src/dmenu/README b/.local/src/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/.local/src/dmenu/arg.h b/.local/src/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/.local/src/dmenu/config.h b/.local/src/dmenu/config.h @@ -0,0 +1,60 @@ +/* See LICENSE file for copyright and license details. */ +static char font[] = "monospace:size=10"; /* -fn option overrides fonts[0]; default font */ +static const char *fonts[] = { + font, + "Vazir:size=10", + "emoji:size=10", +}; + +static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static unsigned int border_width= 2; /* -bw option; size of the window border */ +static char *prompt = NULL; /* -p option; prompt to the left of input field */ +static unsigned int preselected = 0; /* -n option; preselected item starting from 0 */ +static unsigned int lines = 0; /* -l option; if nonzero dmenu draws vertical list */ +static const unsigned int alpha = 0xf0; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; + +static char normfgcolor[] = "#ECEFF4"; +static char normbgcolor[] = "#3B4252"; +static char normhlcolor[] = "#EBCB8B"; +static char selfgcolor[] = "#EBCB8B"; +static char selbgcolor[] = "#4C566A"; +static char selhlcolor[] = "#E5E9F0"; +static char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { normfgcolor, normbgcolor }, + [SchemeSel] = { selfgcolor, selbgcolor }, + [SchemeNormHighlight] = { normhlcolor, normbgcolor }, + [SchemeSelHighlight] = { selhlcolor, selbgcolor }, + [SchemeOut] = { "#000000", "#00ffff" }, + [SchemeOutHighlight] = { normhlcolor, "#00ffff" }, +}; + +static const unsigned int alphas[SchemeLast][2] = { + [SchemeNorm] = { OPAQUE, alpha }, + [SchemeSel] = { OPAQUE, alpha }, + [SchemeOut] = { OPAQUE, alpha }, + [SchemeNormHighlight] = { OPAQUE, alpha }, + [SchemeSelHighlight] = { OPAQUE, alpha }, + [SchemeOutHighlight] = { OPAQUE, alpha }, +}; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "font", STRING, &font }, + { "color12", STRING, &normfgcolor }, + { "color0", STRING, &normbgcolor }, + { "color11", STRING, &normhlcolor }, + { "color0", STRING, &selfgcolor }, + { "color12", STRING, &selbgcolor }, + { "color8", STRING, &selhlcolor }, + { "prompt", STRING, &prompt }, +}; + diff --git a/.local/src/dmenu/config.mk b/.local/src/dmenu/config.mk @@ -0,0 +1,35 @@ +# dmenu version +VERSION = 5.1 + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/local/include +X11LIB = /usr/local/lib + +BDINC = /usr/local/include/fribidi + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/local/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = $(X11INC)/freetype2 + +BDLIBS = -lfribidi + +# includes and libs +INCS = -I$(X11INC) -I$(FREETYPEINC) -I$(BDINC) +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) $(BDLIBS) -lXrender + +# 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/.local/src/dmenu/dmenu b/.local/src/dmenu/dmenu Binary files differ. diff --git a/.local/src/dmenu/dmenu.1 b/.local/src/dmenu/dmenu.1 @@ -0,0 +1,202 @@ +.TH DMENU 1 dmenu\-VERSION +.SH NAME +dmenu \- dynamic menu +.SH SYNOPSIS +.B dmenu +.RB [ \-bfivP ] +.RB [ \-l +.IR lines ] +.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 ] +.RB [ \-n +.IR number ] +.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 +.B \-P +dmenu will not directly display the keyboard input, but instead replace it with dots. All data from stdin will be ignored. +.TP +.BI \-l " lines" +dmenu lists items vertically, with the given number of lines. +.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. +.TP +.BI \-n " number" +preseslected item starting from 0. +.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/.local/src/dmenu/dmenu.c b/.local/src/dmenu/dmenu.c @@ -0,0 +1,1011 @@ +/* See LICENSE file for copyright and license details. */ +#include <ctype.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <time.h> +#include <unistd.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> +#include <X11/Xresource.h> +#ifdef XINERAMA +#include <X11/extensions/Xinerama.h> +#endif +#include <X11/Xft/Xft.h> + +#include <fribidi.h> + +#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 LENGTH(X) (sizeof X / sizeof X[0]) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +#define OPAQUE 0xffU + +/* enums */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeNormHighlight, SchemeSelHighlight, SchemeOutHighlight, SchemeLast }; /* color schemes */ +struct item { + char *text; + struct item *left, *right; + int out; +}; + +static char text[BUFSIZ] = ""; +static char fribidi_text[BUFSIZ] = ""; +static char *embed; +static int bh, mw, mh; +static int inputw = 0, promptw, passwd = 0; +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]; + +/* Xresources preferences */ +enum resource_type { + STRING = 0, + INTEGER = 1, + FLOAT = 2 +}; +typedef struct { + char *name; + enum resource_type type; + void *dst; +} ResourcePref; + +static void load_xresources(void); +static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); + +static int useargb = 0; +static Visual *visual; +static int depth; +static Colormap cmap; + +#include "config.h" + +static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +static char *(*fstrstr)(const char *, const char *) = strstr; +static void xinitvisual(); + +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 void +drawhighlights(struct item *item, int x, int y, int maxw) +{ + char restorechar, tokens[sizeof text], *highlight, *token; + int indentx, highlightlen; + + drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : item->out ? SchemeOutHighlight : SchemeNormHighlight]); + strcpy(tokens, text); + for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) { + highlight = fstrstr(item->text, token); + while (highlight) { + // Move item str end, calc width for highlight indent, & restore + highlightlen = highlight - item->text; + restorechar = *highlight; + item->text[highlightlen] = '\0'; + indentx = TEXTW(item->text); + item->text[highlightlen] = restorechar; + + // Move highlight str end, draw highlight, & restore + restorechar = highlight[strlen(token)]; + highlight[strlen(token)] = '\0'; + if (indentx - (lrpad / 2) - 1 < maxw) + drw_text( + drw, + x + indentx - (lrpad / 2) - 1, + y, + MIN(maxw - indentx, TEXTW(highlight) - lrpad), + bh, 0, highlight, 0 + ); + highlight[strlen(token)] = restorechar; + + if (strlen(highlight) - strlen(token) < strlen(token)) break; + highlight = fstrstr(highlight + strlen(token), token); + } + } +} + +static void +apply_fribidi(char *str) +{ + FriBidiStrIndex len = strlen(str); + FriBidiChar logical[BUFSIZ]; + FriBidiChar visual[BUFSIZ]; + FriBidiParType base = FRIBIDI_PAR_ON; + FriBidiCharSet charset; + fribidi_boolean result; + + fribidi_text[0] = 0; + if (len > 0) { + charset = fribidi_parse_charset("UTF-8"); + len = fribidi_charset_to_unicode(charset, str, len, logical); + result = fribidi_log2vis(logical, len, &base, visual, NULL, NULL, NULL); + len = fribidi_unicode_to_charset(charset, visual, len, fribidi_text); + } +} + +static int +drawitem(struct item *item, int x, int y, int w) +{ + if (item == sel) + drw_setscheme(drw, scheme[SchemeSel]); + else if (item->out) + drw_setscheme(drw, scheme[SchemeOut]); + else + drw_setscheme(drw, scheme[SchemeNorm]); + + apply_fribidi(item->text); + int r = drw_text(drw, x, y, w, bh, lrpad / 2, fribidi_text, 0); + drawhighlights(item, x, y, w); + return r; +} + +static void +drawmenu(void) +{ + unsigned int curpos; + struct item *item; + int x = 0, y = 0, w; + char *censort; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); + + if (prompt && *prompt) { + 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]); + if (passwd) { + censort = ecalloc(1, sizeof(text)); + memset(censort, '.', strlen(text)); + drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0); + free(censort); + } else { + apply_fribidi(text); + drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0); + } + + 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); + } + + if (lines > 0) { + /* draw vertical list */ + for (item = curr; item != next; item = item->right) + drawitem(item, x - promptw, y += bh, mw); + } 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[32]; + int len; + KeySym ksym; + Status status; + + len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); + switch (status) { + default: /* XLookupNone, XBufferOverflow */ + return; + case XLookupChars: + goto insert; + case XLookupKeySym: + case XLookupBoth: + 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 */ + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + return; + case XK_Y: /* paste selection from clipboard */ + XConvertSelection(dpy, clip, 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; + strncpy(text, sel->text, sizeof text - 1); + text[sizeof text - 1] = '\0'; + cursor = strlen(text); + 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 buf[sizeof text], *p; + size_t i, size = 0; + if (passwd) { + inputw = lines = 0; + return; + } + + /* read each line from stdin and add it to the item list */ + for (i = 0; fgets(buf, sizeof buf, stdin); i++) { + if (i + 1 >= size / sizeof *items) + if (!(items = realloc(items, (size += BUFSIZ)))) + die("cannot realloc %zu bytes:", size); + if ((p = strchr(buf, '\n'))) + *p = '\0'; + if (!(items[i].text = strdup(buf))) + die("cannot strdup %zu bytes:", strlen(buf) + 1); + items[i].out = 0; + } + if (items) + items[i].text = NULL; + lines = MIN(lines, i); +} + +void +resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) +{ + char *sdst = NULL; + int *idst = NULL; + float *fdst = NULL; + sdst = dst; + idst = dst; + fdst = dst; + char fullname[256]; + char *type; + XrmValue ret; + snprintf(fullname, sizeof(fullname), "%s.%s", "dmenu", name); + fullname[sizeof(fullname) - 1] = '\0'; + XrmGetResource(db, fullname, "*", &type, &ret); + if (!(ret.addr == NULL || strncmp("String", type, 64))) + { + switch (rtype) { + case STRING: + strcpy(sdst, ret.addr); + break; + case INTEGER: + *idst = strtoul(ret.addr, NULL, 10); + break; + case FLOAT: + *fdst = strtof(ret.addr, NULL); + break; + } + } +} + +void +load_xresources(void) +{ + Display *display; + char *resm; + XrmDatabase db; + ResourcePref *p; + display = XOpenDisplay(NULL); + resm = XResourceManagerString(display); + if (!resm) + return; + db = XrmGetStringDatabase(resm); + for (p = resources; p < resources + LENGTH(resources); p++) + resource_load(db, p->name, p->type, p->dst); + XCloseDisplay(display); +} + +static void +run(void) +{ + XEvent ev; + int i; + + while (!XNextEvent(dpy, &ev)) { + if (preselected) { + for (i = 0; i < preselected; i++) { + if (sel && sel->right && (sel = sel->right) == next) { + curr = next; + calcoffsets(); + } + } + drawmenu(); + preselected = 0; + } + 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, tmp; + XSetWindowAttributes swa; + XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; + XClassHint ch = {"dmenu", "dmenu"}; + struct item *item; +#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], alphas[j], 2); + + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); + + /* calculate menu geometry */ + bh = drw->fonts->h + 2; + 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; + for (item = items; item && item->text; ++item) { + if ((tmp = textw_clamp(item->text, mw/3)) > inputw) { + if ((inputw = tmp) == mw/3) + break; + } + } + match(); + + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = 0; + swa.border_pixel = 0; + swa.colormap = cmap; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dpy, parentwin, x, y, mw - border_width * 2, mh, border_width, + depth, CopyFromParent, visual, + CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa); + if (border_width) + XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); + 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) { + 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) +{ + fputs("usage: dmenu [-bfivP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid] [-n number] [-bw number]\n", stderr); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + XWindowAttributes wa; + int i, fast = 0; + + XrmInitialize(); + load_xresources(); + + 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 (!strcmp(argv[i], "-P")) /* is the input a password */ + passwd = 1; + 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], "-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 if (!strcmp(argv[i], "-n")) /* preselected item */ + preselected = atoi(argv[++i]); + else if (!strcmp(argv[i], "-bw")) + border_width = atoi(argv[++i]); /* border width */ + 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); + xinitvisual(); + drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap); + 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 */ +} + +void +xinitvisual() +{ + XVisualInfo *infos; + XRenderPictFormat *fmt; + int nitems; + int i; + + XVisualInfo tpl = { + .screen = screen, + .depth = 32, + .class = TrueColor + }; + long masks = VisualScreenMask | VisualDepthMask | VisualClassMask; + + infos = XGetVisualInfo(dpy, masks, &tpl, &nitems); + visual = NULL; + for(i = 0; i < nitems; i ++) { + fmt = XRenderFindVisualFormat(dpy, infos[i].visual); + if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { + visual = infos[i].visual; + depth = infos[i].depth; + cmap = XCreateColormap(dpy, root, visual, AllocNone); + useargb = 1; + break; + } + } + + XFree(infos); + + if (! visual) { + visual = DefaultVisual(dpy, screen); + depth = DefaultDepth(dpy, screen); + cmap = DefaultColormap(dpy, screen); + } +} + diff --git a/.local/src/dmenu/dmenu.o b/.local/src/dmenu/dmenu.o Binary files differ. diff --git a/.local/src/dmenu/dmenu_path b/.local/src/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/.local/src/dmenu/dmenu_run b/.local/src/dmenu/dmenu_run @@ -0,0 +1,2 @@ +#!/bin/sh +dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & diff --git a/.local/src/dmenu/dmenu_run.hist b/.local/src/dmenu/dmenu_run.hist @@ -0,0 +1,50 @@ +#!/bin/sh + +cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} +if [ -d "$cachedir" ]; then + cache=$cachedir/dmenu_run + historyfile=$cachedir/dmenu_history +else # if no xdg dir, fall back to dotfiles in ~ + cache=$HOME/.dmenu_cache + historyfile=$HOME/.dmenu_history +fi + +IFS=: +if stest -dqr -n "$cache" $PATH; then + stest -flx $PATH | sort -u > "$cache" +fi +unset IFS + +awk -v histfile=$historyfile ' + BEGIN { + while( (getline < histfile) > 0 ) { + sub("^[0-9]+\t","") + print + x[$0]=1 + } + } !x[$0]++ ' "$cache" \ + | dmenu -i "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + while ( (getline < histfile) > 0 ) { + count=$1 + sub("^[0-9]+\t","") + fname=$0 + history[fname]=count + } + close(histfile) + } + + { + history[$0]++ + print + } + + END { + if(!NR) exit + for (f in history) + print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done diff --git a/.local/src/dmenu/drw.c b/.local/src/dmenu/drw.c @@ -0,0 +1,467 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <X11/Xlib.h> +#include <X11/Xft/Xft.h> + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->visual = visual; + drw->depth = depth; + drw->cmap = cmap; + drw->drawable = XCreatePixmap(dpy, root, w, h, depth); + drw->gc = XCreateGC(dpy, drw->drawable, 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, drw->depth); +} + +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."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + 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, unsigned int alpha) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap, + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); + + dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24); +} + +/* 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, char *clrnames[], const unsigned int alphas[], 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], alphas[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) +{ + if (!drw || !drw->scheme) + return; + 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 i, ty, ellipsis_x = 0; + unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + int utf8strlen, utf8charlen, 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. */ + enum { nomatches_len = 64 }; + static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; + static unsigned int ellipsis_width = 0; + + 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); + d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + if (!ellipsis_width && render) + ellipsis_width = drw_fontset_getwidth(drw, "..."); + while (1) { + ew = ellipsis_len = utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + 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) { + utf8strlen += utf8charlen; + text += utf8charlen; + ew += tmpw; + } else { + nextfont = curfont; + } + break; + } + } + + if (overflow || !charexists || nextfont) + 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 (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; + + for (i = 0; i < nomatches_len; ++i) { + /* avoid calling XftFontMatch if we know we won't find a match */ + if (utf8codepoint == nomatches.codepoint[i]) + 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); + //FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + 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.codepoint[++nomatches.idx % nomatches_len] = 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/.local/src/dmenu/drw.h b/.local/src/dmenu/drw.h @@ -0,0 +1,62 @@ +/* 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; + Visual *visual; + unsigned int depth; + Colormap cmap; + 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, Visual*, unsigned int, Colormap); +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, unsigned int alpha); +Clr *drw_scm_create(Drw *drw, char *clrnames[], const unsigned int alphas[], 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); +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/.local/src/dmenu/drw.o b/.local/src/dmenu/drw.o Binary files differ. diff --git a/.local/src/dmenu/patches/dmenu-alpha-20210605-1a13d04.diff b/.local/src/dmenu/patches/dmenu-alpha-20210605-1a13d04.diff @@ -0,0 +1,267 @@ +diff --git a/config.def.h b/config.def.h +index 1edb647..697d511 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,7 @@ + /* Default settings; can be overriden by command line. */ + + static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ ++static const unsigned int alpha = 0xf0; + /* -fn option overrides fonts[0]; default X11 font or font set */ + static const char *fonts[] = { + "monospace:size=10" +@@ -13,6 +14,13 @@ static const char *colors[SchemeLast][2] = { + [SchemeSel] = { "#eeeeee", "#005577" }, + [SchemeOut] = { "#000000", "#00ffff" }, + }; ++ ++static const unsigned int alphas[SchemeLast][2] = { ++ [SchemeNorm] = { OPAQUE, alpha }, ++ [SchemeSel] = { OPAQUE, alpha }, ++ [SchemeOut] = { OPAQUE, alpha }, ++}; ++ + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; + +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..3e56e1a 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -10,6 +10,7 @@ + + #include <X11/Xlib.h> + #include <X11/Xatom.h> ++#include <X11/Xproto.h> + #include <X11/Xutil.h> + #ifdef XINERAMA + #include <X11/extensions/Xinerama.h> +@@ -25,6 +26,8 @@ + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define OPAQUE 0xffU ++ + /* enums */ + enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ + +@@ -53,10 +56,16 @@ static XIC xic; + static Drw *drw; + static Clr *scheme[SchemeLast]; + ++static int useargb = 0; ++static Visual *visual; ++static int depth; ++static Colormap cmap; ++ + #include "config.h" + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; + static char *(*fstrstr)(const char *, const char *) = strstr; ++static void xinitvisual(); + + static void + appenditem(struct item *item, struct item **list, struct item **last) +@@ -602,7 +611,7 @@ setup(void) + #endif + /* init appearance */ + for (j = 0; j < SchemeLast; j++) +- scheme[j] = drw_scm_create(drw, colors[j], 2); ++ scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2); + + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); +@@ -640,6 +649,7 @@ setup(void) + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; ++ + XFree(info); + } else + #endif +@@ -657,11 +667,13 @@ setup(void) + + /* create menu window */ + swa.override_redirect = True; +- swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ swa.background_pixel = 0; ++ swa.border_pixel = 0; ++ swa.colormap = cmap; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; +- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, +- CopyFromParent, CopyFromParent, CopyFromParent, +- CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); ++ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, ++ depth, CopyFromParent, visual, ++ CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa); + XSetClassHint(dpy, win, &ch); + + +@@ -747,7 +759,8 @@ main(int argc, char *argv[]) + 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); ++ xinitvisual(); ++ drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; +@@ -769,3 +782,40 @@ main(int argc, char *argv[]) + + return 1; /* unreachable */ + } ++ ++ void ++xinitvisual() ++{ ++ XVisualInfo *infos; ++ XRenderPictFormat *fmt; ++ int nitems; ++ int i; ++ ++ XVisualInfo tpl = { ++ .screen = screen, ++ .depth = 32, ++ .class = TrueColor ++ }; ++ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask; ++ ++ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems); ++ visual = NULL; ++ for(i = 0; i < nitems; i ++) { ++ fmt = XRenderFindVisualFormat(dpy, infos[i].visual); ++ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { ++ visual = infos[i].visual; ++ depth = infos[i].depth; ++ cmap = XCreateColormap(dpy, root, visual, AllocNone); ++ useargb = 1; ++ break; ++ } ++ } ++ ++ XFree(infos); ++ ++ if (! visual) { ++ visual = DefaultVisual(dpy, screen); ++ depth = DefaultDepth(dpy, screen); ++ cmap = DefaultColormap(dpy, screen); ++ } ++} +diff --git a/drw.c b/drw.c +index 4cdbcbe..fe3aadd 100644 +--- a/drw.c ++++ b/drw.c +@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen) + } + + Drw * +-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) ++drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap) + { + Drw *drw = ecalloc(1, sizeof(Drw)); + +@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h + 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); ++ drw->visual = visual; ++ drw->depth = depth; ++ drw->cmap = cmap; ++ drw->drawable = XCreatePixmap(dpy, root, w, h, depth); ++ drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) + 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)); ++ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); + } + + void +@@ -194,21 +197,22 @@ drw_fontset_free(Fnt *font) + } + + void +-drw_clr_create(Drw *drw, Clr *dest, const char *clrname) ++drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha) + { + if (!drw || !dest || !clrname) + return; + +- if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), +- DefaultColormap(drw->dpy, drw->screen), ++ if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap, + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); ++ ++ dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24); + } + + /* 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) ++drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount) + { + size_t i; + Clr *ret; +@@ -218,7 +222,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) + return NULL; + + for (i = 0; i < clrcount; i++) +- drw_clr_create(drw, &ret[i], clrnames[i]); ++ drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]); + return ret; + } + +@@ -274,9 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); +- d = XftDrawCreate(drw->dpy, drw->drawable, +- DefaultVisual(drw->dpy, drw->screen), +- DefaultColormap(drw->dpy, drw->screen)); ++ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap); + x += lpad; + w -= lpad; + } +diff --git a/drw.h b/drw.h +index 4c67419..f6fa5cd 100644 +--- a/drw.h ++++ b/drw.h +@@ -20,6 +20,9 @@ typedef struct { + Display *dpy; + int screen; + Window root; ++ Visual *visual; ++ unsigned int depth; ++ Colormap cmap; + Drawable drawable; + GC gc; + Clr *scheme; +@@ -27,7 +30,7 @@ typedef struct { + } Drw; + + /* Drawable abstraction */ +-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); ++Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual*, unsigned int, Colormap); + void drw_resize(Drw *drw, unsigned int w, unsigned int h); + void drw_free(Drw *drw); + +@@ -38,8 +41,8 @@ unsigned int drw_fontset_getwidth(Drw *drw, const char *text); + 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); ++void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha); ++Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount); + + /* Cursor abstraction */ + Cur *drw_cur_create(Drw *drw, int shape); diff --git a/.local/src/dmenu/patches/dmenu-bidi-20210723-b34d318.diff b/.local/src/dmenu/patches/dmenu-bidi-20210723-b34d318.diff @@ -0,0 +1,109 @@ +From b34d318bfed8557f2a1e53fc523b8ecff7c79374 Mon Sep 17 00:00:00 2001 +From: Eyal Seelig <[email protected]> +Date: Fri, 23 Jul 2021 18:31:11 +0300 +Subject: [PATCH] Added support for RTL languages, such as Hebrew, Arabic, and + Farsi, using the FriBiDi library + +--- + config.mk | 8 ++++++-- + dmenu.c | 29 +++++++++++++++++++++++++++-- + 2 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/config.mk b/config.mk +index 05d5a3e..eefd0ae 100644 +--- a/config.mk ++++ b/config.mk +@@ -8,6 +8,8 @@ MANPREFIX = $(PREFIX)/share/man + X11INC = /usr/X11R6/include + X11LIB = /usr/X11R6/lib + ++BDINC = /usr/include/fribidi ++ + # Xinerama, comment if you don't want it + XINERAMALIBS = -lXinerama + XINERAMAFLAGS = -DXINERAMA +@@ -18,9 +20,11 @@ FREETYPEINC = /usr/include/freetype2 + # OpenBSD (uncomment) + #FREETYPEINC = $(X11INC)/freetype2 + ++BDLIBS = -lfribidi ++ + # includes and libs +-INCS = -I$(X11INC) -I$(FREETYPEINC) +-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) ++INCS = -I$(X11INC) -I$(FREETYPEINC) -I$(BDINC) ++LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) $(BDLIBS) + + # flags + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..389916b 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -16,6 +16,8 @@ + #endif + #include <X11/Xft/Xft.h> + ++#include <fribidi.h> ++ + #include "drw.h" + #include "util.h" + +@@ -35,6 +37,7 @@ struct item { + }; + + static char text[BUFSIZ] = ""; ++static char fribidi_text[BUFSIZ] = ""; + static char *embed; + static int bh, mw, mh; + static int inputw = 0, promptw; +@@ -113,6 +116,26 @@ cistrstr(const char *s, const char *sub) + return NULL; + } + ++static void ++apply_fribidi(char *str) ++{ ++ FriBidiStrIndex len = strlen(str); ++ FriBidiChar logical[BUFSIZ]; ++ FriBidiChar visual[BUFSIZ]; ++ FriBidiParType base = FRIBIDI_PAR_ON; ++ FriBidiCharSet charset; ++ fribidi_boolean result; ++ ++ fribidi_text[0] = 0; ++ if (len>0) ++ { ++ charset = fribidi_parse_charset("UTF-8"); ++ len = fribidi_charset_to_unicode(charset, str, len, logical); ++ result = fribidi_log2vis(logical, len, &base, visual, NULL, NULL, NULL); ++ len = fribidi_unicode_to_charset(charset, visual, len, fribidi_text); ++ } ++} ++ + static int + drawitem(struct item *item, int x, int y, int w) + { +@@ -123,7 +146,8 @@ drawitem(struct item *item, int x, int y, int w) + else + drw_setscheme(drw, scheme[SchemeNorm]); + +- return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); ++ apply_fribidi(item->text); ++ return drw_text(drw, x, y, w, bh, lrpad / 2, fribidi_text, 0); + } + + static void +@@ -143,7 +167,8 @@ drawmenu(void) + /* 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); ++ apply_fribidi(text); ++ drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { +-- +2.32.0 + diff --git a/.local/src/dmenu/patches/dmenu-highlight-20201211-fcdc159.diff b/.local/src/dmenu/patches/dmenu-highlight-20201211-fcdc159.diff @@ -0,0 +1,97 @@ +From fcdc1593ed418166f20b7e691a49b1e6eefc116e Mon Sep 17 00:00:00 2001 +From: Nathaniel Evan <[email protected]> +Date: Fri, 11 Dec 2020 11:08:12 +0700 +Subject: [PATCH] Highlight matched text in a different color scheme + +--- + config.def.h | 3 +++ + dmenu.c | 44 +++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 44 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1edb647..79be73a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -11,7 +11,10 @@ static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#bbbbbb", "#222222" }, + [SchemeSel] = { "#eeeeee", "#005577" }, ++ [SchemeSelHighlight] = { "#ffc978", "#005577" }, ++ [SchemeNormHighlight] = { "#ffc978", "#222222" }, + [SchemeOut] = { "#000000", "#00ffff" }, ++ [SchemeOutHighlight] = { "#ffc978", "#00ffff" }, + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..cce1ad1 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -26,8 +26,7 @@ + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + + /* enums */ +-enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ +- ++enum { SchemeNorm, SchemeSel, SchemeOut, SchemeNormHighlight, SchemeSelHighlight, SchemeOutHighlight, SchemeLast }; /* color schemes */ + struct item { + char *text; + struct item *left, *right; +@@ -113,6 +112,43 @@ cistrstr(const char *s, const char *sub) + return NULL; + } + ++static void ++drawhighlights(struct item *item, int x, int y, int maxw) ++{ ++ char restorechar, tokens[sizeof text], *highlight, *token; ++ int indentx, highlightlen; ++ ++ drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : item->out ? SchemeOutHighlight : SchemeNormHighlight]); ++ strcpy(tokens, text); ++ for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) { ++ highlight = fstrstr(item->text, token); ++ while (highlight) { ++ // Move item str end, calc width for highlight indent, & restore ++ highlightlen = highlight - item->text; ++ restorechar = *highlight; ++ item->text[highlightlen] = '\0'; ++ indentx = TEXTW(item->text); ++ item->text[highlightlen] = restorechar; ++ ++ // Move highlight str end, draw highlight, & restore ++ restorechar = highlight[strlen(token)]; ++ highlight[strlen(token)] = '\0'; ++ if (indentx - (lrpad / 2) - 1 < maxw) ++ drw_text( ++ drw, ++ x + indentx - (lrpad / 2) - 1, ++ y, ++ MIN(maxw - indentx, TEXTW(highlight) - lrpad), ++ bh, 0, highlight, 0 ++ ); ++ highlight[strlen(token)] = restorechar; ++ ++ if (strlen(highlight) - strlen(token) < strlen(token)) break; ++ highlight = fstrstr(highlight + strlen(token), token); ++ } ++ } ++} ++ + static int + drawitem(struct item *item, int x, int y, int w) + { +@@ -123,7 +159,9 @@ drawitem(struct item *item, int x, int y, int w) + else + drw_setscheme(drw, scheme[SchemeNorm]); + +- return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); ++ int r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); ++ drawhighlights(item, x, y, w); ++ return r; + } + + static void +-- +2.29.2 + diff --git a/.local/src/dmenu/patches/dmenu-linesbelowprompt-and-fullwidth-20211014.diff b/.local/src/dmenu/patches/dmenu-linesbelowprompt-and-fullwidth-20211014.diff @@ -0,0 +1,25 @@ +From 98e63311c4816fb3c7f5c5d00232fec3232465f3 Mon Sep 17 00:00:00 2001 +From: Sebastian LaVine <[email protected]> +Date: Sat, 3 Jul 2021 17:35:50 -0400 +Subject: [PATCH] Draw lines immediately below prompt + +--- + dmenu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..5a041a6 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -154,7 +154,7 @@ drawmenu(void) + if (lines > 0) { + /* draw vertical list */ + for (item = curr; item != next; item = item->right) +- drawitem(item, x, y += bh, mw - x); ++ drawitem(item, x - promptw, y += bh, mw); + } else if (matches) { + /* draw horizontal list */ + x += inputw; +-- +2.32.0 + diff --git a/.local/src/dmenu/patches/dmenu-password-5.0.diff b/.local/src/dmenu/patches/dmenu-password-5.0.diff @@ -0,0 +1,103 @@ +From c4de1032bd4c247bc20b6ab92a10a8d778966679 Mon Sep 17 00:00:00 2001 +From: Mehrad Mahmoudian <[email protected]> +Date: Tue, 4 May 2021 12:05:09 +0300 +Subject: [PATCH] patched with password patch + +--- + dmenu.1 | 5 ++++- + dmenu.c | 21 +++++++++++++++++---- + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..762f707 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -3,7 +3,7 @@ + dmenu \- dynamic menu + .SH SYNOPSIS + .B dmenu +-.RB [ \-bfiv ] ++.RB [ \-bfivP ] + .RB [ \-l + .IR lines ] + .RB [ \-m +@@ -47,6 +47,9 @@ is faster, but will lock up X until stdin reaches end\-of\-file. + .B \-i + dmenu matches menu items case insensitively. + .TP ++.B \-P ++dmenu will not directly display the keyboard input, but instead replace it with dots. All data from stdin will be ignored. ++.TP + .BI \-l " lines" + dmenu lists items vertically, with the given number of lines. + .TP +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..ad8f63b 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -37,7 +37,7 @@ struct item { + static char text[BUFSIZ] = ""; + static char *embed; + static int bh, mw, mh; +-static int inputw = 0, promptw; ++static int inputw = 0, promptw, passwd = 0; + static int lrpad; /* sum of left and right padding */ + static size_t cursor; + static struct item *items = NULL; +@@ -132,6 +132,7 @@ drawmenu(void) + unsigned int curpos; + struct item *item; + int x = 0, y = 0, w; ++ char *censort; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); +@@ -143,7 +144,12 @@ drawmenu(void) + /* 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); ++ if (passwd) { ++ censort = ecalloc(1, sizeof(text)); ++ memset(censort, '.', strlen(text)); ++ drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0); ++ free(censort); ++ } else drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { +@@ -524,6 +530,11 @@ readstdin(void) + char buf[sizeof text], *p; + size_t i, imax = 0, size = 0; + unsigned int tmpmax = 0; ++ if(passwd){ ++ inputw = lines = 0; ++ return; ++ } ++ + + /* read each line from stdin and add it to the item list */ + for (i = 0; fgets(buf, sizeof buf, stdin); i++) { +@@ -689,7 +700,7 @@ setup(void) + static void + usage(void) + { +- fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++ fputs("usage: dmenu [-bfivP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); + exit(1); + } +@@ -712,7 +723,9 @@ main(int argc, char *argv[]) + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + fstrncmp = strncasecmp; + fstrstr = cistrstr; +- } else if (i + 1 == argc) ++ } else if (!strcmp(argv[i], "-P")) /* is the input a password */ ++ passwd = 1; ++ else if (i + 1 == argc) + usage(); + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ +-- +2.31.1 + diff --git a/.local/src/dmenu/patches/dmenu-preselect-20200513-db6093f.diff b/.local/src/dmenu/patches/dmenu-preselect-20200513-db6093f.diff @@ -0,0 +1,90 @@ +From 055e86dee88c5135b3d3a691942a915334d1b3a2 Mon Sep 17 00:00:00 2001 +From: Mathieu Moneyron <[email protected]> +Date: Wed, 13 May 2020 17:28:37 +0200 +Subject: [PATCH] Added option to preselect an item by providing a number + +--- + config.def.h | 3 +++ + dmenu.1 | 5 +++++ + dmenu.c | 15 ++++++++++++++- + 3 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 1edb647..95bee59 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -21,3 +21,6 @@ static unsigned int lines = 0; + * for example: " /?\"&[]" + */ + static const char worddelimiters[] = " "; ++ ++/* -n option; preselected item starting from 0 */ ++static unsigned int preselected = 0; +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..6e1ee7f 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -22,6 +22,8 @@ dmenu \- dynamic menu + .IR color ] + .RB [ \-w + .IR windowid ] ++.RB [ \-n ++.IR number ] + .P + .BR dmenu_run " ..." + .SH DESCRIPTION +@@ -80,6 +82,9 @@ prints version information to stdout, then exits. + .TP + .BI \-w " windowid" + embed into windowid. ++.TP ++.BI \-n " number" ++preseslected item starting from 0. + .SH USAGE + dmenu is completely controlled by the keyboard. Items are selected using the + arrow keys, page up, page down, home, and end. +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..0a02609 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -551,8 +551,19 @@ static void + run(void) + { + XEvent ev; ++ int i; + + while (!XNextEvent(dpy, &ev)) { ++ if (preselected) { ++ for (i = 0; i < preselected; i++) { ++ if (sel && sel->right && (sel = sel->right) == next) { ++ curr = next; ++ calcoffsets(); ++ } ++ } ++ drawmenu(); ++ preselected = 0; ++ } + if (XFilterEvent(&ev, win)) + continue; + switch(ev.type) { +@@ -690,7 +701,7 @@ static void + usage(void) + { + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); ++ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid] [-n number]\n", stderr); + exit(1); + } + +@@ -733,6 +744,8 @@ main(int argc, char *argv[]) + colors[SchemeSel][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; ++ else if (!strcmp(argv[i], "-n")) /* preselected item */ ++ preselected = atoi(argv[++i]); + else + usage(); + +-- +2.26.2 + diff --git a/.local/src/dmenu/patches/dmenu-xresources-alt-5.0.diff b/.local/src/dmenu/patches/dmenu-xresources-alt-5.0.diff @@ -0,0 +1,182 @@ +diff -rupN orig/config.def.h patched/config.def.h +--- orig/config.def.h 2021-04-16 06:30:47.713924755 +0300 ++++ patched/config.def.h 2021-04-16 06:34:14.956933252 +0300 +@@ -2,16 +2,25 @@ + /* 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 char font[] = "monospace:size=10"; + static const char *fonts[] = { +- "monospace:size=10" ++ font, ++ "monospace:size=10", + }; +-static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +-static const char *colors[SchemeLast][2] = { ++ ++static char *prompt = NULL; /* -p option; prompt to the left of input field */ ++ ++static char normfgcolor[] = "#bbbbbb"; ++static char normbgcolor[] = "#222222"; ++static char selfgcolor[] = "#eeeeee"; ++static char selbgcolor[] = "#005577"; ++static char *colors[SchemeLast][2] = { + /* fg bg */ +- [SchemeNorm] = { "#bbbbbb", "#222222" }, +- [SchemeSel] = { "#eeeeee", "#005577" }, +- [SchemeOut] = { "#000000", "#00ffff" }, ++ [SchemeNorm] = { normfgcolor, normbgcolor }, ++ [SchemeSel] = { selfgcolor, selbgcolor }, ++ [SchemeOut] = { "#000000", "#00ffff" }, + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; +@@ -21,3 +30,15 @@ static unsigned int lines = 0; + * for example: " /?\"&[]" + */ + static const char worddelimiters[] = " "; ++ ++/* ++ * Xresources preferences to load at startup ++ */ ++ResourcePref resources[] = { ++ { "font", STRING, &font }, ++ { "normfgcolor", STRING, &normfgcolor }, ++ { "normbgcolor", STRING, &normbgcolor }, ++ { "selfgcolor", STRING, &selfgcolor }, ++ { "selbgcolor", STRING, &selbgcolor }, ++ { "prompt", STRING, &prompt }, ++}; +diff -rupN orig/dmenu.c patched/dmenu.c +--- orig/dmenu.c 2021-04-16 06:30:47.715924755 +0300 ++++ patched/dmenu.c 2021-04-16 06:30:59.668925245 +0300 +@@ -11,6 +11,7 @@ + #include <X11/Xlib.h> + #include <X11/Xatom.h> + #include <X11/Xutil.h> ++#include <X11/Xresource.h> + #ifdef XINERAMA + #include <X11/extensions/Xinerama.h> + #endif +@@ -53,6 +54,21 @@ static XIC xic; + static Drw *drw; + static Clr *scheme[SchemeLast]; + ++/* Xresources preferences */ ++enum resource_type { ++ STRING = 0, ++ INTEGER = 1, ++ FLOAT = 2 ++}; ++typedef struct { ++ char *name; ++ enum resource_type type; ++ void *dst; ++} ResourcePref; ++ ++static void load_xresources(void); ++static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); ++ + #include "config.h" + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +@@ -395,7 +411,7 @@ keypress(XKeyEvent *ev) + + switch(ksym) { + default: +-insert: ++ insert: + if (!iscntrl(*buf)) + insert(buf, len); + break; +@@ -547,6 +563,54 @@ readstdin(void) + lines = MIN(lines, i); + } + ++void ++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) ++{ ++ char *sdst = NULL; ++ int *idst = NULL; ++ float *fdst = NULL; ++ sdst = dst; ++ idst = dst; ++ fdst = dst; ++ char fullname[256]; ++ char *type; ++ XrmValue ret; ++ snprintf(fullname, sizeof(fullname), "%s.%s", "dmenu", name); ++ fullname[sizeof(fullname) - 1] = '\0'; ++ XrmGetResource(db, fullname, "*", &type, &ret); ++ if (!(ret.addr == NULL || strncmp("String", type, 64))) ++ { ++ switch (rtype) { ++ case STRING: ++ strcpy(sdst, ret.addr); ++ break; ++ case INTEGER: ++ *idst = strtoul(ret.addr, NULL, 10); ++ break; ++ case FLOAT: ++ *fdst = strtof(ret.addr, NULL); ++ break; ++ } ++ } ++} ++ ++void ++load_xresources(void) ++{ ++ Display *display; ++ char *resm; ++ XrmDatabase db; ++ ResourcePref *p; ++ display = XOpenDisplay(NULL); ++ resm = XResourceManagerString(display); ++ if (!resm) ++ return; ++ db = XrmGetStringDatabase(resm); ++ for (p = resources; p < resources + LENGTH(resources); p++) ++ resource_load(db, p->name, p->type, p->dst); ++ XCloseDisplay(display); ++} ++ + static void + run(void) + { +@@ -700,6 +764,9 @@ main(int argc, char *argv[]) + XWindowAttributes wa; + int i, fast = 0; + ++ XrmInitialize(); ++ load_xresources(); ++ + for (i = 1; i < argc; i++) + /* these options take no arguments */ + if (!strcmp(argv[i], "-v")) { /* prints version information */ +diff -rupN orig/drw.c patched/drw.c +--- orig/drw.c 2021-04-16 06:30:47.718924755 +0300 ++++ patched/drw.c 2021-04-16 06:30:59.670925245 +0300 +@@ -208,7 +208,7 @@ drw_clr_create(Drw *drw, Clr *dest, cons + /* 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) ++drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount) + { + size_t i; + Clr *ret; +diff -rupN orig/drw.h patched/drw.h +--- orig/drw.h 2021-04-16 06:30:47.718924755 +0300 ++++ patched/drw.h 2021-04-16 06:30:59.671925245 +0300 +@@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const c + + /* 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); ++Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount); + + /* Cursor abstraction */ + Cur *drw_cur_create(Drw *drw, int shape); diff --git a/.local/src/dmenu/stest b/.local/src/dmenu/stest Binary files differ. diff --git a/.local/src/dmenu/stest.1 b/.local/src/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/.local/src/dmenu/stest.c b/.local/src/dmenu/stest.c @@ -0,0 +1,109 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/stat.h> + +#include <dirent.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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/.local/src/dmenu/stest.o b/.local/src/dmenu/stest.o Binary files differ. diff --git a/.local/src/dmenu/util.c b/.local/src/dmenu/util.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/.local/src/dmenu/util.h b/.local/src/dmenu/util.h @@ -0,0 +1,8 @@ +/* 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)) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/.local/src/dmenu/util.o b/.local/src/dmenu/util.o Binary files differ. diff --git a/.local/src/dwm/LICENSE b/.local/src/dwm/LICENSE @@ -0,0 +1,37 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe <[email protected]> +© 2006-2009 Jukka Salmi <jukka at salmi dot ch> +© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com> +© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com> +© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com> +© 2007-2009 Christof Musik <christof at sendfax dot de> +© 2007-2009 Premysl Hruby <dfenze at gmail dot com> +© 2007-2008 Enno Gottox Boland <gottox at s01 dot de> +© 2008 Martin Hurton <martin dot hurton at gmail dot com> +© 2008 Neale Pickett <neale dot woozle dot org> +© 2009 Mate Nagy <mnagy at port70 dot net> +© 2010-2016 Hiltjo Posthuma <[email protected]> +© 2010-2012 Connor Lane Smith <[email protected]> +© 2011 Christoph Lohmann <[email protected]> +© 2015-2016 Quentin Rameau <[email protected]> +© 2015-2016 Eric Pruitt <[email protected]> +© 2016-2017 Markus Teich <[email protected]> + +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/.local/src/dwm/Makefile b/.local/src/dwm/Makefile @@ -0,0 +1,51 @@ +# dwm - dynamic window manager +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dwm.c util.c +OBJ = ${SRC:.c=.o} + +all: options dwm + +options: + @echo dwm build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + cp config.def.h $@ + +dwm: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + +dist: clean + mkdir -p dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} + tar -cf dwm-${VERSION}.tar dwm-${VERSION} + gzip dwm-${VERSION}.tar + rm -rf dwm-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f dwm ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwm\ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +.PHONY: all options clean dist install uninstall diff --git a/.local/src/dwm/README b/.local/src/dwm/README @@ -0,0 +1,48 @@ +dwm - dynamic window manager +============================ +dwm is an extremely fast, small, and dynamic window manager for X. + + +Requirements +------------ +In order to build dwm you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (dwm is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install dwm (if +necessary as root): + + make clean install + + +Running dwm +----------- +Add the following line to your .xinitrc to start dwm using startx: + + exec dwm + +In order to connect dwm to a specific display, make sure that +the DISPLAY environment variable is set correctly, e.g.: + + DISPLAY=foo.bar:1 exec dwm + +(This will start dwm on display :1 of the host foo.bar.) + +In order to display status info in the bar, you can do something +like this in your .xinitrc: + + while xsetroot -name "`date` `uptime | sed 's/.*,//'`" + do + sleep 1 + done & + exec dwm + + +Configuration +------------- +The configuration of dwm is done by creating a custom config.h +and (re)compiling the source code. diff --git a/.local/src/dwm/config.h b/.local/src/dwm/config.h @@ -0,0 +1,303 @@ +/* See LICENSE file for copyright and license details. */ + +/* Load essentials */ +#include <X11/XF86keysym.h> /* For XF86 multimedia binds */ + +/* System Tray */ +static const int showsystray = 0; /* 0 means no systray */ +static const unsigned int systraypadding= 1; /* systray vertical padding */ +static const unsigned int systrayspacing= 2; /* systray spacing */ +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, 1: systray on left of status text */ + +static const unsigned int systraypinning= 1; /* 0: sloppy systray follows selected monitor, 1: pin systray to monitor X */ +static const int systraypinningfailfirst= 1; /* 1: if pinning fails, display systray on the first monitor, 0: display systray on the last monitor*/ + +/* appearance */ +static const char *fonts[] = { "monospace:size=9", "Vazirmatn:size=9" }; +static const unsigned int borderpx = 0; /* border pixel of windows */ +static const unsigned int gappx = 10; /* gaps between windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const int barheight = 3; /* Spacing around the bar's font */ +static const int hidevacanttags = 1; /* 1 means hide empty tags / 0: show every tag */ +static const int hidetagindicator = 1; /* 1 means hide default top-left square-shaped tag indicator */ +static const int showtitle = 0; /* 1 means show WM_NAME of the currently selected window */ +static const int truecenteredtitle = 0; /* 1 means center the WM_NAME on the status bar */ +static const unsigned int colorfultag = 0; /* 0 means use SchemeSel for selected tag */ +static char fgcolor[] = "#D8DEE9"; +static char bgcolor[] = "#2E3440"; +static char color0[] = "#3B4252"; +static char color1[] = "#BF616A"; +static char color2[] = "#A3BE8C"; +static char color3[] = "#EBCB8B"; +static char color4[] = "#81A1C1"; +static char color5[] = "#B48EAD"; +static char color6[] = "#88C0D0"; +static char color7[] = "#E5E9F0"; +static char color8[] = "#4C566A"; +static char color9[] = "#BF616A"; +static char color10[] = "#A3BE8C"; +static char color11[] = "#EBCB8B"; +static char color12[] = "#81A1C1"; +static char color13[] = "#B48EAD"; +static char color14[] = "#8FBCBB"; +static char color15[] = "#ECEFF4"; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "foreground", STRING, &fgcolor}, + { "background", STRING, &bgcolor}, + { "color0", STRING, &color0}, + { "color1", STRING, &color1}, + { "color2", STRING, &color2}, + { "color3", STRING, &color3}, + { "color4", STRING, &color4}, + { "color5", STRING, &color5}, + { "color6", STRING, &color6}, + { "color7", STRING, &color7}, + { "color8", STRING, &color8}, + { "color9", STRING, &color9}, + { "color10", STRING, &color10}, + { "color11", STRING, &color11}, + { "color12", STRING, &color12}, + { "color13", STRING, &color13}, + { "color14", STRING, &color14}, + { "color15", STRING, &color15}, +}; + +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { color12, color0, color8 }, + [SchemeSel] = { color0, color12, color12 }, + [SchemeLayout] = { color12, color0, color8 }, +}; + +/* if colorfultag == 1: */ +static const char *colortags[][2] = { + { color1, color0 }, + { color2, color0 }, + { color3, color0 }, + { color4, color0 }, + { color5, color0 }, + { color6, color0 }, + { color9, color0 }, + { color10, color0 }, + { color11, color0 }, +}; +//static const char *colortags_sel[][2] = { +// { color1, color8 }, +// { color2, color8 }, +// { color3, color8 }, +// { color4, color8 }, +// { color5, color8 }, +// { color6, color8 }, +// { color9, color8 }, +// { color10, color8 }, +// { color11, color8 }, +//}; +static const char *colortags_sel[][2] = { + { color0, color1 }, + { color0, color2 }, + { color0, color3 }, + { color0, color4 }, + { color0, color5 }, + { color0, color6 }, + { color0, color9 }, + { color0, color10 }, + { color0, color11 }, +}; + +/* tagging */ +//static const char *tags[] = { "𐎠", "𐎡", "𐎢", "𐎣", "𐎤", "𐎥", "𐎦", "𐎧", "𐎨" }; +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + //{ "mpv", NULL, NULL, 0, 1, -1 }, + //{ "Gimp", NULL, NULL, 0, 1, -1 }, + //{ "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { "st-float", NULL, NULL, 0, 1, -1 }, + { NULL, "st-float", NULL, 0, 1, -1 }, + { NULL, NULL, "Event Tester", 0, 0, -1 }, /* xev */ +}; + +/* layout(s) */ +static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static int layouts_default = 0; /* Default layout */ +static const int layouts_floating = 2;/* Layout number for floating mode */ + +//static const Layout layouts[] = { +// /* symbol arrange function */ +// { "Tile", tile }, /* first entry is default */ +// { "Monocle", monocle }, +// { "Float", NULL }, /* no layout function means floating behavior */ +// { NULL, NULL }, +//}; + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "[M]", monocle }, + { "><>", NULL }, /* no layout function means floating behavior */ + { NULL, NULL }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define ALTMOD Mod1Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, \ + { ALTMOD, KEY, focusnthmon, {.i = TAG } }, \ + { ALTMOD|ShiftMask, KEY, tagnthmon, {.i = TAG } }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-i", "-p", "Run:", NULL }; +//static const char *termcmd[] = { "st", NULL }; +//static const char *termcmdfloat[] = { "st", "-c", "st-float", NULL }; +static const char *termcmd[] = { "tabbed", "-cd", "-r", "2", "st", "-w", "''", NULL }; +static const char *termcmdfloat[] = { "tabbed", "-cd", "-n", "st-float", "-r", "2", "st", "-w", "''", NULL }; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_a, spawn, SHCMD("dmenu_drun") }, + { MODKEY, XK_c, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmdfloat } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, + { MODKEY, XK_space, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[2]} }, + { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, + { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, + { MODKEY, XK_s, togglesticky, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY|ControlMask, XK_minus, shiftview, {.i = -1 } }, + { MODKEY|ControlMask, XK_equal, shiftview, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY, XK_F5, live_reload_xresources,{0} }, + { MODKEY|ShiftMask, XK_r, restart, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ControlMask, XK_q, quit, {0} }, + { MODKEY|ShiftMask, XK_b, spawn, SHCMD("dwm-bar -M") }, + { MODKEY|ShiftMask, XK_q, spawn, SHCMD("dmenu-power") }, + { MODKEY, XK_r, spawn, SHCMD("dmenu-record") }, + { MODKEY, XK_w, spawn, SHCMD("surf-open") }, + { MODKEY|ControlMask, XK_w, spawn, SHCMD("surf") }, + { MODKEY|ShiftMask, XK_e, spawn, SHCMD("st -e sh -c \"mutt\"") }, + { MODKEY|ShiftMask, XK_m, spawn, SHCMD("dmenu-man") }, + { MODKEY|ShiftMask, XK_w, spawn, SHCMD("st -c \"st-float\" -g \"100x20\" -e sh -c \"SET_BG_SELECT=1 bg-set\"") }, + { MODKEY|ShiftMask, XK_u, spawn, SHCMD("st -c \"st-float\" -g \"100x28\" -e sh -c \"doas pacman -Syu --noconfirm && rm ~/.cache/pkg_updates\"") }, + { MODKEY|ShiftMask, XK_t, spawn, SHCMD("theme-sel -s") }, + { MODKEY|ShiftMask, XK_g, spawn, SHCMD("gtt") }, + { MODKEY|ShiftMask, XK_y, spawn, SHCMD("myt -d") }, + { MODKEY|ControlMask, XK_l, spawn, SHCMD("slock") }, + { MODKEY, XK_grave, spawn, SHCMD("dmenu-emoji insert") }, + { ControlMask, XK_grave, spawn, SHCMD("dmenu-emoji clipboard") }, + { 0, XK_Print, spawn, SHCMD("screenshot -xc") }, + { ShiftMask, XK_Print, spawn, SHCMD("screenshot -xc -t 5") }, + { ControlMask, XK_Print, spawn, SHCMD("screenshot -xc -s yes") }, + { ControlMask|ShiftMask, XK_Print, spawn, SHCMD("screenshot -xc -s yes -t 5") }, + + { MODKEY, XK_F11, spawn, SHCMD("bright -d") }, + { MODKEY, XK_F12, spawn, SHCMD("bright -i") }, + + { 0, XF86XK_WebCam, spawn, SHCMD("webcam") }, + { 0, XF86XK_TouchpadToggle, spawn, SHCMD("toggle-touch") }, + { 0, XF86XK_TouchpadOn, spawn, SHCMD("toggle-touch") }, + { 0, XF86XK_TouchpadOff, spawn, SHCMD("toggle-touch") }, + { 0, XF86XK_AudioPlay, spawn, SHCMD("media-controller toggle") }, + { 0, XF86XK_AudioPause, spawn, SHCMD("media-controller toggle") }, + { 0, XF86XK_AudioNext, spawn, SHCMD("media-controller next") }, + { 0, XF86XK_AudioPrev, spawn, SHCMD("media-controller prev") }, + { ShiftMask, XF86XK_AudioPlay, spawn, SHCMD("media-controller pause-all") }, + { ShiftMask, XF86XK_AudioPause, spawn, SHCMD("media-controller pause-all") }, + { ShiftMask, XF86XK_AudioNext, spawn, SHCMD("media-controller seek-fwd") }, + { ShiftMask, XF86XK_AudioPrev, spawn, SHCMD("media-controller seek-bwd") }, + { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("bright -i") }, + { 0, XF86XK_MonBrightnessDown, spawn, SHCMD("bright -d") }, + { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("volume -i") }, + { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("volume -d") }, + { 0, XF86XK_AudioMute, spawn, SHCMD("volume -m") }, + { ShiftMask, XF86XK_AudioRaiseVolume, spawn, SHCMD("volume -I") }, + { ShiftMask, XF86XK_AudioLowerVolume, spawn, SHCMD("volume -D") }, + { ShiftMask, XF86XK_AudioMute, spawn, SHCMD("volume -M") }, + { 0, XF86XK_AudioMicMute, spawn, SHCMD("volume -M") }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + /* placemouse options, choose which feels more natural: + * 0 - tiled position is relative to mouse cursor + * 1 - tiled postiion is relative to window center + * 2 - mouse pointer warps to window center + * + * The moveorplace uses movemouse or placemouse depending on the floating state + * of the selected client. Set up individual keybindings for the two if you want + * to control these separately (i.e. to retain the feature to move a tiled window + * into a floating position). + */ + { ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkTagBar, 0, Button4, shiftview, {.i = -1} }, + { ClkTagBar, 0, Button5, shiftview, {.i = +1} }, + { ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1} }, + { ClkLtSymbol, 0, Button3, cyclelayout, {.i = -1} }, + { ClkLtSymbol, 0, Button2, setlayout, {.v = &layouts[0]} }, + { ClkLtSymbol, 0, Button4, cyclelayout, {.i = -1} }, + { ClkLtSymbol, 0, Button5, cyclelayout, {.i = +1} }, + { ClkWinTitle, 0, Button2, togglesticky, {0} }, + { ClkStatusText, 0, Button3, spawn, SHCMD("dwm-bar -M") }, +}; + diff --git a/.local/src/dwm/config.mk b/.local/src/dwm/config.mk @@ -0,0 +1,42 @@ +# dwm version +VERSION = 6.3 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/local/include +X11LIB = /usr/local/lib + +BDINC = /usr/local/include/fribidi + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/local/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = ${X11INC}/freetype2 + +BDLIBS = -lfribidi + +# includes and libs +INCS = -I${X11INC} -I${FREETYPEINC} -I$(BDINC) +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} $(BDLIBS) + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/.local/src/dwm/drw.c b/.local/src/dwm/drw.c @@ -0,0 +1,437 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <X11/Xlib.h> +#include <X11/Xft/Xft.h> + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + 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."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + 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) +{ + if (!drw || !drw->scheme) + return; + 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) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = curfont; + } + break; + } + } + + if (!charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { + 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; + + 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); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + 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); + 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); +} + +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/.local/src/dwm/drw.h b/.local/src/dwm/drw.h @@ -0,0 +1,57 @@ +/* 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, ColBorder }; /* 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); +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); +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/.local/src/dwm/drw.o b/.local/src/dwm/drw.o Binary files differ. diff --git a/.local/src/dwm/dwm b/.local/src/dwm/dwm Binary files differ. diff --git a/.local/src/dwm/dwm.1 b/.local/src/dwm/dwm.1 @@ -0,0 +1,205 @@ +.TH DWM 1 dwm\-VERSION +.SH NAME +dwm \- dynamic window manager +.SH SYNOPSIS +.B dwm +.RB [ \-v ] +.SH DESCRIPTION +dwm is a dynamic window manager for X. It manages windows in tiled, monocle +and floating layouts. Either layout can be applied dynamically, optimising the +environment for the application in use and the task performed. +.P +In tiled layouts windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area on the +right contains all other windows. The number of master area windows can be +adjusted from zero to an arbitrary number. In monocle layout all windows are +maximised to the screen size. In floating layout windows can be resized and +moved freely. Dialog windows are always managed floating, regardless of the +layout applied. +.P +Windows are grouped by tags. Each window can be tagged with one or multiple +tags. Selecting certain tags displays all windows with these tags. +.P +Each screen contains a small status bar which displays all available tags, the +layout, the title of the focused window, and the text read from the root window +name property, if the screen is focused. A floating window is indicated with an +empty square and a maximised floating window is indicated with a filled square +before the windows title. The selected tags are indicated with a different +color. The tags of the focused window are indicated with a filled square in the +top left corner. The tags which are applied to one or more windows are +indicated with an empty square in the top left corner. +.P +dwm draws a small border around windows to indicate the focus state. +.SH OPTIONS +.TP +.B \-v +prints version information to stderr, then exits. +.SH USAGE +.SS Status bar +.TP +.B X root window name +is read and displayed in the status text area. It can be set with the +.BR xsetroot (1) +command. +.TP +.B Button1 +click on a tag label to display all windows with that tag, click on the layout +label toggles between tiled and floating layout. +.TP +.B Button3 +click on a tag label adds/removes all windows with that tag to/from the view. +.TP +.B Mod4\-Button1 +click on a tag label applies that tag to the focused window. +.TP +.B Mod4\-Button3 +click on a tag label adds/removes that tag to/from the focused window. +.SS Keyboard commands +.TP +.B Mod4\-Shift\-Return +Start +.BR st(1). +.TP +.B Mod4\-p +Spawn +.BR dmenu(1) +for launching other programs. +.TP +.B Mod4\-, +Focus previous screen, if any. +.TP +.B Mod4\-. +Focus next screen, if any. +.TP +.B Mod4\-Shift\-, +Send focused window to previous screen, if any. +.TP +.B Mod4\-Shift\-. +Send focused window to next screen, if any. +.TP +.B Mod4\-b +Toggles bar on and off. +.TP +.B Mod4\-t +Sets tiled layout. +.TP +.B Mod4\-f +Sets floating layout. +.TP +.B Mod4\-m +Sets monocle layout. +.TP +.B Mod4\-space +Toggles between current and previous layout. +.TP +.B Mod4\-Control\-, +Cycles backwards in layout list. +.TP +.B Mod4\-Control\-. +Cycles forwards in layout list. +.TP +.B Mod4\-j +Focus next window. +.TP +.B Mod4\-k +Focus previous window. +.TP +.B Mod4\-i +Increase number of windows in master area. +.TP +.B Mod4\-d +Decrease number of windows in master area. +.TP +.B Mod4\-l +Increase master area size. +.TP +.B Mod4\-h +Decrease master area size. +.TP +.B Mod4\-Return +Zooms/cycles focused window to/from master area (tiled layouts only). +.TP +.B Mod4\-Shift\-c +Close focused window. +.TP +.B Mod4\-Shift\-f +Toggle fullscreen for focused window. +.TP +.B Mod4\-Shift\-space +Toggle focused window between tiled and floating state. +.TP +.B Mod4\-Tab +Toggles to the previously selected tags. +.TP +.B Mod4\-Shift\-[1..n] +Apply nth tag to focused window. +.TP +.B Mod4\-Shift\-0 +Apply all tags to focused window. +.TP +.B Mod4\-Control\-Shift\-[1..n] +Add/remove nth tag to/from focused window. +.TP +.B Mod4\-[1..n] +View all windows with nth tag. +.TP +.B Mod4\-0 +View all windows with any tag. +.TP +.B Mod4\-Control\-[1..n] +Add/remove all windows with nth tag to/from the view. +.TP +.B Mod4\-- +Decrease the gaps around windows. +.TP +.B Mod4\-= +Increase the gaps around windows. +.TP +.B Mod4\-Shift-= +Reset the gaps around windows to +.BR 0 . +.TP +.B Mod4\-Shift\-q +Quit dwm. +.TP +.B Mod4\-Control\-Shift\-q +Restart dwm. +.SS Mouse commands +.TP +.B Mod4\-Button1 +Move focused window while dragging. Tiled windows will be toggled to the floating state. +.TP +.B Mod4\-Button2 +Toggles focused window between floating and tiled state. +.TP +.B Mod4\-Button3 +Resize focused window while dragging. Tiled windows will be toggled to the floating state. +.SH CUSTOMIZATION +dwm is customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH SIGNALS +.TP +.B SIGHUP - 1 +Restart the dwm process. +.TP +.B SIGTERM - 15 +Cleanly terminate the dwm process. +.SH SEE ALSO +.BR dmenu (1), +.BR st (1) +.SH ISSUES +Java applications which use the XToolkit/XAWT backend may draw grey windows +only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early +JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds +are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the +environment variable +.BR AWT_TOOLKIT=MToolkit +(to use the older Motif backend instead) or running +.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D +or +.B wmname LG3D +(to pretend that a non-reparenting window manager is running that the +XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable +.BR _JAVA_AWT_WM_NONREPARENTING=1 . +.SH BUGS +Send all bug reports with a patch to [email protected]. diff --git a/.local/src/dwm/dwm.c b/.local/src/dwm/dwm.c @@ -0,0 +1,3243 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include <errno.h> +#include <locale.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xproto.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#ifdef XINERAMA +#include <X11/extensions/Xinerama.h> +#endif /* XINERAMA */ +#include <X11/Xft/Xft.h> +#include <fribidi.h> + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \ + * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y))) +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define WIDTH(X) ((X)->w + 2 * (X)->bw) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw) +#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +#define SYSTEM_TRAY_REQUEST_DOCK 0 +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_MODALITY_ON 10 +#define XEMBED_MAPPED (1 << 0) +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR + +/* enums */ +enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +enum { SchemeNorm, SchemeSel, SchemeLayout }; /* color schemes */ +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */ +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ +enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, issticky, beingmoved; + pid_t pid; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + unsigned int colorfultag; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + +/* Xresources preferences */ +enum resource_type { + STRING = 0, + INTEGER = 1, + FLOAT = 2 +}; + +typedef struct { + char *name; + enum resource_type type; + void *dst; +} ResourcePref; + +/* function declarations */ +static Atom getatomprop(Client *c, Atom prop); +static Client *nexttiled(Client *c); +static Client *recttoclient(int x, int y, int w, int h); +static Client *wintoclient(Window w); +static Client *wintosystrayicon(Window w); +static Monitor *createmon(void); +static Monitor *dirtomon(int dir); +static Monitor *numtomon(int num); +static Monitor *recttomon(int x, int y, int w, int h); +static Monitor *systraytomon(Monitor *m); +static Monitor *wintomon(Window w); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static int drawstatusbar(Monitor *m, int bh, char* text); +static int getrootptr(int *x, int *y); +static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +static int updategeom(void); +static int xerror(Display *dpy, XErrorEvent *ee); +static int xerrordummy(Display *dpy, XErrorEvent *ee); +static int xerrorstart(Display *dpy, XErrorEvent *ee); +static long getstate(Window w); +static unsigned int getsystraywidth(); +static void applyrules(Client *c); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachbottom(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static void cyclelayout(const Arg *arg); +static void destroynotify(XEvent *e); +static void detach(Client *c); +static void detachstack(Client *c); +static void drawbar(Monitor *m); +static void drawbars(void); +static int drawstatusbar(Monitor *m, int bh, char* text); +static void enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void focusnthmon(const Arg *arg); +static void focusstack(const Arg *arg); +static void grabbuttons(Client *c, int focused); +static void grabkeys(void); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static void moveorplace(const Arg *arg); +static void movestack(const Arg *arg); +static void placemouse(const Arg *arg); +static void pop(Client *); +static void propertynotify(XEvent *e); +static void restart(const Arg *arg); +static void quit(const Arg *arg); +static void removesystrayicon(Client *i); +static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizebarwin(Monitor *m); +static void resizeclient(Client *c, int x, int y, int w, int h); +static void resizemouse(const Arg *arg); +static void resizerequest(XEvent *e); +static void restack(Monitor *m); +static void run(void); +static void scan(void); +static void sendmon(Client *c, Monitor *m); +static void setclientstate(Client *c, long state); +static void setclienttagprop(Client *c); +static void setfocus(Client *c); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void shiftview(const Arg *arg); +static void showhide(Client *c); +static void sigchld(int unused); +static void sighup(int unused); +static void sigterm(int unused); +static void spawn(const Arg *arg); +static Monitor *systraytomon(Monitor *m); +static void tag(const Arg *arg); +static void tagmon(const Arg *arg); +static void tagnthmon(const Arg *arg); +static void tile(Monitor *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void togglefullscr(const Arg *arg); +static void togglesticky(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static void updatenumlockmask(void); +static void updatesizehints(Client *c); +static void updatestatus(void); +static void updatesystray(void); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); +static void updatetitle(Client *c); +static void updatewindowtype(Client *c); +static void updatewmhints(Client *c); +static void view(const Arg *arg); +static void warp(const Client *c); +static void zoom(const Arg *arg); + +static void live_reload_xresources(const Arg *arg); +static void load_xresources(void); +static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); + +/* variables */ +static Systray *systray = NULL; +static const char broken[] = "broken"; +static char stext[1024]; +static char fribidi_text[BUFSIZ] = ""; +static int screen; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +static int restartsig = 0; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Clr **tagscheme; +static Clr **tagscheme_sel; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +static void +apply_fribidi(const char *str) +{ + FriBidiStrIndex len = strlen(str); + FriBidiChar logical[BUFSIZ]; + FriBidiChar visual[BUFSIZ]; + FriBidiParType base = FRIBIDI_PAR_ON; + FriBidiCharSet charset; + fribidi_boolean result; + + fribidi_text[0] = 0; + if (len>0) + { + charset = fribidi_parse_charset("UTF-8"); + len = fribidi_charset_to_unicode(charset, str, len, logical); + result = fribidi_log2vis(logical, len, &base, visual, NULL, NULL, NULL); + len = fribidi_unicode_to_charset(charset, visual, len, fribidi_text); + } +} + +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachbottom(Client *c) +{ + Client **tc; + c->next = NULL; + for (tc = &c->mon->clients; *tc; tc = &(*tc)->next); + *tc = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + unsigned int occ = 0; + for(c = m->clients; c; c=c->next) + occ |= c->tags; + do { + /* Do not reserve space for vacant tags */ + if (hidevacanttags && !(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; + x += TEXTW(tags[i]); + } while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; + else if (showtitle != 1 || ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors) + 1; i++) + free(scheme[i]); + free(scheme); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void