dotfiles

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

commit d01a5382c9abd1def8b014320f9db4d2788aab32
Author: Mahdi Mirzade <me@mahdi.pw>
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 = me@mahdi.pw +[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 <me@mahdym.ir> +alias chibby-bromanson Chibby Bromanson <chibby.bromanson@eightbitmonster.com> +alias NRK <nrk@disroot.org> +alias ัั‚ั€ะฐั…ะธัšะฐ-ั€ะฐะดะธั› ะกั‚ั€ะฐั…ะธัšะฐ ะ ะฐะดะธั› <contact@strahinja.org> +alias robert-winkler Robert Winkler <robert.winkler@bioprocess.org> +alias Wolf <wolf@wolfsden.cz> +alias viktor-grigorov Viktor Grigorov <vlg@tutamail.com> +alias laslo-hunhold Laslo Hunhold <dev@frign.de> +alias hadrien-lacour Hadrien Lacour <hadrien.lacour@posteo.net> +alias ุงุจุฑ-ุขุฑูˆุงู† ุงุจุฑ ุขุฑูˆุงู† <rain@arvancloud.com> +alias guillermo-brandcrowd Guillermo Conde BrandCrowd <g.c@hello.brandcrowd.com> +alias oracle-events Oracle Database World Events <replies@oracle-mail.com> +alias internet-club Internet Chess Club <iccnews@news.chessclub.com> +alias red-hat Red Hat <email@engage.redhat.com> +alias felix-esq Felix Mazie Esq <philippeattohesq3@gmail.com> +alias quentin-rameau Quentin Rameau <quinq@fifth.space> +alias mehdi-sadeghi Mehdi Sadeghi <mehdi@mehdix.org> +alias PussyTorrents.org <mailer@torrentleech.org> 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="me@mahdi.pw" +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://me@mahdi.pw@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://me@mahdi.pw@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 = 'me@mahdi.pw' + +# 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="me@mahdym.ir" +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://me@mahdym.ir" +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 = 'your@gpgemailaddre.ss' + +# 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 <morhetz@gmail.com> +! 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 <development@arcticicestudio.com> +! Copyright (c) 2016-present Sven Greb <code@svengreb.de> + +! 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 <anselm@garbe.ca> +ยฉ 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com> +ยฉ 2006-2007 Michaล‚ Janeczek <janeczek@gmail.com> +ยฉ 2007 Kris Maglione <jg@suckless.org> +ยฉ 2009 Gottox <gottox@s01.de> +ยฉ 2009 Markus Schnalke <meillo@marmaro.de> +ยฉ 2009 Evan Gates <evan.gates@gmail.com> +ยฉ 2010-2012 Connor Lane Smith <cls@lubutu.com> +ยฉ 2014-2022 Hiltjo Posthuma <hiltjo@codemadness.org> +ยฉ 2015-2019 Quentin Rameau <quinq@fifth.space> + +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 <eyal.seelig@gmail.com> +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 <nathanielevan@zohomail.com> +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 <mail@smlavine.com> +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 <m.mahmoudian@gmail.com> +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 <mathieu.moneyron@gmail.com> +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 <anselm@garbe.ca> +ยฉ 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 <hiltjo@codemadness.org> +ยฉ 2010-2012 Connor Lane Smith <cls@lubutu.com> +ยฉ 2011 Christoph Lohmann <20h@r-36.net> +ยฉ 2015-2016 Quentin Rameau <quinq@fifth.space> +ยฉ 2015-2016 Eric Pruitt <eric.pruitt@gmail.com> +ยฉ 2016-2017 Markus Teich <markus.teich@stusta.mhn.de> + +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 hackers@suckless.org. 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 +clientmessage(XEvent *e) +{ + XWindowAttributes wa; + XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + XReparentWindow(dpy, c->win, systray->win, 0, 0); + /* use parents background color */ + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + /* FIXME not sure if I have to send these events, too */ + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + XSync(dpy, False); + resizebarwin(selmon); + updatesystray(); + setclientstate(c, NormalState); + }