summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-03-08 15:21:28 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-03-08 15:21:28 +0900
commit4437d5b3c3eea76f6e2b0fd4a2ba21c02a098aeb (patch)
treee8dcb20bf144aacf88f93b012dccacdeb08015cd
parentc2b06f0d5795a789f4ddab459179ff89aedfee98 (diff)
updates
-rwxr-xr-xdmenu/dmenu_run2
-rw-r--r--dwm/FUNDING.yml2
-rw-r--r--dwm/LICENSE2
-rw-r--r--dwm/Makefile22
-rw-r--r--dwm/PKGBUILD44
-rw-r--r--dwm/README48
-rw-r--r--dwm/README.md35
-rw-r--r--dwm/config.def.h1099
-rw-r--r--dwm/config.mk13
-rw-r--r--dwm/drw.c772
-rw-r--r--dwm/drw.h65
-rw-r--r--dwm/dwm.1166
-rw-r--r--dwm/dwm.c5594
-rw-r--r--dwm/exresize.c10
-rwxr-xr-xdwm/layoutmenu5
-rw-r--r--dwm/patches/alwaysontop-6.2.diff109
-rw-r--r--dwm/patches/dwm-accessnthmon.diff100
-rw-r--r--dwm/patches/dwm-actualfullscreen-20211013-cb3f58a.diff67
-rw-r--r--dwm/patches/dwm-allowkillrule-6.4.diff98
-rw-r--r--dwm/patches/dwm-alpha-20230401-348f655.diff287
-rw-r--r--dwm/patches/dwm-alttab2+winview-6.4.diff217
-rw-r--r--dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff12
-rw-r--r--dwm/patches/dwm-bar-height-spacing-6.3.diff25
-rw-r--r--dwm/patches/dwm-barpadding-20211020-a786211.diff117
-rw-r--r--dwm/patches/dwm-bartoggle-keybinds-6.4.diff214
-rw-r--r--dwm/patches/dwm-borderrule-20231226-e7f651b.diff66
-rw-r--r--dwm/patches/dwm-bulkill-20231029-9f88553.diff85
-rw-r--r--dwm/patches/dwm-canfocusfloating-20210724-b914109.diff144
-rw-r--r--dwm/patches/dwm-cfacts-vanitygaps-6.4_combo.diff1018
-rw-r--r--dwm/patches/dwm-clientopacity-6.4.diff274
-rw-r--r--dwm/patches/dwm-clientresizehints-6.5.diff75
-rw-r--r--dwm/patches/dwm-colorbar-6.3.diff85
-rw-r--r--dwm/patches/dwm-exresize-r1606.diff372
-rw-r--r--dwm/patches/dwm-float-border-color-20231008-3a7ea45f.diff108
-rw-r--r--dwm/patches/dwm-floatborderwidth-6.3.diff68
-rw-r--r--dwm/patches/dwm-focusmaster-return-6.2.diff89
-rw-r--r--dwm/patches/dwm-gestures-6.4.diff126
-rw-r--r--dwm/patches/dwm-hide_vacant_tags-6.4.diff48
-rw-r--r--dwm/patches/dwm-keychord-6.4.diff234
-rw-r--r--dwm/patches/dwm-layoutmenu-6.2.diff88
-rw-r--r--dwm/patches/dwm-layoutscroll-6.2.diff67
-rw-r--r--dwm/patches/dwm-mark-new-6.2.diff247
-rw-r--r--dwm/patches/dwm-movecenter-6.5.diff41
-rw-r--r--dwm/patches/dwm-multimon-1-monitor_marker-6.4.diff194
-rw-r--r--dwm/patches/dwm-multimon-2-unified_view-6.4.diff181
-rw-r--r--dwm/patches/dwm-multimon-4-status_all-6.4.diff102
-rw-r--r--dwm/patches/dwm-multimon-6-swap_focus-6.4.diff185
-rw-r--r--dwm/patches/dwm-multimon-7-focus_on_active-6.4.diff59
-rw-r--r--dwm/patches/dwm-multiple-dynamic-scratchpads.diff207
-rw-r--r--dwm/patches/dwm-pertag_with_sel-20231003-9f88553.diff214
-rw-r--r--dwm/patches/dwm-preserveonrestart-6.3.diff118
-rw-r--r--dwm/patches/dwm-preventfocusshift-20240831-6.5.diff24
-rw-r--r--dwm/patches/dwm-refreshrate-20230826-9554a10.diff55
-rw-r--r--dwm/patches/dwm-resetlayout-6.2.diff64
-rw-r--r--dwm/patches/dwm-resetnmaster-pertag-6.3.diff36
-rw-r--r--dwm/patches/dwm-resizehere-20230824-e81f17d.diff60
-rw-r--r--dwm/patches/dwm-restartsig-20180523-6.2.diff138
-rw-r--r--dwm/patches/dwm-scratchpads-20200414-728d397b.diff198
-rw-r--r--dwm/patches/dwm-sendmoncenter-20210805-138b405f.diff27
-rw-r--r--dwm/patches/dwm-setborderpx-6.2.diff90
-rw-r--r--dwm/patches/dwm-shift-tools-6.2.diff55
-rw-r--r--dwm/patches/dwm-showselmon-6.2.diff46
-rw-r--r--dwm/patches/dwm-spawntag-6.2.diff84
-rw-r--r--dwm/patches/dwm-stacker-6.2.diff196
-rw-r--r--dwm/patches/dwm-stairs-fullgaps-20220430-8b48e30.diff98
-rw-r--r--dwm/patches/dwm-statuscmd-20241009-8933ebc.diff219
-rw-r--r--dwm/patches/dwm-sticky-6.5.diff145
-rw-r--r--dwm/patches/dwm-stickyindicator-6.2.diff65
-rw-r--r--dwm/patches/dwm-swallow-6.3.diff410
-rw-r--r--dwm/patches/dwm-switchallmonitortags-6.3.diff62
-rw-r--r--dwm/patches/dwm-taglabels-hide_vacant_tags_funcionality-6.2.diff91
-rw-r--r--dwm/patches/dwm-tiledmove-20231210-b731.diff82
-rw-r--r--dwm/patches/dwm-toggleallmonspertag-6.4.diff74
-rw-r--r--dwm/patches/dwm-toggleborder-6.3.diff52
-rw-r--r--dwm/patches/dwm-togglefloatingcenter-20210806-138b405f.diff30
-rw-r--r--dwm/patches/dwm-toggletopbar-barpadding-6.4.diff43
-rw-r--r--dwm/patches/dwm-unicode_ellipsis-20222909-d3f93c7.diff22
-rw-r--r--dwm/patches/dwm-xresources-20210827-138b405.diff239
-rw-r--r--dwm/patches/dwmblocks-statuscmd-20210402-96cbb45.diff126
-rw-r--r--dwm/shift-tools-scratchpads.c7
-rw-r--r--dwm/tagandview.c4
-rw-r--r--dwm/thesiah-default.mom188
-rw-r--r--dwm/unpatched/dwm-preview-all-windows-6.5.diff287
-rw-r--r--dwm/unpatched/dwm-tag-preview-6.3.diff314
-rw-r--r--dwm/util.c13
-rw-r--r--dwm/util.h1
-rw-r--r--dwm/vanitygaps.c1419
-rw-r--r--dwmblocks/.clang-format8
-rw-r--r--dwmblocks/.clang-tidy30
-rw-r--r--dwmblocks/.clangd5
-rw-r--r--dwmblocks/.github/FUNDING.yml4
-rw-r--r--dwmblocks/.gitignore3
-rw-r--r--dwmblocks/Makefile70
-rw-r--r--dwmblocks/README.md180
-rw-r--r--dwmblocks/config.def.h100
-rw-r--r--dwmblocks/dwmblocks.c296
-rw-r--r--dwmblocks/include/block.h29
-rw-r--r--dwmblocks/include/cli.h12
-rw-r--r--dwmblocks/include/main.h16
-rw-r--r--dwmblocks/include/signal-handler.h33
-rw-r--r--dwmblocks/include/status.h31
-rw-r--r--dwmblocks/include/timer.h21
-rw-r--r--dwmblocks/include/util.h28
-rw-r--r--dwmblocks/include/watcher.h28
-rw-r--r--dwmblocks/include/x11.h13
-rw-r--r--dwmblocks/src/block.c147
-rw-r--r--dwmblocks/src/cli.c33
-rw-r--r--dwmblocks/src/main.c168
-rw-r--r--dwmblocks/src/signal-handler.c124
-rw-r--r--dwmblocks/src/status.c78
-rw-r--r--dwmblocks/src/timer.c72
-rw-r--r--dwmblocks/src/util.c49
-rw-r--r--dwmblocks/src/watcher.c69
-rw-r--r--dwmblocks/src/x11.c44
-rw-r--r--slock/slock.c6
-rw-r--r--st/FAQ253
-rw-r--r--st/FUNDING.yml2
-rw-r--r--st/LEGACY17
-rw-r--r--st/Makefile28
-rw-r--r--st/PKGBUILD45
-rw-r--r--st/README34
-rw-r--r--st/README.md89
-rw-r--r--st/TODO28
-rw-r--r--st/Xdefaults128
-rw-r--r--st/autocomplete.h16
-rw-r--r--st/config.def.h1721
-rw-r--r--st/config.mk9
-rw-r--r--st/externalpipe_buffer.sh47
-rw-r--r--st/hb.c154
-rw-r--r--st/hb.h7
-rw-r--r--st/patches/st-anygeometry-0.8.1.diff123
-rw-r--r--st/patches/st-anysize-20220718-baa9357.diff163
-rw-r--r--st/patches/st-autocomplete-20240703-6508693.diff702
-rw-r--r--st/patches/st-blinking_cursor-20230819-3a6d6d7.diff153
-rw-r--r--st/patches/st-borderpx-option-20241008-e015463.diff74
-rw-r--r--st/patches/st-boxdraw_v2-0.8.5.diff582
-rw-r--r--st/patches/st-changealpha-20230519-b44f2ad.diff80
-rw-r--r--st/patches/st-charoffsets-20220311-0.8.5.diff43
-rw-r--r--st/patches/st-clickurl-nocontrol-0.8.5.diff214
-rw-r--r--st/patches/st-clipboard-0.8.3.diff12
-rw-r--r--st/patches/st-columnredraw-20241119-fb8569b.diff79
-rw-r--r--st/patches/st-copyurl-multiline-20230406-211964d.diff166
-rw-r--r--st/patches/st-csi_22_23-0.8.5.diff208
-rw-r--r--st/patches/st-cyclefonts-20220731-baa9357.diff97
-rw-r--r--st/patches/st-disable-bold-italic-fonts-0.8.2.diff70
-rw-r--r--st/patches/st-dynamic-cursor-color-0.9.diff50
-rw-r--r--st/patches/st-externalpipe-0.8.5.diff104
-rw-r--r--st/patches/st-externalpipe-eternal-0.8.3.diff74
-rw-r--r--st/patches/st-externalpipe-signal-0.8.2.diff74
-rw-r--r--st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff760
-rw-r--r--st/patches/st-focus-20230610-68d1ad9.diff537
-rw-r--r--st/patches/st-font2-0.8.5.diff163
-rw-r--r--st/patches/st-fullscreen-0.8.5.diff69
-rw-r--r--st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff213
-rw-r--r--st/patches/st-iso14755-0.8.5.diff89
-rw-r--r--st/patches/st-keyboard_select-20200617-9ba7ecf.diff319
-rw-r--r--st/patches/st-newterm-0.9-tabbed.diff38
-rw-r--r--st/patches/st-newterm-0.9-tmux.diff140
-rw-r--r--st/patches/st-newterm-0.9.diff112
-rw-r--r--st/patches/st-openclipboard-20220217-0.8.5.diff91
-rw-r--r--st/patches/st-scrollback-0.9.2.diff351
-rw-r--r--st/patches/st-scrollback-mouse-0.9.2.diff25
-rw-r--r--st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff78
-rw-r--r--st/patches/st-scrollback-mouse-increment-0.9.2.diff30
-rw-r--r--st/patches/st-spoiler-20180309-c5ba9c0.diff21
-rw-r--r--st/patches/st-swapmouse-0.8.4.diff37
-rw-r--r--st/patches/st-title_parsing_fix-0.8.5.diff145
-rw-r--r--st/patches/st-vertcenter-20231003-eb3b894.diff65
-rw-r--r--st/patches/st-w3m-0.8.3.diff42
-rw-r--r--st/patches/st-xclearwin-20200419-6ee7143.diff62
-rw-r--r--st/patches/st-xresources-20200604-9ba7ecf.diff183
-rw-r--r--st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff288
-rw-r--r--st/st-autocomplete310
-rw-r--r--st/st-copyout13
-rw-r--r--st/st-urlhandler19
-rw-r--r--st/st.178
-rw-r--r--st/st.c917
-rw-r--r--st/st.h37
-rw-r--r--st/st.info8
-rw-r--r--st/unpatched/st-color_schemes-20220615-baa9357.diff169
-rw-r--r--st/unpatched/st-delkey-20201112-4ef0cbd.diff20
-rw-r--r--st/unpatched/st-relativeborder-0.8.3.diff39
-rw-r--r--st/unpatched/st-undercurl-0.9-20240103.diff606
-rw-r--r--st/unpatched/st-universcroll-0.8.4.diff90
-rw-r--r--st/unpatched/st-universcroll-example-0.8.4.diff47
-rw-r--r--st/win.h11
-rw-r--r--st/x.c600
187 files changed, 26233 insertions, 6616 deletions
diff --git a/dmenu/dmenu_run b/dmenu/dmenu_run
index 834ede5..b1bd32f 100755
--- a/dmenu/dmenu_run
+++ b/dmenu/dmenu_run
@@ -1,2 +1,2 @@
#!/bin/sh
-dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
+dmenu_path | dmenu -i "$@" | ${SHELL:-"/bin/sh"} &
diff --git a/dwm/FUNDING.yml b/dwm/FUNDING.yml
deleted file mode 100644
index c7c9a22..0000000
--- a/dwm/FUNDING.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-custom: ["https://lukesmith.xyz/donate.html"]
-github: lukesmithxyz
diff --git a/dwm/LICENSE b/dwm/LICENSE
index 1e1b5a4..995172f 100644
--- a/dwm/LICENSE
+++ b/dwm/LICENSE
@@ -17,7 +17,7 @@ MIT/X Consortium License
© 2015-2016 Quentin Rameau <quinq@fifth.space>
© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
-© 2019-2020 Luke Smith <luke@lukesmith.xyz>
+© 2020-2022 Chris Down <chris@chrisdown.name>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/dwm/Makefile b/dwm/Makefile
index bc6161e..a9213e7 100644
--- a/dwm/Makefile
+++ b/dwm/Makefile
@@ -6,13 +6,7 @@ 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}"
+all: dwm
.c.o:
${CC} -c ${CFLAGS} $<
@@ -26,7 +20,7 @@ dwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
- rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz *.orig *.rej
+ rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
@@ -38,19 +32,17 @@ dist: clean
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
- install -Dm755 ./dwm ${DESTDIR}${PREFIX}/bin
+ cp -f dwm ${DESTDIR}${PREFIX}/bin
cp -f layoutmenu $(DESTDIR)$(PREFIX)/bin
- chmod 755 $(DESTDIR)$(PREFIX)/bin/layoutmenu
+ 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
- mkdir -p ${DESTDIR}${PREFIX}/share/dwm
- install -Dm644 ./thesiah.mom ${DESTDIR}${PREFIX}/share/dwm
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
+ ${DESTDIR}${MANPREFIX}/man1/dwm.1\
$(DESTDIR)$(PREFIX)/bin/layoutmenu\
- ${DESTDIR}${PREFIX}/share/dwm/thesiah.mom\
- ${DESTDIR}${MANPREFIX}/man1/dwm.1
+ ${DESTDIR}${PREFIX}/share/dwm/thesiah.mom
-.PHONY: all options clean dist install uninstall
+.PHONY: all clean dist install uninstall
diff --git a/dwm/PKGBUILD b/dwm/PKGBUILD
deleted file mode 100644
index 91681ef..0000000
--- a/dwm/PKGBUILD
+++ /dev/null
@@ -1,44 +0,0 @@
-_pkgname=dwm
-pkgname=$_pkgname-thesiah-git
-pkgver=6.2.r1888.0ac09e0
-pkgrel=1
-pkgdesc="Soomin's build of dwm"
-url=https://github.com/TheSiahxyz/suckless/tree/main/dwm
-arch=(i686 x86_64)
-license=(MIT)
-makedepends=(git)
-depends=(freetype2 libx11 libxft)
-optdepends=(
- 'dmenu: program launcher'
- 'st: terminal emulator')
-provides=($_pkgname)
-conflicts=($_pkgname)
-source=(git+https://github.com/TheSiahxyz/suckless/tree/main/dwm)
-sha256sums=('SKIP')
-
-pkgver() {
- cd "$_pkgname"
- echo "$(awk '/^VERSION =/ {print $3}' config.mk)".r"$(git rev-list --count HEAD)"."$(git rev-parse --short HEAD)"
-}
-
-prepare() {
- cd "$_pkgname"
- echo "CPPFLAGS+=${CPPFLAGS}" >>config.mk
- echo "CFLAGS+=${CFLAGS}" >>config.mk
- echo "LDFLAGS+=${LDFLAGS}" >>config.mk
- # to use a custom config.h, place it in the package directory
- if [[ -f ${SRCDEST}/config.h ]]; then
- cp "${SRCDEST}/config.h" .
- fi
-}
-
-build() {
- cd "$_pkgname"
- make X11INC=/usr/include/X11 X11LIB=/usr/lib/X11
-}
-
-package() {
- cd "$_pkgname"
- make PREFIX=/usr DESTDIR="$pkgdir" install
- install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
-}
diff --git a/dwm/README b/dwm/README
new file mode 100644
index 0000000..95d4fd0
--- /dev/null
+++ b/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/dwm/README.md b/dwm/README.md
deleted file mode 100644
index 29db5e8..0000000
--- a/dwm/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# SI's build of dwm
-
-## FAQ
-
-> What are the bindings?
-
-This is suckless, mmmbud, the source code is the documentation! Check out [config.h](config.h).
-
-Okay, okay, actually I keep a readme in `thesiah.mom` for my whole system, including the binds here.
-Press <kbd>super+F1</kbd> to view it in dwm (zathura is required for that binding).
-I haven't kept `man dwm`/`dwm.1` updated though. PRs welcome on that, lol.
-
-## Patches and features
-
-- [Clickable statusbar](https://dwm.suckless.org/patches/statuscmd/) with my build of [dwmblocks](https://github.com/lukesmithxyz/dwmblocks).
-- Reads [xresources](https://dwm.suckless.org/patches/xresources/) colors/variables (i.e. works with `pywal`, etc.).
-- scratchpad: Accessible with <kbd>mod+shift+enter</kbd>.
-- New layouts: bstack, fibonacci, deck, centered master and more. All bound to keys <kbd>super+(shift+)t/y/u/i</kbd>.
-- True fullscreen (<kbd>super+f</kbd>) and prevents focus shifting.
-- Windows can be made sticky (<kbd>super+s</kbd>).
-- [hide vacant tags](https://dwm.suckless.org/patches/hide_vacant_tags/) hides tags with no windows.
-- [stacker](https://dwm.suckless.org/patches/stacker/): Move windows up the stack manually (<kbd>super-K/J</kbd>).
-- [shiftview](https://dwm.suckless.org/patches/nextprev/): Cycle through tags (<kbd>super+g/;</kbd>).
-- [vanitygaps](https://dwm.suckless.org/patches/vanitygaps/): Gaps allowed across all layouts.
-- [swallow patch](https://dwm.suckless.org/patches/swallow/): if a program run from a terminal would make it inoperable, it temporarily takes its place to save space.
-
-## Installation for newbs
-
-```bash
-git clone https://github.com/TheSiahxyz/suckless.git
-cd suckless/dwm
-sudo make install
-```
-
-There is also a `PKGBUILD` usable on distributions with pacman. Run `makepkg -si` instead of `sudo make install`.
diff --git a/dwm/config.def.h b/dwm/config.def.h
index 3207708..ef7dc4d 100644
--- a/dwm/config.def.h
+++ b/dwm/config.def.h
@@ -1,106 +1,160 @@
/* See LICENSE file for copyright and license details. */
-/* constants */
-#define TERMINAL "st"
-#define TERMCLASS "St"
#define BROWSER "firefox"
#define BROWSERCLASS "Firefox"
+#define CLEAR 0x00U
#define GAP 8
#define PADDING 0
+#define STATUSBAR "dwmblocks"
+#define TERMINAL "st"
+#define TERMCLASS "St"
/* appearance */
-static unsigned int borderpx = 3; /* border pixel of windows */
-static unsigned int snap = 32; /* snap pixel */
-static unsigned int gappih = GAP; /* horiz inner gap between windows */
-static unsigned int gappiv = GAP; /* vert inner gap between windows */
-static unsigned int gappoh = GAP; /* horiz outer gap between windows and screen edge */
-static unsigned int gappov = GAP; /* vert outer gap between windows and screen edge */
-static int swallowfloating = 0; /* 1 means swallow floating windows by default */
-static int smartgaps = 0; /* 1 means no outer gap when there is only one window */
-static int showbar = 1; /* 0 means no bar */
-static int topbar = 1; /* 0 means bottom bar */
+static const double activeopacity = 1.0f; /* Window opacity when it's focused (0 <= opacity <= 1) */
+static const double inactiveopacity = 1.0f; /* Window opacity when it's inactive (0 <= opacity <= 1) */
static const int allowkill = 1; /* allow killing clients by default? */
-static const int vertpad = PADDING; /* vertical padding of bar */
+static int alt_tab_direction = 1; /* 1 means cycle forward */
+static int showbar = 1; /* 0 means no bar */
+static const int showfloating = 1; /* 0 means no floating indicator */
+static const int showlayout = 1; /* 0 means no layout indicator */
+static const int showstatus = 1; /* 0 means no status bar */
+static const int showtitle = 1; /* 0 means no title */
+static const int showtags = 1; /* 0 means no tags */
static const int sidepad = PADDING; /* horizontal padding of bar */
-static const char *barlayout = "tln|s"; /* t: tag, l: layout, n: name, s: status */
-static const unsigned int ulinepad = 5; /* horizontal padding between the underline and tag */
-static const unsigned int ulinestroke = 2; /* thickness / height of the underline */
-static const unsigned int ulinevoffset = 0; /* how far above the bottom of the bar the line should appear */
-static const int ulineall = 0; /* 1 to show underline on all tags, 0 for just the active ones */
-
-static char *fonts[] = {
- "monospace:size=10",
- "NotoColorEmoji:pixelsize=10:antialias=true:autohint=true"
+static int smartgaps = 0; /* 1 means no outer gap when there is only one window */
+static const int stairdirection = 1; /* 0: left-aligned, 1: right-aligned */
+static const int stairsamesize = 1; /* 1 means shrink all the staired windows to the same size */
+static const int statusall = 1; /* 1 means status is shown in all bars, not just active monitor */
+static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
+static int topbar = 1; /* 0 means bottom bar */
+static const int user_bh = 2; /* 2 is the default spacing around the bar's font */
+static const int vertpad = PADDING; /* vertical padding of bar */
+static const unsigned int baralpha = 0xc8;
+static const unsigned int borderalpha = OPAQUE;
+static const unsigned int floatalpha = OPAQUE;
+static const unsigned int markalpha = OPAQUE;
+static unsigned int borderpx = 4; /* border pixel of windows */
+static const unsigned int fborderpx = 6; /* border pixel of floating windows */
+static const unsigned int gappih = GAP; /* horiz inner gap between windows */
+static const unsigned int gappiv = GAP; /* vert inner gap between windows */
+static const unsigned int gappoh = GAP; /* horiz outer gap between windows and screen edge */
+static const unsigned int gappov = GAP; /* vert outer gap between windows and screen edge */
+static unsigned int snap = 32; /* snap pixel */
+static const unsigned int stairpx = 20; /* depth of the stairs layout */
+static const unsigned int tabModKey = 0x40;
+static const unsigned int tabCycleKey = 0x17;
+static char dmenufont[] = "monospace:size=10";
+static char font[] = "monospace:size=10";
+static const char *fonts[] = {
+ font,
+ "NotoColorEmoji:pixelsize=10:antialias=true:autohint=true",
};
-static const unsigned int baralpha = 0xd0;
-static const unsigned int borderalpha = OPAQUE;
-static char normbgcolor[] = "#222222";
-static char normbordercolor[] = "#444444";
-static char normfgcolor[] = "#bbbbbb";
-static char normmarkcolor[] = "#009900"; /*border color for marked client*/
-static char selfgcolor[] = "#eeeeee";
-static char selbgcolor[] = "#005577";
-static char selbordercolor[] = "#770000";
-static char selmarkcolor[] = "#00CC00"; /*border color for marked client on focus*/
-static char *colors[][4] = {
- /* fg bg border mark */
- [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normmarkcolor },
- [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selmarkcolor },
+static char normbgcolor[] = "#222222";
+static char normbordercolor[] = "#444444";
+static char normfgcolor[] = "#bbbbbb";
+static char normfloatcolor[] = "#330000";
+static char normmarkcolor[] = "#b16286";
+static char norminfobgcolor[] = "#222222";
+static char norminfofgcolor[] = "#f8f8f2";
+static char normstatusbgcolor[] = "#222222";
+static char normstatusfgcolor[] = "#eeeeee";
+static char normtagbgcolor[] = "#222222";
+static char normtagfgcolor[] = "#cccccc";
+static char selbgcolor[] = "#005577";
+static char selbordercolor[] = "#770000";
+static char selfgcolor[] = "#eeeeee";
+static char selfloatcolor[] = "#770000";
+static char selmarkcolor[] = "#770000";
+static char selinfobgcolor[] = "#005577";
+static char selinfofgcolor[] = "#eeeeee";
+static char selstatusbgcolor[] = "#222222";
+static char selstatusfgcolor[] = "#eeeeee";
+static char seltagbgcolor[] = "#005577";
+static char seltagfgcolor[] = "#ffffff";
+
+static char *colors[][5] = {
+ /* fg bg border float mark */
+ [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor, normmarkcolor },
+ [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor, selmarkcolor },
+ [SchemeInv] = { normbgcolor, normfgcolor, normbordercolor, normfloatcolor, normmarkcolor },
+ [SchemeStatusNorm] = { normstatusfgcolor, normstatusbgcolor, normbordercolor, normfloatcolor, normmarkcolor }, // Statusbar right unselected {text,background,not used but cannot be empty}
+ [SchemeStatusSel] = { selstatusfgcolor, selstatusbgcolor, selbordercolor, selfloatcolor, selmarkcolor }, // Statusbar right selected {text,background,not used but cannot be empty}
+ [SchemeTagsNorm] = { normtagfgcolor, normtagbgcolor, normbordercolor, normfloatcolor, normmarkcolor }, // Tagbar left unselected {text,background,not used but cannot be empty}
+ [SchemeTagsSel] = { seltagfgcolor, seltagbgcolor, selbordercolor, selfloatcolor, selmarkcolor }, // Tagbar left selected {text,background,not used but cannot be empty}
+ [SchemeInfoNorm] = { norminfofgcolor, norminfobgcolor, normbordercolor, normfloatcolor, normmarkcolor }, // infobar middle unselected {text,background,not used but cannot be empty}
+ [SchemeInfoSel] = { selinfofgcolor, selinfobgcolor, selbordercolor, selfloatcolor, selmarkcolor }, // infobar middle selected {text,background,not used but cannot be empty}
};
-static const unsigned int alphas[][3] = {
- /* fg bg border */
- [SchemeNorm] = { OPAQUE, baralpha, borderalpha },
- [SchemeSel] = { OPAQUE, baralpha, borderalpha },
+static const unsigned int alphas[][5] = {
+ /* fg bg border float mark */
+ [SchemeNorm] = { OPAQUE, baralpha, borderalpha, floatalpha, markalpha },
+ [SchemeSel] = { OPAQUE, baralpha, borderalpha, floatalpha, markalpha },
+ [SchemeInv] = { CLEAR, CLEAR, CLEAR, CLEAR, CLEAR },
+ [SchemeStatusNorm] = { OPAQUE, CLEAR, CLEAR, CLEAR, CLEAR },
+ [SchemeStatusSel] = { OPAQUE, baralpha, borderalpha, floatalpha, markalpha },
+ [SchemeTagsNorm] = { OPAQUE, CLEAR, CLEAR, CLEAR, CLEAR },
+ [SchemeTagsSel] = { OPAQUE, baralpha, borderalpha, floatalpha, markalpha },
+ [SchemeInfoNorm] = { OPAQUE, CLEAR, CLEAR, CLEAR, CLEAR },
+ [SchemeInfoSel] = { OPAQUE, baralpha, borderalpha, floatalpha, markalpha },
};
+static const XPoint stickyicon[] = { {0,0}, {4,0}, {4,8}, {2,6}, {0,8}, {0,0} }; /* represents the icon as an array of vertices */
+static const XPoint stickyiconbb = {4,8}; /* defines the bottom right corner of the polygon's bounding box (speeds up scaling) */
+
typedef struct {
- const char *name;
- const void *cmd;
+ const char *name;
+ const void *cmd;
} Sp;
-
-/* scratchpads */
-const char *spcmd1[] = { TERMINAL, "-n", "spterm", "-g", "120x34", NULL }; /* Terminal */
-const char *spcmd2[] = { TERMINAL, "-n", "spcalc", "-f", "monospace:size=16", /* Calculator */
- "-g", "50x20", "-e", "bc", "-lq", NULL };
+const char *spcmd1[] = { TERMINAL, "-n", "spterm", "-g", "120x34", NULL };
+const char *spcmd2[] = { TERMINAL, "-n", "splf", "-g", "144x41", "-e", "lf", NULL };
+const char *spcmd3[] = { TERMINAL, "-n", "spcalc", "-f", "monospace:size=16", "-g", "50x20", "-e", "bc", "-lq", NULL };
+const char *spcmd4[] = { "keepassxc", NULL };
static Sp scratchpads[] = {
- /* name cmd */
- { "spterm", spcmd1 },
- { "spcalc", spcmd2 },
+ /* name cmd */
+ {"spterm", spcmd1},
+ {"splf", spcmd2},
+ {"spcalc", spcmd3},
+ {"keepassxc", spcmd4},
};
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+static const char ptagf[] = "%s. %s"; /* format of a tag label */
+static const char etagf[] = "%s"; /* format of an empty tag */
+static const int taglbl = 0; /* 1 means enable tag label */
+static const int lcaselbl = 0; /* 1 means make tag label lowercase */
+
static const Rule rules[] = {
- /* xprop(1):
- * WM_CLASS(STRING) = instance, class
- * WM_NAME(STRING) = title
- */
- /* class instance title tags mask allowkill isfloating isterminal noswallow monitor */
- { "Gimp", NULL, NULL, 1 << 7, 1, 1, 0, 0, -1 },
- { "kakaotalk", NULL, NULL, 1 << 8, 1, 0, 0, 0, -1 },
- // { "sooptvstreamer", NULL, NULL, 1 << 6, 1, 0, 0, 0, -1 },
- { BROWSERCLASS, NULL, NULL, 0, 1, 0, 0, -1, -1 },
- { TERMCLASS, NULL, NULL, 0, 1, 0, 1, 0, -1 },
- { TERMCLASS, "floatterm", NULL, 0, 1, 1, 1, 0, -1 },
- { TERMCLASS, "bg", NULL, 1 << 7, 1, 0, 1, 0, -1 },
- { TERMCLASS, "spterm", NULL, SPTAG(0), 1, 1, 1, 0, -1 },
- { TERMCLASS, "spcalc", NULL, SPTAG(1), 1, 1, 1, 0, -1 },
- { NULL, NULL, "Event Tester", 0, 1, 0, 0, 1, -1 },
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+ /* class instance title tags mask allowkill focusopacity unfocusopacity isfloating isterminal noswallow monitor resizehints border width */
+ { "Gimp", NULL, NULL, 1 << 7, 1, 1.0, inactiveopacity, 1, 0, 0, -1, 1, -1 },
+ { TERMCLASS, NULL, NULL, 0, 1, activeopacity, inactiveopacity, 0, 1, 0, -1, 0, -1 },
+ { BROWSERCLASS, NULL, NULL, 0, 1, activeopacity, inactiveopacity, 0, 0, -1, -1, 1, -1 },
+ { "kakaotalk", NULL, NULL, 1 << 8, 1, activeopacity, inactiveopacity, 0, 0, -1, -1, 0, 0 },
+ { NULL, "spterm", NULL, SPTAG(0), 1, activeopacity, inactiveopacity, 1, 0, 0, -1, 1, -1 },
+ { NULL, "spfm", NULL, SPTAG(1), 1, activeopacity, inactiveopacity, 1, 0, 0, -1, 1, -1 },
+ { NULL, "keepassxc", NULL, SPTAG(2), 1, activeopacity, inactiveopacity, 0, 0, 0, -1, 1, -1 },
+ { NULL, NULL, "Event Tester", 0, 1, activeopacity, inactiveopacity, 0, 0, 1, -1, 1, -1 }, /* xev */
};
/* layout(s) */
-static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
-static int nmaster = 1; /* number of clients in master area */
-static int resizehints = 0; /* 1 means respect size hints in tiled resizals */
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+static int nmaster = 1; /* number of clients in master area */
+static int resizehints = 0; /* 1 means respect size hints in tiled resizals */
+static const int lockfullscreen = 0; /* 1 will force focus on the fullscreen window */
-#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
+#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
+#include <X11/XF86keysym.h>
+#include "exresize.c"
+#include "shift-tools-scratchpads.c"
#include "vanitygaps.c"
static const Layout layouts[] = {
- /* symbol arrange function */
+ /* symbol arrange function */
{ "[]=", tile }, /* 0: Default: Master on left, slaves on right */
{ "[M]", monocle }, /* 1: All windows on top of eachother */
{ "|||", col }, /* 2: Column */
@@ -115,91 +169,65 @@ static const Layout layouts[] = {
{ ":::", gaplessgrid }, /* 11: Gapless grid */
{ "|M|", centeredmaster }, /* 12: Master in middle, slaves on sides */
{ ">M>", centeredfloatingmaster }, /* 13: Same but master floats */
- { "><>", NULL }, /* 14: no layout function means floating behavior */
+ { "[S]", stairs }, /* 14: Stairs */
+ { "><>", NULL }, /* 15: no layout function means floating behavior */
};
-/* imports */
-#include <X11/XF86keysym.h>
-#include "shift-tools-scratchpads.c"
-#include "tagandview.c"
-#include "exresize.c"
-
/* key definitions */
-#define MODKEY Mod4Mask
-#define MODKEY2 Mod1Mask
-#define WINMOD (MODKEY | ShiftMask)
-#define WINMOD2 (MODKEY | ControlMask)
-#define ULTRAMOD (MODKEY | ControlMask | ShiftMask)
-#define TERMMOD (MODKEY2 | ShiftMask)
-#define TERMMOD2 (MODKEY2 | ControlMask)
-#define ULTRAMOD2 (MODKEY2 | ControlMask | ShiftMask)
-#define EXTRAMOD (ControlMask | ShiftMask)
-
-#define TAGKEYS(KEY, TAG) \
- { MODKEY, KEY, view, { .ui = 1 << TAG } }, \
- { WINMOD2, KEY, toggleview, { .ui = 1 << TAG } }, \
- { WINMOD, KEY, tag, { .ui = 1 << TAG } }, \
- { ULTRAMOD, KEY, toggletag, { .ui = 1 << TAG } }, \
- { TERMMOD, KEY, tagandview, { .ui = 1 << TAG } },
-
-#define CTAGKEYS(KEY, TAG) \
- { {0,0,0,0}, {KEY,0,0,0}, view, { .ui = 1 << TAG} }, \
- { {ControlMask,0,0,0}, {KEY,0,0,0}, toggleview, { .ui = 1 << TAG} }, \
- { {ShiftMask,0,0,0}, {KEY,0,0,0}, tag, { .ui = 1 << TAG} }, \
- { {EXTRAMOD,0,0,0}, {KEY,0,0,0}, toggletag, { .ui = 1 << TAG} },
-
-#define STACKKEYS(MOD, ACTION) \
- { MOD, XK_j, ACTION##stack, { .i = INC(+1) } }, \
- { MOD, XK_k, ACTION##stack, { .i = INC(-1) } }, \
- { MOD, XK_Tab, ACTION##stack, { .i = PREVSEL } }, \
- { MOD, XK_space, ACTION##stack, { .i = 0 } }, \
- { MOD, XK_a, ACTION##stack, { .i = 1 } }, \
- { MOD, XK_z, ACTION##stack, { .i = -1 } },
-
-#define CSTACKKEYS(MOD, ACTION) \
- { {MOD,0,0,0}, {XK_j, 0,0,0}, ACTION##stack, { .i = INC(+1) } }, \
- { {MOD,0,0,0}, {XK_k, 0,0,0}, ACTION##stack, { .i = INC(-1) } }, \
- { {MOD,0,0,0}, {XK_Tab, 0,0,0}, ACTION##stack, { .i = PREVSEL } }, \
- { {MOD,0,0,0}, {XK_space, 0,0,0}, ACTION##stack, { .i = 0 } }, \
- { {MOD,0,0,0}, {XK_a, 0,0,0}, ACTION##stack, { .i = 1 } }, \
- { {MOD,0,0,0}, {XK_z, 0,0,0}, ACTION##stack, { .i = -1 } },
+#define WINKEY Mod4Mask
+#define WINMOD (WINKEY | ShiftMask)
+#define WINMOD2 (WINKEY | ControlMask)
+#define WINMODALL (WINKEY | ControlMask | ShiftMask)
+#define ALTKEY Mod1Mask
+#define ALTMOD (ALTKEY | ShiftMask)
+#define ALTMOD2 (ALTKEY | ControlMask)
+#define ALTMODALL (ALTKEY | ControlMask | ShiftMask)
+#define ULTRAKEY (WINKEY | ALTKEY)
+#define ULTRAMOD (WINKEY | ALTKEY | ShiftMask)
+#define ULTRAMOD2 (WINKEY | ALTKEY | ControlMask)
+#define ULTRAMODALL (WINKEY | ALTKEY | ControlMask)
+#define EXTRAMOD (ControlMask | ShiftMask)
+#define TAGKEYS(KEY,TAG) \
+ &((Keychord){1, {{WINKEY, KEY}}, view, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{WINMOD, KEY}}, tag, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{WINMOD2, KEY}}, toggleview, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{WINMODALL, KEY}}, tagandview, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{ALTKEY, KEY}}, focusnthmon, {.i = TAG } }), \
+ &((Keychord){1, {{ALTMOD, KEY}}, tagnthmon, {.i = TAG } }), \
+ &((Keychord){1, {{ALTMOD2, KEY}}, toggletag, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{ULTRAKEY, KEY}}, nview, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{ULTRAMOD, KEY}}, viewall, {.ui = 1 << TAG} }), \
+ &((Keychord){1, {{ULTRAMOD2, KEY}}, ntoggleview, {.ui = 1 << TAG} }),
+#define STACKKEYS(MOD,ACTION) \
+ &((Keychord){1, {{MOD, XK_j}}, ACTION##stack, {.i = INC(+1) } }), \
+ &((Keychord){1, {{MOD, XK_k}}, ACTION##stack, {.i = INC(-1) } }), \
+ &((Keychord){1, {{MOD, XK_Tab}}, ACTION##stack, {.i = PREVSEL } }), \
+ &((Keychord){2, {{MOD, XK_BackSpace},{0, XK_BackSpace}}, ACTION##stack, {.i = 0 } }), \
+ &((Keychord){2, {{MOD, XK_BackSpace},{0, XK_a}}, ACTION##stack, {.i = 1 } }), \
+ &((Keychord){2, {{MOD, XK_BackSpace},{0, XK_z}}, ACTION##stack, {.i = 2 } }), \
+ &((Keychord){2, {{MOD, XK_BackSpace},{0, XK_x}}, ACTION##stack, {.i = -1 } }),
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
-#define SHCMD(cmd) { .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } }
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* helper for launching gtk application */
#define GTKCMD(cmd) { .v = (const char*[]){ "/usr/bin/gtk-launch", cmd, NULL } }
/* commands */
-// static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb",
-// normbgcolor, "-nf", normfgcolor, "-sb",
-// selbordercolor, "-sf", selfgcolor, NULL };
-static const char *termcmd[] = { TERMINAL, NULL };
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
+static const char *termcmd[] = { TERMINAL, NULL };
static const char *layoutmenu_cmd = "layoutmenu";
-
-/* Xresources preferences to load at startup */
-ResourcePref resources[] = {
- { "color0", STRING, &normbordercolor },
- { "color8", STRING, &selbordercolor },
- { "color0", STRING, &normbgcolor },
- { "color4", STRING, &normfgcolor },
- { "color0", STRING, &selfgcolor },
- { "color4", STRING, &selbgcolor },
- { "borderpx", INTEGER, &borderpx },
- { "gappih", INTEGER, &gappih },
- { "gappiv", INTEGER, &gappiv },
- { "gappoh", INTEGER, &gappoh },
- { "gappov", INTEGER, &gappov },
- { "mfact", FLOAT, &mfact },
- { "nmaster", INTEGER, &nmaster },
- { "normmarkcolor", INTEGER, &normmarkcolor },
- { "resizehints", INTEGER, &resizehints },
- { "selmarkcolor", INTEGER, &selmarkcolor },
- { "showbar", INTEGER, &showbar },
- { "smartgaps", INTEGER, &smartgaps },
- { "snap", INTEGER, &snap },
- { "swallowfloating", INTEGER, &swallowfloating },
- { "topbar", INTEGER, &topbar },
+static const Arg tagexec[] = {
+ { .v = termcmd }, // 1
+ { .v = (const char *[]){ BROWSER, NULL } }, // 2
+ SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks"), // 3
+ SHCMD(TERMINAL " -e newsboat ; pkill -RTMIN+19 dwmblocks"), // 4
+ { .v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } }, // 5
+ { .v = (const char *[]){ "torwrap", NULL } }, // 6
+ { .v = (const char *[]){ TERMINAL, "-e", "sudo", "nmtui", NULL } }, // 7
+ { .v = (const char *[]){ TERMINAL, "-e", "htop", NULL } }, // 8
+ { .v = (const char *[]){ "kakaotalk", NULL } } // 9
};
/* gestures
@@ -212,439 +240,418 @@ ResourcePref resources[] = {
static Gesture gestures[] = {
{ "u", spawn, { .v = termcmd } },
{ "d", spawn, { .v = (const char *[]){ BROWSER, NULL } } },
- { "l", spawn, SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks; rmdir ~/.abook 2>/dev/null") },
- { "r", spawn, SHCMD(TERMINAL " -e newsboat ; pkill -RTMIN+19 dwmblocks") },
+ { "l", spawn, SHCMD(TERMINAL " -e neomutt; pkill -RTMIN+20 dwmblocks; rmdir ~/.abook 2>/dev/null") },
+ { "r", spawn, SHCMD(TERMINAL " -e newsboat; pkill -RTMIN+19 dwmblocks") },
};
-static const Arg tagexec[] = {
- { .v = termcmd }, // 1
- { .v = (const char *[]){ BROWSER, NULL } }, // 2
- SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks"), // 3
- SHCMD(TERMINAL " -e newsboat ; pkill -RTMIN+19 dwmblocks"), // 4
- { .v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } }, // 5
- { .v = (const char *[]){ "torwrap", NULL } }, // 6
- { .v = (const char *[]){ TERMINAL, "-e", "sudo", "nmtui", NULL } }, // 7
- { .v = (const char *[]){ TERMINAL, "-e", "htop", NULL } }, // 8
- { .v = (const char *[]){ "kakaotalk", NULL } } // 9
+/*
+ * Xresources preferences to load at startup
+ */
+ResourcePref resources[] = {
+ { "borderpx", INTEGER, &borderpx },
+ { "dmenufont", STRING, &dmenufont },
+ { "font", STRING, &font },
+ { "mfact", FLOAT, &mfact },
+ { "nmaster", INTEGER, &nmaster },
+ { "normbgcolor", STRING, &normbgcolor },
+ { "normbordercolor", STRING, &normbordercolor },
+ { "normfgcolor", STRING, &normfgcolor },
+ { "normfloatcolor", STRING, &normfloatcolor },
+ { "normmarkcolor", STRING, &normmarkcolor },
+ { "normstatusbgcolor", STRING, &normstatusbgcolor },
+ { "normstatusfgcolor", STRING, &normstatusfgcolor },
+ { "normtagbgcolor", STRING, &normtagbgcolor },
+ { "normtagfgcolor", STRING, &normtagfgcolor },
+ { "norminfobgcolor", STRING, &norminfobgcolor },
+ { "norminfofgcolor", STRING, &norminfofgcolor },
+ { "resizehints", INTEGER, &resizehints },
+ { "selbgcolor", STRING, &selbgcolor },
+ { "selbordercolor", STRING, &selbordercolor },
+ { "selfgcolor", STRING, &selfgcolor },
+ { "selfloatcolor", STRING, &selfloatcolor },
+ { "selmarkcolor", STRING, &selmarkcolor },
+ { "seltagbgcolor", STRING, &seltagbgcolor },
+ { "seltagfgcolor", STRING, &seltagfgcolor },
+ { "selinfobgcolor", STRING, &selinfobgcolor },
+ { "selinfofgcolor", STRING, &selinfofgcolor },
+ { "showbar", INTEGER, &showbar },
+ { "snap", INTEGER, &snap },
+ { "topbar", INTEGER, &topbar },
};
-static const Key keys[] = {
+static Keychord *keychords[] = {
+ /* Num Keys Function argument */
// STACKKEYS
- STACKKEYS(MODKEY, focus)
- STACKKEYS(WINMOD, push)
+ STACKKEYS( WINKEY, focus)
+ STACKKEYS( WINMOD, push)
// TAGKEYS
- 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)
-
- /* modifier key function argument */
+ 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)
+
+ // APPEARANCE
+ &((Keychord){1, {{WINKEY, XK_a}}, changefocusopacity, {.f = +0.025}}),
+ &((Keychord){1, {{WINKEY, XK_s}}, changefocusopacity, {.f = -0.025}}),
+ &((Keychord){1, {{WINMOD, XK_a}}, changeunfocusopacity, {.f = +0.025}}),
+ &((Keychord){1, {{WINMOD, XK_s}}, changeunfocusopacity, {.f = -0.025}}),
+ &((Keychord){1, {{WINKEY, XK_o}}, setborderpx, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD, XK_o}}, setborderpx, {.i = +1 } }),
+ &((Keychord){1, {{WINMOD2, XK_o}}, setborderpx, {.i = 0 } }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_a}}, togglebartags, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_b}}, togglebar, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{ShiftMask, XK_b}}, togglebar, {.i = 1} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_o}}, toggleborder, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_f}}, togglebarfloat, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_g}}, togglegaps, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{ControlMask, XK_g}}, defaultgaps, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_l}}, togglebarlt, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_s}}, togglebarstatus, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{0, XK_t}}, togglebartitle, {0} }),
+ &((Keychord){3, {{WINKEY, XK_t},{0,XK_b},{ControlMask, XK_t}}, toggletopbar, {0} }),
+
// AUDIO CONTROLS
- { MODKEY, XK_m, spawn, SHCMD("mpc random on; mpc load entire; mpc play && sleep 1 && mpc volume 50 && pkill -RTMIN+23 dwmblocks") },
- { WINMOD, XK_m, spawn, SHCMD("mpdmenu && pkill -RTMIN+23 dwmblocks") },
- { WINMOD2, XK_m, spawn, SHCMD("mpc stop; sleep 1 && mpc repeat off && mpc random off && mpc single off && mpc consume off && mpc clear") },
- { ULTRAMOD, XK_m, spawn, { .v = (const char *[]){ "dmenudelmusic", NULL } } },
- { MODKEY, XK_p, spawn, SHCMD("mpc toggle") },
- { WINMOD, XK_p, spawn, SHCMD("mpc pause; sleep 1 && pauseallmpv") },
- { WINMOD2, XK_p, spawn, SHCMD("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; sleep 1 && kill -39 $(pidof dwmblocks)") },
- { MODKEY, XK_comma, spawn, { .v = (const char *[]){ "mpc", "prev", NULL } } },
- { MODKEY, XK_period, spawn, { .v = (const char *[]){ "mpc", "next", NULL } } },
- { WINMOD, XK_comma, spawn, { .v = (const char *[]){ "mpc", "seek", "-10", NULL } } },
- { WINMOD, XK_period, spawn, { .v = (const char *[]){ "mpc", "seek", "+10", NULL } } },
- { WINMOD2, XK_comma, spawn, { .v = (const char *[]){ "mpc", "seek", "-60", NULL } } },
- { WINMOD2, XK_period, spawn, { .v = (const char *[]){ "mpc", "seek", "+60", NULL } } },
- { ULTRAMOD, XK_comma, spawn, { .v = (const char *[]){ "mpc", "seek", "0%", NULL } } },
- { ULTRAMOD, XK_period, spawn, { .v = (const char *[]){ "mpc", "seek", "90%", NULL } } },
- { MODKEY , XK_slash, spawn, SHCMD("mpc single on; mpc random on; mpc repeat on") },
- { WINMOD, XK_slash, spawn, SHCMD("mpc single off; mpc random on; mpc repeat on") },
- { WINMOD2, XK_slash, spawn, SHCMD("mpc repeat off; mpc random off; mpc single off") },
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_d}}, spawn, SHCMD("mpdmenu && pkill -RTMIN+23 dwmblocks") }),
+ &((Keychord){2, {{WINKEY, XK_m},{ShiftMask, XK_d}}, spawn, {.v = (const char *[]){ "dmenudelmusic", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_m}}, spawn, SHCMD("mpc random on; mpc load entire; mpc play && sleep 1 && mpc volume 50 && pkill -RTMIN+23 dwmblocks") }),
+ &((Keychord){2, {{WINKEY, XK_m},{ShiftMask, XK_m}}, spawn, SHCMD("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; sleep 1 && kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_o}}, spawn, SHCMD("mpc repeat off; mpc random off; mpc single off") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_p}}, spawn, SHCMD("mpc pause; sleep 1 && pauseallmpv") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_r}}, spawn, SHCMD("mpc single off; mpc random on; mpc repeat on") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_s}}, spawn, SHCMD("mpc single on; mpc random on; mpc repeat on") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_t}}, spawn, SHCMD("mpc toggle") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_x}}, spawn, SHCMD("mpc stop; sleep 1 && mpc repeat off && mpc random off && mpc single off && mpc consume off && mpc clear") }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_comma}}, spawn, {.v = (const char *[]){ "mpc", "prev", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_period}}, spawn, {.v = (const char *[]){ "mpc", "next", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{ShiftMask, XK_comma}}, spawn, {.v = (const char *[]){ "mpc", "seek", "-10", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{ShiftMask, XK_period}}, spawn, {.v = (const char *[]){ "mpc", "seek", "+10", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{ControlMask, XK_comma}}, spawn, {.v = (const char *[]){ "mpc", "seek", "-60", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{ControlMask, XK_period}}, spawn, {.v = (const char *[]){ "mpc", "seek", "+60", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_bracketleft}}, spawn, {.v = (const char *[]){ "mpc", "seek", "0%", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_m},{0, XK_bracketright}}, spawn, {.v = (const char *[]){ "mpc", "seek", "90%", NULL } } }),
// FLOATING POSITIONS
- { ULTRAMOD2, XK_u, explace, { .ui = EX_NW } },
- { ULTRAMOD2, XK_i, explace, { .ui = EX_N } },
- { ULTRAMOD2, XK_o, explace, { .ui = EX_NE } },
- { ULTRAMOD2, XK_j, explace, { .ui = EX_W } },
- { ULTRAMOD2, XK_k, explace, { .ui = EX_C } },
- { ULTRAMOD2, XK_l, explace, { .ui = EX_E } },
- { ULTRAMOD2, XK_m, explace, { .ui = EX_SW } },
- { ULTRAMOD2, XK_comma, explace, { .ui = EX_S } },
- { ULTRAMOD2, XK_period, explace, { .ui = EX_SE } },
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_c}}, movecenter, {0} }),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_m}}, explace, {.ui = EX_SW }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_comma}}, explace, {.ui = EX_S }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_period}}, explace, {.ui = EX_SE }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_j}}, explace, {.ui = EX_W }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_k}}, explace, {.ui = EX_C }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_l}}, explace, {.ui = EX_E }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_u}}, explace, {.ui = EX_NW }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_i}}, explace, {.ui = EX_N }}),
+ &((Keychord){2, {{WINKEY, XK_f},{0, XK_o}}, explace, {.ui = EX_NE }}),
// FLOATING SIZES
- { TERMMOD2, XK_h, exresize, { .v = (int []){ -25, 0 } } },
- { TERMMOD2, XK_l, exresize, { .v = (int []){ 25, 0 } } },
- { TERMMOD2, XK_j, exresize, { .v = (int []){ 0, 25 } } },
- { TERMMOD2, XK_k, exresize, { .v = (int []){ 0, -25 } } },
- { TERMMOD2, XK_comma, exresize, { .v = (int []){ -25, -25 } } },
- { TERMMOD2, XK_period, exresize, { .v = (int []){ 25, 25 } } },
+ &((Keychord){1, {{ALTKEY, XK_Down}}, exresize, {.v = (int []){ 0, -25 }}}),
+ &((Keychord){1, {{ALTKEY, XK_Left}}, exresize, {.v = (int []){ -25, 0 }}}),
+ &((Keychord){1, {{ALTKEY, XK_Begin}}, exresize, {.v = (int []){ 25, 25 }}}),
+ &((Keychord){1, {{ALTMOD, XK_Begin}}, exresize, {.v = (int []){ -25, -25 }}}),
+ &((Keychord){1, {{ALTKEY, XK_Right}}, exresize, {.v = (int []){ 25, 0 }}}),
+ &((Keychord){1, {{ALTKEY, XK_Up}}, exresize, {.v = (int []){ 0, 25 }}}),
+ &((Keychord){1, {{ALTKEY, XK_End}}, toggleverticalexpand, {.i = 0} }),
+ &((Keychord){1, {{ALTKEY, XK_Down}}, toggleverticalexpand, {.i = -1} }),
+ &((Keychord){1, {{ALTKEY, XK_Next}}, togglehorizontalexpand, {.i = 0} }),
+ &((Keychord){1, {{ALTKEY, XK_Left}}, togglehorizontalexpand, {.i = -1} }),
+ &((Keychord){1, {{ALTKEY, XK_Begin}}, togglemaximize, {.i = 0} }),
+ &((Keychord){1, {{ALTKEY, XK_Right}}, togglehorizontalexpand, {.i = +1} }),
+ &((Keychord){1, {{ALTKEY, XK_Home}}, togglemaximize, {.i = +1} }),
+ &((Keychord){1, {{ALTKEY, XK_Up}}, toggleverticalexpand, {.i = +1} }),
+ &((Keychord){1, {{ALTKEY, XK_Prior}}, togglemaximize, {.i = -1} }),
// LAYOUTS
- { MODKEY, XK_f, togglefullscr, {0} },
- { WINMOD2, XK_f, togglefloating, {0} },
- { WINMOD, XK_h, layoutscroll, { .i = -1 } },
- { WINMOD, XK_l, layoutscroll, { .i = +1 } },
- { WINMOD2, XK_s, togglesticky, {0} },
- { EXTRAMOD, XK_grave, setlayout, { .v = &layouts[0] } },
- { EXTRAMOD, XK_1, setlayout, { .v = &layouts[1] } },
- { EXTRAMOD, XK_2, setlayout, { .v = &layouts[2] } },
- { EXTRAMOD, XK_3, setlayout, { .v = &layouts[3] } },
- { EXTRAMOD, XK_4, setlayout, { .v = &layouts[4] } },
- { EXTRAMOD, XK_5, setlayout, { .v = &layouts[5] } },
- { EXTRAMOD, XK_6, setlayout, { .v = &layouts[6] } },
- { EXTRAMOD, XK_7, setlayout, { .v = &layouts[7] } },
- { EXTRAMOD, XK_8, setlayout, { .v = &layouts[8] } },
- { EXTRAMOD, XK_9, setlayout, { .v = &layouts[9] } },
- { EXTRAMOD, XK_0, setlayout, { .v = &layouts[10] } },
- { EXTRAMOD, XK_minus, setlayout, { .v = &layouts[11] } },
- { EXTRAMOD, XK_equal, setlayout, { .v = &layouts[12] } },
- { EXTRAMOD, XK_backslash, setlayout, { .v = &layouts[13] } },
+ &((Keychord){1, {{WINMOD, XK_h}}, layoutscroll, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD, XK_l}}, layoutscroll, {.i = +1 } }),
+ &((Keychord){2, {{WINMOD2, XK_l},{0, XK_r}}, resetlayout, {0} }),
+ &((Keychord){2, {{WINMOD2, XK_l},{0, XK_n}}, resetnmaster, {0} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_0}}, setlayout, {0} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_1}}, setlayout, {.v = &layouts[0]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_2}}, setlayout, {.v = &layouts[1]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_3}}, setlayout, {.v = &layouts[2]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_4}}, setlayout, {.v = &layouts[3]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_5}}, setlayout, {.v = &layouts[4]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_6}}, setlayout, {.v = &layouts[5]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_7}}, setlayout, {.v = &layouts[6]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_8}}, setlayout, {.v = &layouts[7]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_0},{0,XK_9}}, setlayout, {.v = &layouts[8]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_0}}, setlayout, {.v = &layouts[9]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_1}}, setlayout, {.v = &layouts[10]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_2}}, setlayout, {.v = &layouts[11]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_3}}, setlayout, {.v = &layouts[12]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_4}}, setlayout, {.v = &layouts[13]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_5}}, setlayout, {.v = &layouts[14]} }),
+ &((Keychord){3, {{WINMOD2, XK_l},{0, XK_1},{0,XK_6}}, setlayout, {.v = &layouts[15]} }),
// LAYOUT SIZES
- { MODKEY, XK_h, setmfact, { .f = -0.05 } },
- { MODKEY, XK_l, setmfact, { .f = +0.05 } },
- { WINMOD2, XK_j, setcfact, { .f = -0.25 } },
- { WINMOD2, XK_k, setcfact, { .f = +0.25 } },
- { WINMOD2, XK_l, setcfact, { .f = 0.00 } },
- { WINMOD, XK_c, incrgaps, { .i = -5 } },
- { WINMOD2, XK_c, incrgaps, { .i = +5 } },
- { WINMOD, XK_i, incrigaps, { .i = -5 } },
- { WINMOD2, XK_i, incrigaps, { .i = +5 } },
- { WINMOD, XK_n, incnmaster, { .i = -1 } },
- { WINMOD2, XK_n, incnmaster, { .i = +1 } },
- { WINMOD, XK_o, incrogaps, { .i = -5 } },
- { WINMOD2, XK_o, incrogaps, { .i = +5 } },
- { WINMOD, XK_y, incrihgaps, { .i = -5 } },
- { WINMOD2, XK_y, incrihgaps, { .i = +5 } },
- { WINMOD, XK_t, incrivgaps, { .i = -5 } },
- { WINMOD2, XK_t, incrivgaps, { .i = +5 } },
- { WINMOD, XK_u, incrohgaps, { .i = -5 } },
- { WINMOD2, XK_u, incrohgaps, { .i = +5 } },
- { WINMOD, XK_r, incrovgaps, { .i = -5 } },
- { WINMOD2, XK_r, incrovgaps, { .i = +5 } },
- { WINMOD, XK_g, defaultgaps, {0} },
- { WINMOD2, XK_g, togglegaps, {0} },
- { WINMOD, XK_space, zoom, {0} },
+ &((Keychord){1, {{WINKEY, XK_Insert}}, setcfact, {.f = 0.00} }),
+ &((Keychord){1, {{WINKEY, XK_End}}, incrgaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_End}}, incrgaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Down}}, incrigaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Down}}, incrigaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Next}}, incrogaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Next}}, incrogaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Left}}, incrihgaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Left}}, incrihgaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Begin}}, incrivgaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Begin}}, incrivgaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Right}}, incrohgaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Right}}, incrohgaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Home}}, incrovgaps, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Home}}, incrovgaps, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_Up}}, incnmaster, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Up}}, incnmaster, {.i = +1 } }),
+ &((Keychord){1, {{WINKEY, XK_h}}, setmfact, {.f = -0.05} }),
+ &((Keychord){1, {{WINKEY, XK_l}}, setmfact, {.f = +0.05} }),
// MEDIA CONTROLS
- { 0, NoSymbol, spawn, { .v = termcmd } },
- { 0, XF86XK_Battery, spawn, SHCMD("pkill -RTMIN+4 dwmblocks") },
- { 0, XF86XK_WWW, spawn, { .v = (const char *[]){ BROWSER, NULL } } },
- { 0, XF86XK_DOS, spawn, { .v = termcmd } },
- { 0, XF86XK_AudioMute, spawn, SHCMD("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; kill -39 $(pidof dwmblocks)") },
- { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 0%- && wpctl set-volume @DEFAULT_AUDIO_SINK@ 3%+; kill -39 $(pidof dwmblocks)") },
- { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 0%+ && wpctl set-volume @DEFAULT_AUDIO_SINK@ 3%-; kill -39 $(pidof dwmblocks)") },
- { 0, XF86XK_AudioPrev, spawn, { .v = (const char *[]){ "mpc", "prev", NULL } } },
- { 0, XF86XK_AudioNext, spawn, { .v = (const char *[]){ "mpc", "next", NULL } } },
- { 0, XF86XK_AudioPause, spawn, { .v = (const char *[]){ "mpc", "pause", NULL } } },
- { 0, XF86XK_AudioPlay, spawn, { .v = (const char *[]){ "mpc", "play", NULL } } },
- { 0, XF86XK_AudioStop, spawn, { .v = (const char *[]){ "mpc", "stop", NULL } } },
- { 0, XF86XK_AudioRewind, spawn, { .v = (const char *[]){ "mpc", "seek", "-10", NULL } } },
- { 0, XF86XK_AudioForward, spawn, { .v = (const char *[]){ "mpc", "seek", "+10", NULL } } },
- { 0, XF86XK_AudioMedia, spawn, { .v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } } },
- { 0, XF86XK_AudioMicMute, spawn, SHCMD("pactl set-source-mute @DEFAULT_SOURCE@ toggle") },
- { 0, XF86XK_Calculator, spawn, { .v = (const char *[]){ TERMINAL, "-e", "bc", "-l", NULL } } },
- { 0, XF86XK_Launch1, spawn, { .v = (const char *[]){ "xset", "dpms", "force", "off", NULL } } },
- { 0, XF86XK_Mail, spawn, SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks") },
- { 0, XF86XK_MonBrightnessDown, spawn, SHCMD("pkexec brillo -U 5 -q; kill -43 $(pidof dwmblocks)") },
- /* { 0, XF86XK_MonBrightnessDown, spawn, {.v = (const char*[]){ "xbacklight", "-dec", "15", NULL } } }, */
- { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("pkexec brillo -A 5 -q; kill -43 $(pidof dwmblocks)") },
- /* { 0, XF86XK_MonBrightnessUp, spawn, {.v = (const char*[]){ "xbacklight", "-inc", "15", NULL } } }, */
- { 0, XF86XK_MyComputer, spawn, { .v = (const char *[]){ TERMINAL, "-e", "lfub", "/", NULL } } },
- { 0, XF86XK_PowerOff, spawn, { .v = (const char*[]){ "sysact", NULL } } },
- { 0, XF86XK_RotateWindows, spawn, { .v = (const char *[]){ "tablet", NULL } } },
- { 0, XF86XK_ScreenSaver, spawn, SHCMD("slock & xset dpms force off; mpc pause; pauseallmpv") },
- { 0, XF86XK_Sleep, spawn, { .v = (const char *[]){ "sudo", "-A", "zzz", NULL } } },
- { 0, XF86XK_TaskPane, spawn, { .v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } },
- { 0, XF86XK_TouchpadOff, spawn, { .v = (const char *[]){ "synclient", "TouchpadOff=1", NULL } } },
- { 0, XF86XK_TouchpadOn, spawn, { .v = (const char *[]){ "synclient", "TouchpadOff=0", NULL } } },
- { 0, XF86XK_TouchpadToggle, spawn, SHCMD("(synclient | grep 'TouchpadOff.*1' && synclient TouchpadOff=0) || synclient TouchpadOff=1") },
-
- // MODE
- { MODKEY, XK_Escape, setkeymode, { .ui = ModeCommand } },
+ &((Keychord){1, {{0, NoSymbol}}, spawn, {.v = termcmd } }),
+ &((Keychord){1, {{0, XF86XK_Battery}}, spawn, SHCMD("pkill -RTMIN+4 dwmblocks") }),
+ &((Keychord){1, {{0, XF86XK_WWW}}, spawn, {.v = (const char *[]){ BROWSER, NULL } } }),
+ &((Keychord){1, {{0, XF86XK_DOS}}, spawn, {.v = termcmd } }),
+ &((Keychord){1, {{0, XF86XK_AudioMute}}, spawn, SHCMD("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{0, XF86XK_AudioRaiseVolume}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 0%- && wpctl set-volume @DEFAULT_AUDIO_SINK@ 3%+; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{0, XF86XK_AudioLowerVolume}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 0%+ && wpctl set-volume @DEFAULT_AUDIO_SINK@ 3%-; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{0, XF86XK_AudioPrev}}, spawn, {.v = (const char *[]){ "mpc", "prev", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioNext}}, spawn, {.v = (const char *[]){ "mpc", "next", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioPause}}, spawn, {.v = (const char *[]){ "mpc", "pause", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioPlay}}, spawn, {.v = (const char *[]){ "mpc", "play", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioStop}}, spawn, {.v = (const char *[]){ "mpc", "stop", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioRewind}}, spawn, {.v = (const char *[]){ "mpc", "seek", "-10", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioForward}}, spawn, {.v = (const char *[]){ "mpc", "seek", "+10", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioMedia}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_AudioMicMute}}, spawn, SHCMD("pactl set-source-mute @DEFAULT_SOURCE@ toggle") }),
+ &((Keychord){1, {{0, XF86XK_Calculator}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "bc", "-l", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_Launch1}}, spawn, {.v = (const char *[]){ "xset", "dpms", "force", "off", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_Mail}}, spawn, SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks") }),
+ &((Keychord){1, {{0, XF86XK_MonBrightnessDown}}, spawn, SHCMD("pkexec brillo -U 5 -q; kill -43 $(pidof dwmblocks)") }),
+ /* &((Keychord){1, {{0, XF86XK_MonBrightnessDown}}, spawn, {.v = (const char*[]){ "xbacklight", "-dec", "15", NULL } } }), */
+ &((Keychord){1, {{0, XF86XK_MonBrightnessUp}}, spawn, SHCMD("pkexec brillo -A 5 -q; kill -43 $(pidof dwmblocks)") }),
+ /* &((Keychord){1, {{0, XF86XK_MonBrightnessUp}}, spawn, {.v = (const char*[]){ "xbacklight", "-inc", "15", NULL } } }), */
+ &((Keychord){1, {{0, XF86XK_MyComputer}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "lfub", "/", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_PowerOff}}, spawn, {.v = (const char*[]){ "sysact", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_RotateWindows}}, spawn, {.v = (const char *[]){ "tablet", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_ScreenSaver}}, spawn, SHCMD("slock & xset dpms force off; mpc pause; pauseallmpv") }),
+ &((Keychord){1, {{0, XF86XK_Sleep}}, spawn, {.v = (const char *[]){ "sudo", "-A", "zzz", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_TaskPane}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_TouchpadOff}}, spawn, {.v = (const char *[]){ "synclient", "TouchpadOff=1", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_TouchpadOn}}, spawn, {.v = (const char *[]){ "synclient", "TouchpadOff=0", NULL } } }),
+ &((Keychord){1, {{0, XF86XK_TouchpadToggle}}, spawn, SHCMD("(synclient | grep 'TouchpadOff.*1' && synclient TouchpadOff=0) || synclient TouchpadOff=1") }),
// MOUSE
- { ULTRAMOD, XK_h, spawn, { .v = (const char *[]){ "xdotmouse", "h", NULL } } },
- { ULTRAMOD, XK_j, spawn, { .v = (const char *[]){ "xdotmouse", "j", NULL } } },
- { ULTRAMOD, XK_k, spawn, { .v = (const char *[]){ "xdotmouse", "k", NULL } } },
- { ULTRAMOD, XK_l, spawn, { .v = (const char *[]){ "xdotmouse", "l", NULL } } },
- { ULTRAMOD, XK_i, spawn, { .v = (const char *[]){ "xdotmouse", "c", NULL } } },
- { ULTRAMOD, XK_u, spawn, { .v = (const char *[]){ "xdotmouse", "C", NULL } } },
- { ULTRAMOD, XK_o, spawn, { .v = (const char *[]){ "xdotmouse", "m", NULL } } },
+ &((Keychord){1, {{ULTRAMOD, XK_j}}, spawn, { .v = (const char *[]){ "xdotmouse", "h", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_k}}, spawn, { .v = (const char *[]){ "xdotmouse", "j", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_l}}, spawn, { .v = (const char *[]){ "xdotmouse", "k", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_semicolon}}, spawn, { .v = (const char *[]){ "xdotmouse", "l", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_i}}, spawn, { .v = (const char *[]){ "xdotmouse", "c", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_u}}, spawn, { .v = (const char *[]){ "xdotmouse", "C", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD, XK_o}}, spawn, { .v = (const char *[]){ "xdotmouse", "m", NULL } } }),
// PROGRAMS
- { MODKEY, XK_c, spawn, { .v = (const char *[]){ TERMINAL, "-e", "calcurse", NULL } } },
- { MODKEY, XK_d, spawn, { .v = (const char *[]){ "dmenu_run", NULL } } },
- { MODKEY, XK_e, spawn, SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks; rmdir ~/.abook 2>/dev/null") },
- { MODKEY, XK_g, gesture, {0} },
- { MODKEY, XK_n, spawn, SHCMD(TERMINAL " -e newsboat ; pkill -RTMIN+19 dwmblocks") },
- { MODKEY, XK_o, spawn, { .v = (const char *[]){ TERMINAL, "-e", "lfub", NULL } } },
- { MODKEY, XK_r, spawn, { .v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } },
- { MODKEY, XK_t, spawn, { .v = (const char *[]){ "torwrap", NULL } } },
- { MODKEY, XK_w, spawn, { .v = (const char *[]){ BROWSER, NULL } } },
- { WINMOD, XK_w, spawn, { .v = (const char *[]){ BROWSER, "--target", "private-window", NULL } } },
- { WINMOD2, XK_w, spawn, { .v = (const char *[]){ "pkill", "-f", BROWSER, NULL } } },
- { MODKEY, XK_grave, togglescratch, { .ui = 1 } }, // calculator //
- { WINMOD, XK_grave, spawn, { .v = (const char *[]){ "dmenuunicode", NULL } } },
- { WINMOD2, XK_grave, spawn, { .v = (const char *[]){ "crontog", NULL } } },
- { MODKEY, XK_Return, spawn, { .v = termcmd } },
- { WINMOD, XK_Return, spawn, { .v = (const char *[]){ "sd", NULL } } },
- { WINMOD2, XK_Return, togglescratch, { .ui = 0 } }, // terminal //
+ &((Keychord){1, {{WINKEY, XK_e}}, spawn, SHCMD(TERMINAL " -e neomutt; pkill -RTMIN+20 dwmblocks; rmdir ~/.abook 2>/dev/null") }),
+ &((Keychord){1, {{WINKEY, XK_w}}, spawn, {.v = (const char *[]){ BROWSER, NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_w}}, spawn, {.v = (const char *[]){ BROWSER, "--target", "private-window", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_x},{0, XK_k}}, spawn, {.v = (const char *[]){ "pkill", "-f", "kakaotalk", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_x},{0, XK_w}}, spawn, {.v = (const char *[]){ "pkill", "-f", BROWSER, NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_a}}, spawn, SHCMD(TERMINAL " -e abook -C ${XDG_CONFIG_HOME:-${HOME}/.config}/abook/abookrc --datafile ${XDG_CONFIG_HOME:-${HOME}/.config}/abook/addressbook") }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_c}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "calcurse", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_g}}, spawn, {.v = (const char *[]){ "gimp", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_h}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_i}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "nmtui", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_k}}, spawn, {.v = (const char *[]){ "kakaotalk", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_l}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "lfub", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{ShiftMask, XK_l}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "lfub", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_m}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_n}}, spawn, SHCMD(TERMINAL " -e newsboat; pkill -RTMIN+19 dwmblocks") }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_p}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "profanity", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_r}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_t}}, spawn, {.v = (const char *[]){ "torwrap", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_v},{0, XK_w}}, spawn, {.v = (const char *[]){ TERMINAL, "-e", "nvim", "-c", "VimwikiIndex", "1", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_w}}, spawn, SHCMD(TERMINAL " -e less -Sf ${XDG_CACHE_HOME:-${HOME}/.cache}/weatherreport") }),
// SCRIPTS
- { MODKEY, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-t", NULL } } },
- { WINMOD, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-o", NULL } } },
- { ULTRAMOD, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-p", NULL } } },
- { WINMOD2, XK_b, togglebar, {0} },
- { EXTRAMOD, XK_b, togglebar, { .i = 1 } },
- { MODKEY2 , XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-c", NULL } } },
- { TERMMOD, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-b", NULL } } },
- { TERMMOD2, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-s", NULL } } },
- { ULTRAMOD2, XK_b, spawn, { .v = (const char *[]){ "bookmarks", "-v", NULL } } },
- { WINMOD, XK_d, spawn, { .v = (const char *[]){ "passmenu", NULL } } },
- { WINMOD2, XK_d, spawn, { .v = (const char *[]){ "passmenu2", NULL } } },
- { WINMOD2, XK_e, spawn, SHCMD("ecrypt; pkill -RTMIN+2 dwmblocks") },
- { MODKEY, XK_s, spawn, { .v = (const char *[]){ "dmenubrowse", NULL } } },
- { MODKEY, XK_v, spawn, { .v = (const char *[]){ "mpvplay", NULL } } },
- { WINMOD, XK_v, spawn, { .v = (const char *[]){ "clipmenu", NULL } } },
- { WINMOD2, XK_v, spawn, SHCMD("ovpn; kill -41 $(pidof dwmblocks)") },
- { MODKEY, XK_Insert, spawn, SHCMD("xdotool type $(grep -v '^#' ~/.local/share/thesiah/snippets | dmenu -i -l 50 | cut -d' ' -f1)") },
- { 0, XK_Print, spawn, SHCMD("maim | tee ~/Pictures/screenshots/$(date '+%y%m%d-%H%M-%S').png | xclip -selection clipboard") },
- { ShiftMask, XK_Print, spawn, { .v = (const char *[]){ "maimpick", NULL } } },
- { MODKEY, XK_Print, spawn, { .v = (const char *[]){ "dmenurecord", NULL } } },
- { WINMOD2, XK_Print, spawn, { .v = (const char *[]){ "dmenurecord", "kill", NULL } } },
- { MODKEY, XK_Scroll_Lock, spawn, SHCMD("remaps") },
- { WINMOD2, XK_Scroll_Lock, spawn, SHCMD("killall screenkey || screenkey -t 3 -p fixed -s small -g 20%x5%+40%-5% --key-mode keysyms --bak-mode normal --mods-mode normal -f ttf-font-awesome --opacity 0.5 &") },
- { MODKEY, XK_F1, spawn, SHCMD("groff -mom /usr/local/share/dwm/thesiah.mom -Tpdf | zathura -") },
- { WINMOD, XK_F1, spawn, SHCMD("nsxiv -a ${XDG_PICTURES_DIR:-${HOME}/Pictures}/resources") },
- { WINMOD2, XK_F1, spawn, { .v = (const char *[]){ "dmenuman", NULL } } },
- { MODKEY, XK_F2, spawn, { .v = (const char *[]){ "tutorialvids", NULL } } },
- { MODKEY, XK_F3, spawn, { .v = (const char *[]){ "displayselect", NULL } } },
- { MODKEY, XK_F4, spawn, SHCMD(TERMINAL " -e pulsemixer; kill -39 $(pidof dwmblocks)") },
- { WINMOD2, XK_F4, spawn, { .v = (const char *[]){ "toggleoutput", NULL } } },
- { MODKEY, XK_F5, xrdb, { .v = NULL } },
- { WINMOD, XK_F5, spawn, { .v = (const char *[]){ "stw", NULL } } },
- { WINMOD2, XK_F5, spawn, { .v = (const char *[]){ "rbackup", NULL } } },
- { ULTRAMOD , XK_F5, spawn, { .v = (const char *[]){ "dmenuupgrade", NULL } } },
- { MODKEY, XK_F6, spawn, { .v = (const char *[]){ "qndl", "-v", NULL } } },
- { WINMOD, XK_F6, spawn, { .v = (const char *[]){ "qndl", "-m", NULL } } },
- { MODKEY, XK_F7, spawn, { .v = (const char *[]){ "transadd", "-l", NULL } } },
- { WINMOD2, XK_F7, spawn, { .v = (const char *[]){ "td-toggle", NULL } } },
- { MODKEY, XK_F8, spawn, { .v = (const char *[]){ "mailsync", NULL } } },
- { MODKEY, XK_F9, spawn, { .v = (const char *[]){ "mounter", NULL } } },
- { WINMOD, XK_F9, spawn, { .v = (const char *[]){ "dmenumountcifs", NULL } } },
- { WINMOD2, XK_F9, spawn, { .v = (const char *[]){ "unmounter", NULL } } },
- { MODKEY, XK_F10, spawn, { .v = (const char *[]){ "dmenuconnections", NULL } } },
- { WINMOD, XK_F10, spawn, { .v = (const char *[]){ "dmenusmbadd", NULL } } },
- { WINMOD2, XK_F10, spawn, { .v = (const char *[]){ "dmenusmbdel", NULL } } },
- { MODKEY, XK_F11, spawn, { .v = (const char *[]){ "webcam", "h", NULL } } },
- { WINMOD, XK_F11, spawn, { .v = (const char *[]){ "webcam", NULL } } },
- { MODKEY, XK_F12, spawn, { .v = (const char *[]){ "fcitx5-configtool", NULL } } },
- { WINMOD, XK_F12, spawn, SHCMD("remaps") },
- { ShiftMask, XK_F12, spawn, SHCMD("remaps") },
+ &((Keychord){1, {{WINKEY, XK_p}}, spawn, {.v = (const char *[]){ "passmenu", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_p}}, spawn, {.v = (const char *[]){ "passmenu2", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_c}}, spawn, {.v = (const char *[]){ "crontog", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_e}}, spawn, SHCMD("ecrypt; pkill -RTMIN+2 dwmblocks") }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_v}}, spawn, {.v = (const char *[]){ "ovpn", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_f}}, spawn, {.v = (const char *[]){ "dmenubrowse", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_i}}, spawn, {.v = (const char *[]){ "bookmarks", "-t", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_o}}, spawn, {.v = (const char *[]){ "bookmarks", "-o", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_p}}, spawn, {.v = (const char *[]){ "bookmarks", "-p", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_c}}, spawn, {.v = (const char *[]){ "bookmarks", "-c", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_b}}, spawn, {.v = (const char *[]){ "bookmarks", "-b", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_s}}, spawn, {.v = (const char *[]){ "bookmarks", "-s", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_b},{0, XK_v}}, spawn, {.v = (const char *[]){ "bookmarks", "-v", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_c}}, spawn, {.v = (const char *[]){ "clipmenu", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_u}}, spawn, {.v = (const char *[]){ "dmenuunicode", NULL } } }),
+ &((Keychord){3, {{WINKEY, XK_space},{0, XK_v},{0, XK_v}}, spawn, {.v = (const char *[]){ "mpvplay", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_Insert}}, spawn, SHCMD("xdotool type $(grep -v '^#' ~/.local/share/thesiah/snippets | dmenu -i -l 50 | cut -d' ' -f1)") }),
+ &((Keychord){1, {{0, XK_Print}}, spawn, SHCMD("maim | tee ~/Pictures/screenshots/$(date '+%y%m%d-%H%M-%S').png | xclip -selection clipboard") }),
+ &((Keychord){1, {{ShiftMask, XK_Print}}, spawn, {.v = (const char *[]){ "maimpick", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_Print}}, spawn, {.v = (const char *[]){ "dmenurecord", NULL } } }),
+ &((Keychord){1, {{WINMOD2, XK_Print}}, spawn, {.v = (const char *[]){ "dmenurecord", "kill", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_Scroll_Lock}}, spawn, SHCMD("remaps") }),
+ &((Keychord){1, {{WINMOD2, XK_Scroll_Lock}}, spawn, SHCMD("killall screenkey || screenkey -t 3 -p fixed -s small -g 20%x5%+40%-5% --key-mode keysyms --bak-mode normal --mods-mode normal -f ttf-font-awesome --opacity 0.5 &") }),
+ &((Keychord){1, {{WINKEY, XK_F1}}, spawn, SHCMD("groff -mom /usr/local/share/dwm/thesiah.mom -Tpdf | zathura -") }),
+ &((Keychord){1, {{WINMOD, XK_F1}}, spawn, SHCMD("nsxiv -a ${XDG_PICTURES_DIR:-${HOME}/Pictures}/resources") }),
+ &((Keychord){1, {{WINMOD2, XK_F1}}, spawn, {.v = (const char *[]){ "dmenuman", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F2}}, spawn, {.v = (const char *[]){ "tutorialvids", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F3}}, spawn, {.v = (const char *[]){ "displayselect", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F4}}, spawn, SHCMD(TERMINAL " -e pulsemixer; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINMOD2, XK_F4}}, spawn, {.v = (const char *[]){ "toggleoutput", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F5}}, spawn, {.v = (const char *[]){ "stw", NULL } } }),
+ &((Keychord){1, {{WINMOD2, XK_F5}}, spawn, {.v = (const char *[]){ "rbackup", NULL } } }),
+ &((Keychord){1, {{ULTRAMOD,XK_F5}}, spawn, {.v = (const char *[]){ "dmenuupgrade", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F6}}, spawn, {.v = (const char *[]){ "qndl", "-v", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F6}}, spawn, {.v = (const char *[]){ "qndl", "-m", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F7}}, spawn, {.v = (const char *[]){ "transadd", "-l", NULL } } }),
+ &((Keychord){1, {{WINMOD2, XK_F7}}, spawn, {.v = (const char *[]){ "td-toggle", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F8}}, spawn, {.v = (const char *[]){ "mailsync", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F9}}, spawn, {.v = (const char *[]){ "mounter", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F9}}, spawn, {.v = (const char *[]){ "dmenumountcifs", NULL } } }),
+ &((Keychord){1, {{WINMOD2, XK_F9}}, spawn, {.v = (const char *[]){ "unmounter", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F10}}, spawn, {.v = (const char *[]){ "dmenuconnections", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F10}}, spawn, {.v = (const char *[]){ "dmenusmbadd", NULL } } }),
+ &((Keychord){1, {{WINMOD2, XK_F10}}, spawn, {.v = (const char *[]){ "dmenusmbdel", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F11}}, spawn, {.v = (const char *[]){ "webcam", "h", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F11}}, spawn, {.v = (const char *[]){ "webcam", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_F12}}, spawn, {.v = (const char *[]){ "fcitx5-configtool", NULL } } }),
+ &((Keychord){1, {{WINMOD, XK_F12}}, spawn, SHCMD("remaps") }),
+ &((Keychord){1, {{ShiftMask, XK_F12}}, spawn, SHCMD("remaps") }),
// SYSTEMS
- { WINMOD2, XK_k, spawn, { .v = (const char *[]){ "pkill", "-f", "kakaotalk", NULL } } },
- { MODKEY, XK_q, killclient, {0} }, // kill only current client
- { WINMOD, XK_q, killclient, { .ui = 1 } }, // kill other clients in the same tag
- { WINMOD2, XK_q, killclient, { .ui = 2 } }, // kill all clients in the same tag
- { MODKEY2, XK_q, toggleallowkill, {0} },
- { MODKEY, XK_BackSpace, spawn, { .v = (const char *[]){ "slock", NULL } } },
- { WINMOD, XK_BackSpace, spawn, { .v = (const char *[]){ "sysact", NULL } } },
- { MODKEY, XK_minus, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; kill -39 $(pidof dwmblocks)") },
- { MODKEY, XK_equal, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; kill -39 $(pidof dwmblocks)") },
- { WINMOD, XK_minus, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%-; kill -39 $(pidof dwmblocks)") },
- { WINMOD, XK_equal, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%+; kill -39 $(pidof dwmblocks)") },
- { WINMOD2, XK_minus, spawn, SHCMD("pkexec brillo -U 5 -q; kill -43 $(pidof dwmblocks)") },
- { WINMOD2, XK_equal, spawn, SHCMD("pkexec brillo -A 5 -q; kill -43 $(pidof dwmblocks)") },
- { ULTRAMOD, XK_minus, spawn, SHCMD("monitorbright -dec 5; kill -42 $(pidof dwmblocks)") },
- { ULTRAMOD, XK_equal, spawn, SHCMD("monitorbright -inc 5; kill -42 $(pidof dwmblocks)") },
- { 0, XK_Alt_R, spawn, SHCMD("fcitx5-remote -t && kill -44 $(pidof dwmblocks)") },
- { ControlMask, XK_F5, quit, {1} },
- { EXTRAMOD, XK_F5, spawn, SHCMD("killall -q dwmblocks; setsid -f dwmblocks") },
+ &((Keychord){1, {{WINKEY, XK_g}}, gesture, {0} }),
+ &((Keychord){1, {{WINKEY, XK_q}}, killclient, {0} }), // kill only current client
+ &((Keychord){1, {{WINMOD, XK_q}}, killclient, {.ui = 1 } }), // kill other clients in the same tag
+ &((Keychord){1, {{WINMOD2, XK_q}}, killclient, {.ui = 2 } }), // kill all clients in the same tag
+ &((Keychord){1, {{WINKEY, XK_d}}, spawn, {.v = dmenucmd } }),
+ &((Keychord){1, {{WINKEY, XK_Return}}, spawn, {.v = termcmd } }),
+ &((Keychord){1, {{WINMOD, XK_Return}}, spawn, {.v = (const char *[]){ "sd", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_BackSpace}}, spawn, {.v = (const char *[]){ "slock", NULL } } }),
+ &((Keychord){2, {{WINKEY, XK_space},{ShiftMask, XK_BackSpace}}, spawn, {.v = (const char *[]){ "sysact", NULL } } }),
+ &((Keychord){1, {{WINKEY, XK_minus}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINKEY, XK_equal}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINMOD, XK_minus}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%-; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINMOD, XK_equal}}, spawn, SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%+; kill -39 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINMOD2, XK_minus}}, spawn, SHCMD("pkexec brillo -U 5 -q; kill -43 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{WINMOD2, XK_equal}}, spawn, SHCMD("pkexec brillo -A 5 -q; kill -43 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{ULTRAMOD, XK_minus}}, spawn, SHCMD("monitorbright -dec 5; kill -42 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{ULTRAMOD, XK_equal}}, spawn, SHCMD("monitorbright -inc 5; kill -42 $(pidof dwmblocks)") }),
+ &((Keychord){1, {{0, XK_Alt_R}}, spawn, SHCMD("fcitx5-remote -t && kill -44 $(pidof dwmblocks)") }),
+ /* &((Keychord){1, {{WINMOD, XK_q}}, quit, {0} }), */
+ &((Keychord){1, {{ControlMask, XK_F5}}, quit, {1} }),
+ &((Keychord){1, {{EXTRAMOD, XK_F5}}, spawn, SHCMD("killall -q dwmblocks; setsid -f dwmblocks") }),
// TRAVERSALS
- { MODKEY, XK_apostrophe, togglemark, {0} },
- { MODKEY2, XK_Tab, view, {0} },
- { TERMMOD, XK_Tab, swapfocus, {0} },
- { TERMMOD2, XK_Tab, swapclient, {0} },
- { MODKEY, XK_0, view, { .ui = ~0 } },
- { WINMOD, XK_0, tag, { .ui = ~0 } },
- { MODKEY2, XK_bracketleft, shiftview, { .i = -1 } },
- { MODKEY2, XK_bracketright, shiftview, { .i = 1 } },
- { TERMMOD, XK_bracketleft, shifttag, { .i = -1 } },
- { TERMMOD, XK_bracketright, shifttag, { .i = 1 } },
- { TERMMOD2, XK_bracketleft, shifttagandview, { .i = -1 } },
- { TERMMOD2, XK_bracketright, shifttagandview, { .i = 1 } },
- { MODKEY, XK_bracketleft, shiftviewclients, { .i = -1 } },
- { MODKEY, XK_bracketright, shiftviewclients, { .i = +1 } },
- { WINMOD, XK_bracketleft, shifttagclients, { .i = -1 } },
- { WINMOD, XK_bracketright, shifttagclients, { .i = +1 } },
- { WINMOD2, XK_bracketleft, shiftboth, { .i = -1 } },
- { WINMOD2, XK_bracketright, shiftboth, { .i = +1 } },
- { ULTRAMOD, XK_bracketleft, shiftswaptags, { .i = -1 } },
- { ULTRAMOD, XK_bracketright, shiftswaptags, { .i = +1 } },
- { MODKEY, XK_Left, focusmon, { .i = -1 } },
- { MODKEY, XK_Right, focusmon, { .i = +1 } },
- { WINMOD, XK_Left, tagmon, { .i = -1 } },
- { WINMOD, XK_Right, tagmon, { .i = +1 } },
-
- /* { WINMOD, XK_apostrophe, togglesmartgaps, {0} }, */
-};
-
-static Key cmdkeys[] = {
- /* modifier keys function argument */
- // COMMANDS
- { 0, XK_Escape, clearcmd, {0} },
- { ControlMask, XK_c, clearcmd, {0} },
- { ControlMask, XK_x, setkeymode, { .ui = ModeInsert } },
-};
-
-static Command commands[] = {
- // STACKKEYS
- CSTACKKEYS(MODKEY, focus)
- CSTACKKEYS(WINMOD, push)
-
- // TAGKEYS
- CTAGKEYS(XK_1, 0)
- CTAGKEYS(XK_2, 1)
- CTAGKEYS(XK_3, 2)
- CTAGKEYS(XK_4, 3)
- CTAGKEYS(XK_5, 4)
- CTAGKEYS(XK_6, 5)
- CTAGKEYS(XK_7, 6)
- CTAGKEYS(XK_8, 7)
- CTAGKEYS(XK_9, 8)
-
- /* Modifier (4 keys) keysyms (4 keys) function argument */
- // APPEARANCES
- { { ShiftMask, 0, 0, 0 }, { XK_b, 0, 0, 0 }, togglebar, {0} },
- { { ControlMask, 0, 0, 0 }, { XK_b, 0, 0, 0 }, togglebar, { .i = 1 } },
- { { ControlMask, 0, 0, 0 }, { XK_o, 0, 0, 0 }, toggleborder, {0} },
- { { ControlMask, 0, 0, 0 }, { XK_f, 0, 0, 0 }, togglefloating, {0} },
- { { ControlMask, 0, 0, 0 }, { XK_g, 0, 0, 0 }, togglegaps, {0} },
- { { ShiftMask, 0, 0, 0 }, { XK_g, 0, 0, 0 }, defaultgaps, {0} },
-
- // LAYOUTS
- { { 0, 0, 0, 0 }, { XK_l, XK_d, 0, 0 }, setlayout, { .v = &layouts[0] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_s, 0, 0 }, setlayout, { .v = &layouts[1] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_l, XK_l, 0 }, setlayout, { .v = &layouts[2] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_a, 0, 0 }, setlayout, { .v = &layouts[3] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_backslash, 0, 0 }, setlayout, { .v = &layouts[4] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_h, XK_l, 0 }, setlayout, { .v = &layouts[5] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_t, XK_t, 0 }, setlayout, { .v = &layouts[6] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_e, XK_e, 0 }, setlayout, { .v = &layouts[7] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_h, XK_h, 0 }, setlayout, { .v = &layouts[8] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_3, XK_3, 0 }, setlayout, { .v = &layouts[9] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_minus, XK_minus, 0 }, setlayout, { .v = &layouts[10] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_period, XK_period, 0 }, setlayout, { .v = &layouts[11] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_m, XK_l, 0 }, setlayout, { .v = &layouts[12] } },
- { { 0, 0, 0, 0 }, { XK_l, XK_m, XK_s, 0 }, setlayout, { .v = &layouts[13] } },
-
- // FLOATING POSITIONS
- { { 0, 0, 0, 0 }, { XK_f, XK_u, 0, 0 }, explace, { .ui = EX_NW } },
- { { 0, 0, 0, 0 }, { XK_f, XK_i, 0, 0 }, explace, { .ui = EX_N } },
- { { 0, 0, 0, 0 }, { XK_f, XK_o, 0, 0 }, explace, { .ui = EX_NE } },
- { { 0, 0, 0, 0 }, { XK_f, XK_j, 0, 0 }, explace, { .ui = EX_W } },
- { { 0, 0, 0, 0 }, { XK_f, XK_k, 0, 0 }, explace, { .ui = EX_C } },
- { { 0, 0, 0, 0 }, { XK_f, XK_l, 0, 0 }, explace, { .ui = EX_E } },
- { { 0, 0, 0, 0 }, { XK_f, XK_m, 0, 0 }, explace, { .ui = EX_SW } },
- { { 0, 0, 0, 0 }, { XK_f, XK_comma, 0, 0 }, explace, { .ui = EX_S } },
- { { 0, 0, 0, 0 }, { XK_f, XK_period, 0, 0 }, explace, { .ui = EX_SE } },
-
- // FLOATING SIZES
- { { 0, 0, 0, 0 }, { XK_s, XK_j, 0, 0 }, exresize, { .v = (int []){ 0, 25 } } },
- { { 0, 0, 0, 0 }, { XK_s, XK_k, 0, 0 }, exresize, { .v = (int []){ 0, -25 } } },
- { { 0, 0, 0, 0 }, { XK_s, XK_l, 0, 0 }, exresize, { .v = (int []){ 25, 0 } } },
- { { 0, 0, 0, 0 }, { XK_s, XK_h, 0, 0 }, exresize, { .v = (int []){ -25, 0 } } },
- { { 0, 0, 0, 0 }, { XK_s, XK_comma, 0, 0 }, exresize, { .v = (int []){ -25, -25 } } },
- { { 0, 0, 0, 0 }, { XK_s, XK_period, 0, 0 }, exresize, { .v = (int []){ 25, 25 } } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_i, XK_h }, togglehorizontalexpand, { .i = +1 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_r, XK_h }, togglehorizontalexpand, { .i = 0 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_d, XK_h }, togglehorizontalexpand, { .i = -1 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_i, XK_v }, toggleverticalexpand, { .i = +1 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_r, XK_v }, toggleverticalexpand, { .i = 0 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_d, XK_v }, toggleverticalexpand, { .i = -1 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_i, XK_m }, togglemaximize, { .i = +1 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_r, XK_m }, togglemaximize, { .i = 0 } },
- { { 0, 0, 0, 0 }, { XK_f, XK_s, XK_d, XK_m }, togglemaximize, { .i = -1 } },
-
- // PROGRAMS
- { { 0, 0, 0, 0 }, { XK_a, 0, 0, 0 }, spawn, SHCMD(TERMINAL " -e abook -C ${XDG_CONFIG_HOME:-${HOME}/.config}/abook/abookrc --datafile ${XDG_CONFIG_HOME:-${HOME}/.config}/abook/addressbook") },
- { { 0, 0, 0, 0 }, { XK_e, 0, 0, 0 }, spawn, SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+20 dwmblocks; rmdir ~/.abook 2>/dev/null") },
- { { 0, 0, 0, 0 }, { XK_g, 0, 0, 0 }, spawn, { .v = (const char *[]){ "gimp", NULL } } },
- { { 0, 0, 0, 0 }, { XK_i, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "nmtui", NULL } } },
- { { 0, 0, 0, 0 }, { XK_k, 0, 0, 0 }, spawn, { .v = (const char *[]){ "kakaotalk", NULL } } },
- { { 0, 0, 0, 0 }, { XK_m, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "ncmpcpp", NULL } } },
- { { 0, 0, 0, 0 }, { XK_n, 0, 0, 0 }, spawn, SHCMD(TERMINAL " -e newsboat ; pkill -RTMIN+19 dwmblocks") },
- { { 0, 0, 0, 0 }, { XK_p, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "profanity", NULL } } },
- { { 0, 0, 0, 0 }, { XK_r, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "htop", NULL } } },
- { { 0, 0, 0, 0 }, { XK_t, 0, 0, 0 }, spawn, { .v = (const char *[]){ "torwrap", NULL } } },
- { { 0, 0, 0, 0 }, { XK_v, 0, 0, 0 }, spawn, { .v = (const char *[]){ "ovpn", NULL } } },
- { { ShiftMask, 0, 0, 0 }, { XK_v, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "nvim", "-c", "VimwikiIndex", "1", NULL } } },
- { { 0, 0, 0, 0 }, { XK_w, 0, 0, 0 }, spawn, SHCMD(TERMINAL " -e less -Sf ${XDG_CACHE_HOME:-${HOME}/.cache}/weatherreport") },
- { { 0, 0, 0, 0 }, { XK_Return, 0, 0, 0 }, spawn, { .v = (const char *[]){ TERMINAL, "-e", "lfub", NULL } } },
+ &((Keychord){1, {{WINMOD2, XK_z}}, zoom, {0} }),
+ &((Keychord){1, {{WINKEY, XK_grave}}, view, {0} }),
+ &((Keychord){1, {{WINKEY, XK_0}}, view, {.ui = ~0 } }),
+ &((Keychord){1, {{WINMOD, XK_0}}, tag, {.ui = ~0 } }),
+ &((Keychord){1, {{WINKEY, XK_Left}}, focusmon, {.i = -1 } }),
+ &((Keychord){1, {{WINKEY, XK_Right}}, focusmon, {.i = +1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Left}}, tagmon, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD2, XK_Right}}, tagmon, {.i = +1 } }),
+ &((Keychord){1, {{WINMOD, XK_Left}}, shiftswaptags, {.i = -1 } }),
+ &((Keychord){1, {{WINMOD, XK_Right}}, shiftswaptags, {.i = +1 } }),
+ &((Keychord){1, {{WINMODALL, XK_Left}}, shiftboth, {.i = -1 } }),
+ &((Keychord){1, {{WINMODALL, XK_Right}}, shiftboth, {.i = +1 } }),
+ &((Keychord){1, {{ALTKEY, XK_Tab}}, swapfocus, {0} }),
+ &((Keychord){1, {{ALTMOD2, XK_Tab}}, swapfocus, {0} }),
+ &((Keychord){1, {{ALTMOD, XK_Tab}}, swapclient, {0} }),
+ &((Keychord){1, {{ALTMODALL, XK_Tab}}, alttab, {0} }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_h}}, shiftview, {.i = -1 } }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_l}}, shiftview, {.i = +1 } }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_j}}, shiftviewclients, {.i = +1 } }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_k}}, shiftviewclients, {.i = -1 } }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_w}}, winview, {0} }),
+ &((Keychord){2, {{WINKEY, XK_v},{0, XK_w}}, winview, {0} }),
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_space}}, focusmaster, {0} }),
+
+ // TOGGLES
+ &((Keychord){2, {{WINKEY, XK_space},{0, XK_f}}, togglefullscr, {0} }),
+ &((Keychord){2, {{WINKEY, XK_s},{0, XK_m}}, scratchpad_show, {.i = 1} }),
+ &((Keychord){2, {{WINKEY, XK_s},{0, XK_comma}}, scratchpad_show, {.i = 2} }),
+ &((Keychord){2, {{WINKEY, XK_s},{0, XK_period}}, scratchpad_show, {.i = 3} }),
+ &((Keychord){2, {{WINKEY, XK_s},{ShiftMask, XK_m}}, scratchpad_hide, {.i = 1} }),
+ &((Keychord){2, {{WINKEY, XK_s},{ShiftMask, XK_comma}}, scratchpad_hide, {.i = 2} }),
+ &((Keychord){2, {{WINKEY, XK_s},{ShiftMask, XK_period}}, scratchpad_hide, {.i = 3} }),
+ &((Keychord){2, {{WINKEY, XK_s},{0, XK_x}}, scratchpad_remove, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_f}}, togglefloating, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{ControlMask, XK_f}}, togglecanfocusfloating, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_m}}, togglemark, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_p}}, togglescratch, {.ui = 1 } }), // calculator //
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_q}}, toggleallowkill, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_s}}, togglesticky, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_Tab}}, toggleall, {0} }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_space}}, togglealwaysontop, {0} }),
+ &((Keychord){1, {{WINMOD2, XK_Return}}, togglescratch, {.ui = 0 } }), // terminal //
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_1}}, togglescratch, {.ui = 0 } }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_2}}, togglescratch, {.ui = 1 } }),
+ &((Keychord){2, {{WINKEY, XK_t},{0, XK_3}}, togglescratch, {.ui = 2 } }),
// SUCKLESS CONFIGS
- { { ShiftMask, 0, 0, 0 }, { XK_p, 0, 0, 0 }, spawn, SHCMD(TERMINAL " -e sc-im ${THESIAH_WWW:-${HOME}/Private/git/THESIAH}/static/progs.csv") },
- { { ShiftMask, 0, 0, 0 }, { XK_s, XK_d, XK_b, 0 }, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.def.h") },
- { { ShiftMask, 0, 0, 0 }, { XK_s, XK_d, XK_m, 0 }, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dmenu/config.def.h") },
- { { ShiftMask, 0, 0, 0 }, { XK_s, XK_d, XK_w, 0 }, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwm/config.def.h") },
- { { ShiftMask, 0, 0, 0 }, { XK_s, XK_s, XK_t, 0 }, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/st/config.def.h") },
- { { ShiftMask, 0, 0, 0 }, { XK_s, XK_s, XK_l, 0 }, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/slock/config.def.h") },
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_p}}, spawn, SHCMD(TERMINAL " -e sc-im ${THESIAH_WWW:-${HOME}/Private/git/THESIAH}/static/progs.csv") }),
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_b}}, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.def.h") }),
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_d}}, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwm/config.def.h") }),
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_m}}, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dmenu/config.def.h") }),
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_l}}, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/slock/config.def.h") }),
+ &((Keychord){3, {{WINKEY, XK_v},{0, XK_s},{0, XK_s}}, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/st/config.def.h") }),
};
/* button definitions */
-/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
- * ClkClientWin, or ClkRootWin */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
- /* click event mask button function argument */
- // MOUSE BUTTONS
-#ifndef __OpenBSD__
- { ClkWinTitle, 0, Button2, zoom, {0} },
- { ClkStatusText, 0, Button1, sigdwmblocks, { .i = 1 } },
- { ClkStatusText, 0, Button2, sigdwmblocks, { .i = 2 } },
- { ClkStatusText, 0, Button3, sigdwmblocks, { .i = 3 } },
- { ClkStatusText, 0, Button4, sigdwmblocks, { .i = 4 } },
- { ClkStatusText, 0, Button5, sigdwmblocks, { .i = 5 } },
- { ClkStatusText, ShiftMask, Button1, sigdwmblocks, { .i = 6 } },
- { ClkStatusText, ShiftMask, Button2, sigdwmblocks, { .i = 7 } },
- { ClkStatusText, ShiftMask, Button3, sigdwmblocks, { .i = 8 } },
- { ClkStatusText, ShiftMask, Button4, sigdwmblocks, { .i = 9 } },
- { ClkStatusText, ShiftMask, Button5, sigdwmblocks, { .i = 10 } },
- { ClkStatusText, ControlMask, Button1, sigdwmblocks, { .i = 11 } },
- { ClkStatusText, ControlMask, Button2, sigdwmblocks, { .i = 12 } },
- { ClkStatusText, ControlMask, Button3, sigdwmblocks, { .i = 13 } },
- { ClkStatusText, ControlMask, Button4, sigdwmblocks, { .i = 14 } },
- { ClkStatusText, ControlMask, Button5, sigdwmblocks, { .i = 15 } },
-#endif
- { ClkStatusText, MODKEY, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwm/config.def.h") },
- { ClkStatusText, WINMOD, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.def.h") },
- { ClkStatusText, WINMOD2, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dmenu/config.def.h") },
- { ClkStatusText, MODKEY, Button3, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/st/config.def.h") },
- { ClkStatusText, WINMOD, Button3, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/slock/config.def.h") },
- { ClkClientWin, MODKEY, Button1, movemouse, {0} },
- { ClkClientWin, WINMOD, Button1, killclient, {0} },
- { ClkClientWin, WINMOD2, Button1, killclient, { .ui = 2 } },
- { ClkClientWin, MODKEY, Button2, defaultgaps, {0} },
- { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
- { ClkClientWin, WINMOD, Button3, gesture, {0} },
- { ClkClientWin, MODKEY, Button4, incrgaps, { .i = -1 } },
- { ClkClientWin, MODKEY, Button5, incrgaps, { .i = +1 } },
- { ClkLtSymbol, 0, Button3, layoutmenu, {0} },
- { ClkTagBar, 0, Button1, view, {0} },
- { ClkTagBar, 0, Button2, spawntag, {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 } },
- { ClkRootWin, 0, Button2, togglebar, {0} },
- { ClkRootWin, MODKEY, Button2, togglebar, { .i = 1 } },
+ /* click event mask button function argument */
+ { ClkClientWin, WINKEY, Button1, movemouse, {0} },
+ { ClkClientWin, WINMOD, Button1, killclient, {0} },
+ { ClkClientWin, WINMOD2, Button1, killclient, {.ui = 2 } },
+ { ClkClientWin, WINKEY, Button2, defaultgaps, {0} },
+ { ClkClientWin, WINMOD, Button2, togglefloating, {0} },
+ { ClkClientWin, WINKEY, Button3, resizemouse, {0} },
+ { ClkClientWin, WINMOD, Button3, gesture, {0} },
+ { ClkClientWin, WINKEY, Button4, incrgaps, {.i = -1 } },
+ { ClkClientWin, WINKEY, Button5, incrgaps, {.i = +1 } },
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, layoutmenu, {0} },
+ { ClkMonNum, 0, Button4, focusmon, {.i = -1} },
+ { ClkMonNum, 0, Button5, focusmon, {.i = +1} },
+ { ClkRootWin, 0, Button2, togglebar, {0} },
+ { ClkRootWin, WINKEY, Button2, togglebar, {.i = 1 } },
+ { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} },
+ { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} },
+ { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} },
+ { ClkStatusText, 0, Button4, sigstatusbar, {.i = 4} },
+ { ClkStatusText, 0, Button5, sigstatusbar, {.i = 5} },
+ { ClkStatusText, ShiftMask, Button1, sigstatusbar, {.i = 6} },
+ { ClkStatusText, ShiftMask, Button2, sigstatusbar, {.i = 7} },
+ { ClkStatusText, ShiftMask, Button3, sigstatusbar, {.i = 8} },
+ { ClkStatusText, ShiftMask, Button4, sigstatusbar, {.i = 9} },
+ { ClkStatusText, ShiftMask, Button5, sigstatusbar, {.i = 10} },
+ { ClkStatusText, ControlMask, Button1, sigstatusbar, {.i = 11} },
+ { ClkStatusText, ControlMask, Button2, sigstatusbar, {.i = 12} },
+ { ClkStatusText, ControlMask, Button3, sigstatusbar, {.i = 13} },
+ { ClkStatusText, ControlMask, Button4, sigstatusbar, {.i = 14} },
+ { ClkStatusText, ControlMask, Button5, sigstatusbar, {.i = 15} },
+ { ClkStatusText, WINKEY, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwm/config.def.h") },
+ { ClkStatusText, WINMOD, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.def.h") },
+ { ClkStatusText, WINMOD2, Button1, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dmenu/config.def.h") },
+ { ClkStatusText, WINKEY, Button3, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/st/config.def.h") },
+ { ClkStatusText, WINMOD, Button3, spawn, SHCMD(TERMINAL " -e nvim ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/slock/config.def.h") },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, WINKEY, Button1, tag, {0} },
+ { ClkTagBar, ULTRAKEY, Button1, nview, {0} },
+ { ClkTagBar, 0, Button2, spawntag, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, WINKEY, Button3, toggletag, {0} },
+ { ClkTagBar, ULTRAKEY, Button3, ntoggleview, {0} },
+ { ClkTagBar, 0, Button4, shiftview, {.i = 1 } },
+ { ClkTagBar, 0, Button5, shiftview, {.i = -1 } },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
};
diff --git a/dwm/config.mk b/dwm/config.mk
index 13ed3dc..f4f099b 100644
--- a/dwm/config.mk
+++ b/dwm/config.mk
@@ -1,5 +1,5 @@
# dwm version
-VERSION = 6.4
+VERSION = 6.5
# Customize below to fit your system
@@ -18,17 +18,22 @@ XINERAMAFLAGS = -DXINERAMA
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
-#MANPREFIX = ${PREFIX}/man
#FREETYPEINC = ${X11INC}/freetype2
+#MANPREFIX = ${PREFIX}/man
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res -lXrender
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
+
+# Optional compiler optimisations may create smaller binaries and
+# faster code, but increases compile time.
+# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
+#OPTIMISATIONS = -march=native -flto=auto -O3
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
-CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
+CFLAGS = ${OPTIMISATIONS} -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}
# Solaris
diff --git a/dwm/drw.c b/dwm/drw.c
index a450078..ffe9c3f 100644
--- a/dwm/drw.c
+++ b/dwm/drw.c
@@ -1,431 +1,471 @@
/* See LICENSE file for copyright and license details. */
-#include <X11/Xft/Xft.h>
-#include <X11/Xlib.h>
#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;
+static int
+utf8decode(const char *s_in, long *u, int *err)
+{
+ static const unsigned char lens[] = {
+ /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */
+ /* 110XX */ 2, 2, 2, 2,
+ /* 1110X */ 3, 3,
+ /* 11110 */ 4,
+ /* 11111 */ 0, /* invalid */
+ };
+ static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
+ static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
+
+ const unsigned char *s = (const unsigned char *)s_in;
+ int len = lens[*s >> 3];
+ *u = UTF_INVALID;
+ *err = 1;
+ if (len == 0)
+ return 1;
+
+ long cp = s[0] & leading_mask[len - 1];
+ for (int i = 1; i < len; ++i) {
+ if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
+ return i;
+ cp = (cp << 6) | (s[i] & 0x3F);
+ }
+ /* out of range, surrogate, overlong encoding */
+ if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
+ return len;
+
+ *err = 0;
+ *u = cp;
+ return len;
}
-Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w,
- unsigned int h, 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;
+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_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);
+void
+drw_free(Drw *drw)
+{
+ XFreePixmap(drw->dpy, drw->drawable);
+ XFreeGC(drw->dpy, drw->gc);
+ drw_fontset_free(drw->fonts);
+ free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_fontset_create instead.
*/
-static Fnt *xfont_create(Drw *drw, const char *fontname,
- FcPattern *fontpattern) {
- Fnt *font;
- XftFont *xfont = NULL;
- FcPattern *pattern = NULL;
-
- if (fontname) {
- /* Using the pattern found at font->xfont->pattern does not yield the
- * same substitution results as using the pattern returned by
- * FcNameParse; using the latter results in the desired fallback
- * behaviour whereas the former just results in missing-character
- * rectangles being drawn, at least with some fonts. */
- if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
- fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
- return NULL;
- }
- if (!(pattern = FcNameParse((FcChar8 *)fontname))) {
- fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n",
- fontname);
- XftFontClose(drw->dpy, xfont);
- return NULL;
- }
- } else if (fontpattern) {
- if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
- fprintf(stderr, "error, cannot load font from pattern.\n");
- return NULL;
- }
- } else {
- die("no font specified.");
- }
-
- font = ecalloc(1, sizeof(Fnt));
- font->xfont = xfont;
- font->pattern = pattern;
- font->h = xfont->ascent + xfont->descent;
- font->dpy = drw->dpy;
-
- return font;
+static Fnt *
+xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
+{
+ Fnt *font;
+ XftFont *xfont = NULL;
+ FcPattern *pattern = NULL;
+
+ if (fontname) {
+ /* Using the pattern found at font->xfont->pattern does not yield the
+ * same substitution results as using the pattern returned by
+ * FcNameParse; using the latter results in the desired fallback
+ * behaviour whereas the former just results in missing-character
+ * rectangles being drawn, at least with some fonts. */
+ if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
+ fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
+ return NULL;
+ }
+ if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
+ fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
+ XftFontClose(drw->dpy, xfont);
+ return NULL;
+ }
+ } else if (fontpattern) {
+ if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
+ fprintf(stderr, "error, cannot load font from pattern.\n");
+ return NULL;
+ }
+ } else {
+ die("no font specified.");
+ }
+
+ font = ecalloc(1, sizeof(Fnt));
+ font->xfont = xfont;
+ font->pattern = pattern;
+ font->h = xfont->ascent + xfont->descent;
+ font->dpy = drw->dpy;
+
+ return font;
}
-static void xfont_free(Fnt *font) {
- if (!font)
- return;
- if (font->pattern)
- FcPatternDestroy(font->pattern);
- XftFontClose(font->dpy, font->xfont);
- free(font);
+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, 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);
+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_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;
+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);
+ 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;
+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_setfontset(Drw *drw, Fnt *set) {
- if (drw)
- drw->fonts = set;
+void
+drw_setscheme(Drw *drw, Clr *scm)
+{
+ if (drw)
+ drw->scheme = scm;
}
-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);
}
-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);
+void
+drw_polygon(Drw *drw, int x, int y, int ow, int oh, int sw, int sh, const XPoint *points, int npoints, int shape, int filled) /* wrapper function to scale and draw a polygon with X11 */
+{
+ if (!drw || !drw->scheme)
+ return;
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
+ if (!filled) { /* reduces the scaled width and height by 1 when drawing the outline to compensate for X11 drawing the line 1 pixel over */
+ sw -= 1;
+ sh -= 1;
+ }
+ XPoint scaledpoints[npoints];
+ memcpy(scaledpoints, points, npoints);
+ for (int v = 0; v < npoints; v++)
+ scaledpoints[v] = (XPoint){ .x = points[v].x * sw / ow + x, .y = points[v].y * sh / oh + y };
+ if (filled)
+ XFillPolygon(drw->dpy, drw->drawable, drw->gc, scaledpoints, npoints, shape, CoordModeOrigin); /* Change shape to 'Convex' or 'Complex' in dwm.c if the shape is not 'Nonconvex' */
+ else
+ XDrawLines(drw->dpy, drw->drawable, drw->gc, scaledpoints, npoints, CoordModeOrigin);
}
-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);
+int
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
+{
+ int ty, ellipsis_x = 0;
+ unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
+ XftDraw *d = NULL;
+ Fnt *usedfont, *curfont, *nextfont;
+ int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
+ long utf8codepoint = 0;
+ const char *utf8str;
+ FcCharSet *fccharset;
+ FcPattern *fcpattern;
+ FcPattern *match;
+ XftResult result;
+ int charexists = 0, overflow = 0;
+ /* keep track of a couple codepoints for which we have no match. */
+ static unsigned int nomatches[128], ellipsis_width, invalid_width;
+ static const char invalid[] = "�";
+
+ if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
+ return 0;
+
+ if (!render) {
+ w = invert ? invert : ~invert;
+ } else {
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ if (w < lpad)
+ return x + w;
+ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
+ x += lpad;
+ w -= lpad;
+ }
+
+ usedfont = drw->fonts;
+ if (!ellipsis_width && render)
+ ellipsis_width = drw_fontset_getwidth(drw, "…");
+ if (!invalid_width && render)
+ invalid_width = drw_fontset_getwidth(drw, invalid);
+ while (1) {
+ ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
+ utf8str = text;
+ nextfont = NULL;
+ while (*text) {
+ utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
+ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
+ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
+ if (charexists) {
+ drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
+ if (ew + ellipsis_width <= w) {
+ /* keep track where the ellipsis still fits */
+ ellipsis_x = x + ew;
+ ellipsis_w = w - ew;
+ ellipsis_len = utf8strlen;
+ }
+
+ if (ew + tmpw > w) {
+ overflow = 1;
+ /* called from drw_fontset_getwidth_clamp():
+ * it wants the width AFTER the overflow
+ */
+ if (!render)
+ x += tmpw;
+ else
+ utf8strlen = ellipsis_len;
+ } else if (curfont == usedfont) {
+ text += utf8charlen;
+ utf8strlen += utf8err ? 0 : utf8charlen;
+ ew += utf8err ? 0 : tmpw;
+ } else {
+ nextfont = curfont;
+ }
+ break;
+ }
+ }
+
+ if (overflow || !charexists || nextfont || utf8err)
+ break;
+ else
+ charexists = 0;
+ }
+
+ if (utf8strlen) {
+ if (render) {
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
+ XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
+ usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
+ }
+ x += ew;
+ w -= ew;
+ }
+ if (utf8err && (!render || invalid_width < w)) {
+ if (render)
+ drw_text(drw, x, y, w, h, 0, invalid, invert);
+ x += invalid_width;
+ w -= invalid_width;
+ }
+ if (render && overflow)
+ drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "…", invert);
+
+ if (!*text || overflow) {
+ break;
+ } else if (nextfont) {
+ charexists = 0;
+ usedfont = nextfont;
+ } else {
+ /* Regardless of whether or not a fallback font is found, the
+ * character must be drawn. */
+ charexists = 1;
+
+ hash = (unsigned int)utf8codepoint;
+ hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
+ hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
+ h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
+ h1 = (hash >> 17) % LENGTH(nomatches);
+ /* avoid expensive XftFontMatch call when we know we won't find a match */
+ if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
+ goto no_match;
+
+ fccharset = FcCharSetCreate();
+ FcCharSetAddChar(fccharset, utf8codepoint);
+
+ if (!drw->fonts->pattern) {
+ /* Refer to the comment in xfont_create for more information. */
+ die("the first font in the cache must be loaded from a font string.");
+ }
+
+ fcpattern = FcPatternDuplicate(drw->fonts->pattern);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
+
+ FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+ match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
+
+ FcCharSetDestroy(fccharset);
+ FcPatternDestroy(fcpattern);
+
+ if (match) {
+ usedfont = xfont_create(drw, NULL, match);
+ if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
+ for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
+ ; /* NOP */
+ curfont->next = usedfont;
+ } else {
+ xfont_free(usedfont);
+ nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
+no_match:
+ usedfont = drw->fonts;
+ }
+ }
+ }
+ }
+ if (d)
+ XftDrawDestroy(d);
+
+ return x + (render ? w : 0);
}
-void drw_map(Drw *drw, Window win, int x, int y, unsigned int w,
- unsigned int h) {
- if (!drw)
- return;
+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);
+ 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(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);
+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;
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
+{
+ XGlyphInfo ext;
- if (!font || !text)
- return;
+ if (!font || !text)
+ return;
- XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
- if (w)
- *w = ext.xOff;
- if (h)
- *h = font->h;
+ 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;
+Cur *
+drw_cur_create(Drw *drw, int shape)
+{
+ Cur *cur;
- if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
- return NULL;
+ if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
+ return NULL;
- cur->cursor = XCreateFontCursor(drw->dpy, shape);
+ cur->cursor = XCreateFontCursor(drw->dpy, shape);
- return cur;
+ return cur;
}
-void drw_cur_free(Drw *drw, Cur *cursor) {
- if (!cursor)
- return;
+void
+drw_cur_free(Drw *drw, Cur *cursor)
+{
+ if (!cursor)
+ return;
- XFreeCursor(drw->dpy, cursor->cursor);
- free(cursor);
+ XFreeCursor(drw->dpy, cursor->cursor);
+ free(cursor);
}
diff --git a/dwm/drw.h b/dwm/drw.h
index b5f2856..c0ca5a8 100644
--- a/dwm/drw.h
+++ b/dwm/drw.h
@@ -1,56 +1,49 @@
/* See LICENSE file for copyright and license details. */
typedef struct {
- Cursor cursor;
+ Cursor cursor;
} Cur;
typedef struct Fnt {
- Display *dpy;
- unsigned int h;
- XftFont *xfont;
- FcPattern *pattern;
- struct Fnt *next;
+ Display *dpy;
+ unsigned int h;
+ XftFont *xfont;
+ FcPattern *pattern;
+ struct Fnt *next;
} Fnt;
enum { ColFg, ColBg, ColBorder, ColMark }; /* 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;
+ 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 *visual, unsigned int depth,
- Colormap cmap);
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
-Fnt *drw_fontset_create(Drw *drw, char *fonts[], size_t fontcount);
-void drw_fontset_free(Fnt *set);
+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);
+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);
+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);
@@ -61,12 +54,10 @@ 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);
+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
+void drw_polygon(Drw *drw, int x, int y, int ow, int oh, int sw, int sh, const XPoint *points, int npoints, int shape, int filled);
+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);
+void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
diff --git a/dwm/dwm.1 b/dwm/dwm.1
index 731f794..2473d9e 100644
--- a/dwm/dwm.1
+++ b/dwm/dwm.1
@@ -1,16 +1,21 @@
.TH DWM 1 dwm\-VERSION
.SH NAME
-dwm \- dynamic window manager (Luke Smith <https://lukesmith.xyz>'s build)
+dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
-dwm is a dynamic window manager for X.
+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
-dwm "orders" windows based on recency and primacy, while dwm layouts may
-change, the most recent "master" window is shown in the most prominent
-position. There are bindings for cycling through and promoting windows to the
-master position.
+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.
@@ -37,159 +42,124 @@ is read and displayed in the status text area. It can be set with the
.BR xsetroot (1)
command.
.TP
-.B Left click
+.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 Right click
+.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
.TP
-.B Super\-Left click
+.B Mod1\-Button1
click on a tag label applies that tag to the focused window.
.TP
-.B Super\-Right click
+.B Mod1\-Button3
click on a tag label adds/removes that tag to/from the focused window.
.SS Keyboard commands
.TP
-.B Super\-Return
-Start terminal,
+.B Mod1\-Shift\-Return
+Start
.BR st(1).
.TP
-.B Super\-d
+.B Mod1\-p
Spawn
.BR dmenu(1)
for launching other programs.
.TP
-.B Super\-grave
-Toggle scratch for the calculator.
+.B Mod1\-,
+Focus previous screen, if any.
.TP
-.B Super\-~
-Spawn
-.BR dmenuunicode(1)
-for selecting emoji.
+.B Mod1\-.
+Focus next screen, if any.
.TP
-.B Super\-minus/plus, Super\-Shift\-minus/plus
-Decrease/increase volume by 5 and 15 respectively.
+.B Mod1\-Shift\-,
+Send focused window to previous screen, if any.
.TP
-.B Super\-b
-Open bookmarks.
+.B Mod1\-Shift\-.
+Send focused window to next screen, if any.
.TP
-.B Super\-Ctrl\-b
+.B Mod1\-b
Toggles bar on and off.
.TP
-.B Super\-q
-Close focused window.
-.TP
-.B Super\-t/T
-Sets tiled/bstack layouts.
-.TP
-.B Super\-f
-Toggle fullscreen window.
-.TP
-.B Super\-F
-Toggle floating layout.
+.B Mod1\-t
+Sets tiled layout.
.TP
-.B Super\-y/Y
-Sets Fibonacci spiral/dwinde layouts.
+.B Mod1\-f
+Sets floating layout.
.TP
-.B Super\-u/U
-Sets centered master layout.
+.B Mod1\-m
+Sets monocle layout.
.TP
-.B Super\-i/I
-Sets centered master or floating master layouts.
+.B Mod1\-space
+Toggles between current and previous layout.
.TP
-.B Super\-space
-Zooms/cycles focused window to/from master area.
+.B Mod1\-j
+Focus next window.
.TP
-.B Super\-j/k
-Focus next/previous window.
+.B Mod1\-k
+Focus previous window.
.TP
-.B Super\-Shift\-j/k
-Move selected window down/up in stack.
+.B Mod1\-i
+Increase number of windows in master area.
.TP
-.B Super\-o/O
-Increase/decrease number of windows in master area.
+.B Mod1\-d
+Decrease number of windows in master area.
.TP
-.B Super\-l
+.B Mod1\-l
Increase master area size.
.TP
-.B Super\-h
+.B Mod1\-h
Decrease master area size.
.TP
-.B Super\-Shift\-space
-Toggle focused window between tiled and floating state.
-.TP
-.B Super\-Tab
-Toggles to the previously selected tags.
-.TP
-.B Super\-g
-Moves to the previous tag.
-.TP
-.B Super\-Shift\-g
-Moves selected window to the previous tag.
+.B Mod1\-o
+Select view of the window in focus. The list of tags to be displayed is matched to the window tag list.
.TP
-.B Super\-;
-Moves to the next tag.
+.B Mod1\-Return
+Zooms/cycles focused window to/from master area (tiled layouts only).
.TP
-.B Super\-Shift\-;
-Moves selected window to the next tag.
-.TP
-.B Super\-PageUp
-Moves to the previous tag.
-.TP
-.B Super\-Shift\-PageUp
-Moves selected window to the previous tag.
-.TP
-.B Super\-Pagedown
-Moves to the next tag.
-.TP
-.B Super\-Shift\-PageDown
-Moves selected window to the next tag.
+.B Mod1\-Shift\-c
+Close focused window.
.TP
-.B Super\-a
-Toggle gaps.
+.B Mod1\-Shift\-f
+Toggle fullscreen for focused window.
.TP
-.B Super\-z
-Increase gaps between windows.
+.B Mod1\-Shift\-space
+Toggle focused window between tiled and floating state.
.TP
-.B Super\-x
-Decrease gaps between windows.
+.B Mod1\-Tab
+Toggles to the previously selected tags.
.TP
-.B Super\-Shift\-[1..n]
+.B Mod1\-Shift\-[1..n]
Apply nth tag to focused window.
.TP
-.B Super\-Shift\-0
+.B Mod1\-Shift\-0
Apply all tags to focused window.
.TP
-.B Super\-Control\-Shift\-[1..n]
+.B Mod1\-Control\-Shift\-[1..n]
Add/remove nth tag to/from focused window.
.TP
-.B Super\-[1..n]
+.B Mod1\-[1..n]
View all windows with nth tag.
.TP
-.B Super\-0
+.B Mod1\-0
View all windows with any tag.
.TP
-.B Super\-Control\-[1..n]
+.B Mod1\-Control\-[1..n]
Add/remove all windows with nth tag to/from the view.
.TP
-.B Super\-Shift\-q
+.B Mod1\-Shift\-q
Quit dwm.
.TP
-.B Super\-Shift\-r
-Restart dwm.
-.TP
.B Mod1\-Control\-Shift\-q
-Menu to refresh/quit/reboot/shutdown.
+Restart dwm.
.SS Mouse commands
.TP
-.B Super\-Left click
+.B Mod1\-Button1
Move focused window while dragging. Tiled windows will be toggled to the floating state.
.TP
-.B Super\-Middle click
+.B Mod1\-Button2
Toggles focused window between floating and tiled state.
.TP
-.B Super\-Right click
+.B Mod1\-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
diff --git a/dwm/dwm.c b/dwm/dwm.c
index 3ab11c4..883ca2b 100644
--- a/dwm/dwm.c
+++ b/dwm/dwm.c
@@ -20,13 +20,7 @@
*
* To understand everything else, start reading main().
*/
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xproto.h>
-#include <X11/Xresource.h>
-#include <X11/Xutil.h>
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
+#include <ctype.h> /* for making tab label lowercase, very tiny standard library */
#include <errno.h>
#include <locale.h>
#include <signal.h>
@@ -34,250 +28,211 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <unistd.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
#include <X11/Xlib-xcb.h>
#include <xcb/res.h>
-
+#ifdef __OpenBSD__
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif /* __OpenBSD */
#include "drw.h"
#include "util.h"
-#include <assert.h>
-#include <libgen.h>
-#include <sys/stat.h>
-
/* macros */
-#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
-#define CLEANMASK(mask) \
- (mask & ~(numlockmask | LockMask) & \
- (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | \
- Mod5Mask))
-#define GETINC(X) ((X)-2000)
-#define INC(X) ((X) + 2000)
-#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 ISINC(X) ((X) > 1000 && (X) < 3000)
-#define ISVISIBLE(C) \
- ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
-#define PREVSEL 3000
-#define LENGTH(X) (sizeof X / sizeof X[0])
-#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
-#define MOD(N, M) ((N) % (M) < 0 ? (N) % (M) + (M) : (N) % (M))
-#define WIDTH(X) ((X)->w + 2 * (X)->bw)
-#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
-#define NUMTAGS (LENGTH(tags) + LENGTH(scratchpads))
-#define TAGMASK ((1 << NUMTAGS) - 1)
-#define SPTAG(i) ((1 << LENGTH(tags)) << (i))
-#define SPTAGMASK (((1 << LENGTH(scratchpads)) - 1) << LENGTH(tags))
-#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
-#define TRUNC(X, A, B) (MAX((A), MIN((X), (B))))
-#define ColFloat 3
-#define OPAQUE 0xffU
+#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+#define GETINC(X) ((X) - 2000)
+#define INC(X) ((X) + 2000)
+#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 ISINC(X) ((X) > 1000 && (X) < 3000)
+#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
+#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M))
+#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
+#define PREVSEL 3000
+#define WIDTH(X) ((X)->w + 2 * (X)->bw)
+#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
+#define NUMTAGS (LENGTH(tags) + LENGTH(scratchpads))
+#define OPAQUE 0xffU
+#define SPTAG(i) ((1 << LENGTH(tags)) << (i))
+#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
+#define TAGMASK ((1 << NUMTAGS) - 1)
+#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+#define TRUNC(X,A,B) (MAX((A), MIN((X), (B))))
+#define ColFloat 3
/* enums */
-enum
-{
- CurNormal,
- CurResize,
- CurMove,
- CurLast
-}; /* cursor */
-enum
-{
- SchemeNorm,
- SchemeSel
-}; /* color schemes */
-enum
-{
- ModeCommand,
- ModeInsert
-};
-enum
-{
- NetSupported,
- NetWMName,
- NetWMState,
- NetWMCheck,
- NetWMFullscreen,
- NetActiveWindow,
- NetWMWindowType,
- NetWMWindowTypeDialog,
- NetClientList,
- NetClientInfo,
- NetLast
-}; /* EWMH 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;
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+enum { SchemeNorm, SchemeInv, SchemeSel, SchemeStatusSel, SchemeStatusNorm, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */
+enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetWMSticky, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetWMWindowsOpacity, NetClientInfo, NetLast }; /* EWMH atoms */
+enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+enum { ClkTagBar, ClkLtSymbol, ClkMonNum, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+
+typedef union {
+ int i;
+ unsigned int ui;
+ float f;
+ const void *v;
} Arg;
-typedef struct
-{
- char *gname;
+typedef struct {
+ char *gname;
void (*func)(const Arg *arg);
const Arg arg;
} Gesture;
-typedef struct
-{
- unsigned int click;
- unsigned int mask;
- unsigned int button;
- void (*func)(const Arg *arg);
- const Arg arg;
+typedef struct {
+ unsigned int click;
+ unsigned int mask;
+ unsigned int button;
+ void (*func)(const Arg *arg);
+ const Arg arg;
} Button;
-typedef struct
-{
- unsigned int mod[4];
- KeySym keysym[4];
- void (*func)(const Arg *);
- const Arg arg;
-} Command;
-
typedef struct Monitor Monitor;
typedef struct Client Client;
-struct Client
-{
- char name[256];
- float mina, maxa;
- float cfact;
- int x, y, w, h;
- int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
- int oldx, oldy, oldw, oldh;
- int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
- int bw, oldbw;
- unsigned int tags;
- int allowkill, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow, issticky;
- unsigned char expandmask;
- int expandx1, expandy1, expandx2, expandy2;
- pid_t pid;
- Client *next;
- Client *snext;
- Client *swallowing;
- Monitor *mon;
- Window win;
+
+struct Client {
+ char name[256];
+ float mina, maxa;
+ float cfact;
+ int x, y, w, h;
+ int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
+ int oldx, oldy, oldw, oldh;
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+ int bw, oldbw;
+ unsigned int tags;
+ int wasfloating, iscentered, isfixed, isfloating, isalwaysontop, isurgent, neverfocus, oldstate, isfullscreen, issticky, cantfocus, isterminal, noswallow, resizehints;
+ pid_t pid;
+ unsigned char expandmask;
+ int expandx1, expandy1, expandx2, expandy2;
+ int allowkill;
+ Client *next;
+ Client *snext;
+ Client *swallowing;
+ double opacity;
+ double unfocusopacity;
+ Monitor *mon;
+ Window win;
};
-typedef struct
-{
- unsigned int mod;
- KeySym keysym;
- void (*func)(const Arg *);
- const Arg arg;
+typedef struct {
+ unsigned int mod;
+ KeySym keysym;
} Key;
-typedef struct
-{
- const char *symbol;
- void (*arrange)(Monitor *);
+typedef struct {
+ unsigned int n;
+ const Key keys[5];
+ void (*func)(const Arg *);
+ const Arg arg;
+} Keychord;
+
+typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
} Layout;
typedef struct Pertag Pertag;
-
-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 gappih; /* horizontal gap between windows */
- int gappiv; /* vertical gap between windows */
- int gappoh; /* horizontal outer gaps */
- int gappov; /* vertical outer gaps */
- unsigned int seltags;
- unsigned int sellt;
- unsigned int tagset[2];
- int showbar;
- unsigned int barmask;
- int topbar;
- Client *clients;
- Client *sel;
- Client *stack;
- Monitor *next;
- Window barwin;
- const Layout *lt[2];
- Pertag *pertag;
- int ltcur; /* current layout */
+struct Monitor {
+ char ltsymbol[16];
+ char monmark[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 gappih; /* horizontal gap between windows */
+ int gappiv; /* vertical gap between windows */
+ int gappoh; /* horizontal outer gaps */
+ int gappov; /* vertical outer gaps */
+ unsigned int borderpx;
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+ int showbar;
+ int showtitle;
+ int showtags;
+ int showlayout;
+ int showstatus;
+ int showfloating;
+ int topbar;
+ Client *clients;
+ Client *sel;
+ Client *stack;
+ Client *tagmarked[32];
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
+ int ltcur; /* current layout */
+ Pertag *pertag;
};
-typedef struct
-{
- const char *class;
- const char *instance;
- const char *title;
- unsigned int tags;
- int allowkill;
- int isfloating;
- int isterminal;
- int noswallow;
- int monitor;
+typedef struct {
+ const char *class;
+ const char *instance;
+ const char *title;
+ unsigned int tags;
+ int allowkill;
+ double opacity;
+ double unfocusopacity;
+ int isfloating;
+ int isterminal;
+ int noswallow;
+ int monitor;
+ int resizehints;
+ int bw;
} Rule;
/* Xresources preferences */
-enum resource_type
-{
- STRING = 0,
- INTEGER = 1,
- FLOAT = 2
+enum resource_type {
+ STRING = 0,
+ INTEGER = 1,
+ FLOAT = 2
};
-typedef struct
-{
- char *name;
- enum resource_type type;
- void *dst;
+typedef struct {
+ char *name;
+ enum resource_type type;
+ void *dst;
} ResourcePref;
/* function declarations */
+static void alttab(const Arg *arg);
static void applyrules(Client *c);
-static int applysizehints(Client *c, int *x, int *y, int *w, int *h,
- int interact);
+static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
+static void changefocusopacity(const Arg *arg);
+static void changeunfocusopacity(const Arg *arg);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
-static void clearcmd(const Arg *arg);
static void clientmessage(XEvent *e);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
-static void copyvalidchars(char *text, char *rawtext);
static Monitor *createmon(void);
static void destroynotify(XEvent *e);
static void detach(Client *c);
@@ -289,19 +244,22 @@ static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
+static void focusmaster(const Arg *arg);
static void focusmon(const Arg *arg);
+static void focusnext(const Arg *arg);
+static void focusnthmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
+static pid_t getstatusbarpid();
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
-static void keypresscmd(XEvent *e);
-static void killclient(const Arg *arg);
static void killthis(Client *c);
+static void killclient(const Arg *arg);
static void layoutmenu(const Arg *arg);
static void layoutscroll(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
@@ -309,59 +267,78 @@ static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
+static void ntoggleview(const Arg *arg);
+static Monitor *numtomon(int num);
+static void nview(const Arg *arg);
static void gesture(const Arg *arg);
static void movemouse(const Arg *arg);
+static void movecenter(const Arg *arg);
static Client *nexttiled(Client *c);
+static void opacity(Client *c, double opacity);
static void pop(Client *c);
static void propertynotify(XEvent *e);
static void pushstack(const Arg *arg);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
+static void resetlayout(const Arg *arg);
+static void resetnmaster(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
+static void resetcanfocusfloating();
static void restack(Monitor *m);
static void run(void);
static void runAutostart(void);
static void scan(void);
+static void scratchpad_hide();
+static void scratchpad_remove();
+static void scratchpad_show();
+static void scratchpad_show_client(Client *c);
+static void scratchpad_show_first(int scratchNum);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
+static void setborderpx(const Arg *arg);
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 setinsertmode(void);
-static void setkeymode(const Arg *arg);
+static void setcfact(const Arg *arg);
static void setlayout(const Arg *arg);
static void setmark(Client *c);
-static void setcfact(const Arg *arg);
static void setmfact(const Arg *arg);
+static void setsticky(Client *c, int sticky);
static void setup(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
-static void sigchld(int unused);
-#ifndef __OpenBSD__
-static int getdwmblockspid();
-static void sigdwmblocks(const Arg *arg);
-#endif
static void sighup(int unused);
+static void sigstatusbar(const Arg *arg);
static void sigterm(int unused);
static void spawn(const Arg *arg);
+static int stackpos(const Arg *arg);
static void swapclient(const Arg *arg);
static void swapfocus(const Arg *arg);
-static int stackpos(const Arg *arg);
static void tag(const Arg *arg);
-static void tagmon(const Arg *arg);
static void spawntag(const Arg *arg);
+static void tagmon(const Arg *arg);
+static void tagnthmon(const Arg *arg);
+static void toggleall(const Arg *arg);
+static void toggleallowkill(const Arg *arg);
+static void togglealwaysontop(const Arg *arg);
static void togglebar(const Arg *arg);
+static void togglebartags(const Arg *arg);
+static void togglebartitle(const Arg *arg);
+static void togglebarlt(const Arg *arg);
+static void togglebarstatus(const Arg *arg);
+static void togglebarfloat(const Arg *arg);
static void toggleborder(const Arg *arg);
+static void togglecanfocusfloating(const Arg *arg);
static void togglefloating(const Arg *arg);
-static void toggleallowkill(const Arg *arg);
+static void togglefullscr(const Arg *arg);
static void togglemark(const Arg *arg);
static void togglescratch(const Arg *arg);
static void togglesticky(const Arg *arg);
-static void togglefullscr(const Arg *arg);
static void toggletag(const Arg *arg);
+static void toggletopbar(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
@@ -377,14 +354,15 @@ static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
+static void viewall(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
+static void winview(const Arg* arg);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void xinitvisual();
static void zoom(const Arg *arg);
-static void xrdb(const Arg *arg);
static void load_xresources(void);
static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
@@ -395,36 +373,36 @@ static Client *termforwin(const Client *c);
static pid_t winpid(Window w);
/* variables */
+static Client *prevclient = NULL;
static const char broken[] = "broken";
static char stext[256];
-static char rawstext[256];
-static int dwmblockssig;
-pid_t dwmblockspid = 0;
+static int statusw;
+static int statussig;
+static pid_t statuspid = -1;
static int screen;
-static int sw, sh; /* X display screen geometry width, height */
-static int bh; /* bar height */
-static int lrpad; /* sum of left and right padding for text */
-static int vp; /* vertical padding for bar */
-static int sp; /* side padding for bar */
+static int sw, sh; /* X display screen geometry width, height */
+static int bh; /* bar height */
+static int lrpad; /* sum of left and right padding for text */
+static int vp; /* vertical padding for bar */
+static int sp; /* side padding for bar */
static int (*xerrorxlib)(Display *, XErrorEvent *);
-static unsigned int cmdmod[4];
-static unsigned int keymode = ModeCommand;
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,
- [UnmapNotify] = unmapnotify};
+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,
+ [UnmapNotify] = unmapnotify
+};
static Atom wmatom[WMLast], netatom[NetLast];
static int restart = 0;
static int running = 1;
@@ -432,1340 +410,1416 @@ static Cur *cursor[CurLast];
static Clr **scheme;
static Display *dpy;
static Drw *drw;
-static KeySym cmdkeysym[4];
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
static Client *mark;
+static xcb_connection_t *xcon;
static int useargb = 0;
static Visual *visual;
static int depth;
static Colormap cmap;
-static xcb_connection_t *xcon;
+/* scratchpad */
+#define SCRATCHPAD_MASK_1 (1u << sizeof tags / sizeof * tags)
+#define SCRATCHPAD_MASK_2 (1u << (sizeof tags / sizeof * tags + 1))
+#define SCRATCHPAD_MASK_3 (1u << (sizeof tags / sizeof * tags + 2))
+static int scratchpad_hide_flag = 0;
+static Client *scratchpad_last_showed_1 = NULL;
+static Client *scratchpad_last_showed_2 = NULL;
+static Client *scratchpad_last_showed_3 = NULL;
+
+unsigned int currentkey = 0;
/* configuration, allows nested code to access above variables */
#include "config.h"
-struct Pertag
-{
- unsigned int curtag, prevtag; /* current and previous tag */
- int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
- float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
- unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
- const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
+struct Pertag {
+ unsigned int curtag, prevtag; /* current and previous tag */
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
+ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+ Client *sel[LENGTH(tags) + 1]; /* selected client */
};
+unsigned int tagw[LENGTH(tags)];
+
/* compile-time check if all tags fit into an unsigned int bit array. */
-struct NumTags
-{
- char limitexceeded[LENGTH(tags) > 31 ? -1 : 1];
-};
+struct NumTags { char limitexceeded[LENGTH(tags) > 28 ? -1 : 1]; };
/* function implementations */
+
+static void
+alttab(const Arg *arg) {
+
+ view(&(Arg){ .ui = ~0 });
+ focusnext(&(Arg){ .i = alt_tab_direction });
+
+ int grabbed = 1;
+ int grabbed_keyboard = 1000;
+ for (int i = 0; i < 100; i += 1) {
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+
+ if (grabbed_keyboard != GrabSuccess) {
+ grabbed_keyboard = XGrabKeyboard(dpy, DefaultRootWindow(dpy), True,
+ GrabModeAsync, GrabModeAsync, CurrentTime);
+ }
+ if (grabbed_keyboard == GrabSuccess) {
+ XGrabButton(dpy, AnyButton, AnyModifier, None, False,
+ BUTTONMASK, GrabModeAsync, GrabModeAsync,
+ None, None);
+ break;
+ }
+ nanosleep(&ts, NULL);
+ if (i == 100 - 1)
+ grabbed = 0;
+ }
+
+ XEvent event;
+ Client *c;
+ Monitor *m;
+ XButtonPressedEvent *ev;
+
+ while (grabbed) {
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case KeyPress:
+ if (event.xkey.keycode == tabCycleKey)
+ focusnext(&(Arg){ .i = alt_tab_direction });
+ break;
+ case KeyRelease:
+ if (event.xkey.keycode == tabModKey) {
+ XUngrabKeyboard(dpy, CurrentTime);
+ XUngrabButton(dpy, AnyButton, AnyModifier, None);
+ grabbed = 0;
+ alt_tab_direction = !alt_tab_direction;
+ winview(0);
+ }
+ break;
+ case ButtonPress:
+ ev = &(event.xbutton);
+ if ((m = wintomon(ev->window)) && m != selmon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ focus(NULL);
+ }
+ if ((c = wintoclient(ev->window)))
+ focus(c);
+ XAllowEvents(dpy, AsyncBoth, CurrentTime);
+ break;
+ case ButtonRelease:
+ XUngrabKeyboard(dpy, CurrentTime);
+ XUngrabButton(dpy, AnyButton, AnyModifier, None);
+ grabbed = 0;
+ alt_tab_direction = !alt_tab_direction;
+ winview(0);
+ break;
+ }
+ }
+ return;
+}
+
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;
- c->allowkill = allowkill;
- 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->isterminal = r->isterminal;
- c->isfloating = r->isfloating;
- c->noswallow = r->noswallow;
- c->tags |= r->tags;
- c->allowkill = r->allowkill;
- if ((r->tags & SPTAGMASK) && r->isfloating)
- {
- c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
- c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
- }
-
- 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);
+ const char *class, *instance;
+ unsigned int i;
+ const Rule *r;
+ Monitor *m;
+ XClassHint ch = { NULL, NULL };
+
+ /* rule matching */
+ c->isfloating = 0;
+ c->tags = 0;
+ c->allowkill = allowkill;
+ c->opacity = activeopacity;
+ c->unfocusopacity = inactiveopacity;
+ c->bw = borderpx;
+ 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->isterminal = r->isterminal;
+ c->noswallow = r->noswallow;
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
+ c->allowkill = r->allowkill;
+ c->opacity = r->opacity;
+ c->unfocusopacity = r->unfocusopacity;
+ c->resizehints = r->resizehints;
+ if (r->bw != -1)
+ c->bw = r->bw;
+ if ((r->tags & SPTAGMASK) && r->isfloating) {
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
+ }
+ 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);
+ if(c->tags != SCRATCHPAD_MASK_1 && c->tags != SCRATCHPAD_MASK_2 && c->tags != SCRATCHPAD_MASK_3)
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK);
}
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)
- {
- if (!c->hintsvalid)
- updatesizehints(c);
- /* 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;
+ 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 (c->resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+ if (!c->hintsvalid)
+ updatesizehints(c);
+ /* 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);
+ 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);
+ 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;
+ c->next = c->mon->clients;
+ c->mon->clients = c;
}
void
attachstack(Client *c)
{
- c->snext = c->mon->stack;
- c->mon->stack = c;
+ c->snext = c->mon->stack;
+ c->mon->stack = c;
}
void
swallow(Client *p, Client *c)
{
- if (c->noswallow || c->isterminal)
- return;
- if (!swallowfloating && c->isfloating)
- return;
-
- detach(c);
- detachstack(c);
- setclientstate(c, WithdrawnState);
- XUnmapWindow(dpy, p->win);
+ if (c->noswallow || c->isterminal)
+ return;
+ if (c->noswallow && !swallowfloating && c->isfloating)
+ return;
- p->swallowing = c;
- c->mon = p->mon;
+ detach(c);
+ detachstack(c);
- Window w = p->win;
- p->win = c->win;
- c->win = w;
- updatetitle(p);
+ setclientstate(c, WithdrawnState);
+ XUnmapWindow(dpy, p->win);
- XWindowChanges wc;
- wc.border_width = p->bw;
- XConfigureWindow(dpy, p->win, CWBorderWidth, &wc);
- XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
- XSetWindowBorder(dpy, p->win, scheme[SchemeNorm][ColBorder].pixel);
+ p->swallowing = c;
+ c->mon = p->mon;
- arrange(p->mon);
- configure(p);
- updateclientlist();
+ Window w = p->win;
+ p->win = c->win;
+ c->win = w;
+ updatetitle(p);
+ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
+ arrange(p->mon);
+ configure(p);
+ updateclientlist();
}
void
unswallow(Client *c)
{
- c->win = c->swallowing->win;
-
- free(c->swallowing);
- c->swallowing = NULL;
+ c->win = c->swallowing->win;
- /* unfullscreen the client */
- setfullscreen(c, 0);
- updatetitle(c);
- arrange(c->mon);
- XMapWindow(dpy, c->win);
-
- XWindowChanges wc;
- wc.border_width = c->bw;
- XConfigureWindow(dpy, c->win, CWBorderWidth, &wc);
- XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ free(c->swallowing);
+ c->swallowing = NULL;
- setclientstate(c, NormalState);
- focus(NULL);
- arrange(c->mon);
+ /* unfullscreen the client */
+ setfullscreen(c, 0);
+ updatetitle(c);
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ setclientstate(c, NormalState);
+ focus(NULL);
+ arrange(c->mon);
}
void
buttonpress(XEvent *e)
{
- unsigned int i, x, click, occ = 0;
- 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;
- for (c = m->clients; c; c = c->next)
- occ |= c->tags == 255 ? 0 : c->tags;
- do
- {
- /* do not reserve space for vacant tags */
- if (!(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 + TEXTW(selmon->ltsymbol))
- click = ClkLtSymbol;
- else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad))
- {
- click = ClkStatusText;
-
- char *text = rawstext;
- int i = -1;
- char ch;
- dwmblockssig = 0;
- while (text[++i])
- {
- if ((unsigned char)text[i] < ' ')
- {
- ch = text[i];
- text[i] = '\0';
- x += TEXTW(text) - lrpad;
- text[i] = ch;
- text += i + 1;
- i = -1;
- if (x >= ev->x)
- break;
- dwmblockssig = ch;
- }
- }
- }
- 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);
+ unsigned int i, x, click;
+ Arg arg = {0};
+ Client *c;
+ Monitor *m;
+ XButtonPressedEvent *ev = &e->xbutton;
+ char *text, *s, ch;
+
+ 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 == TAGMASK ? 0 : c->tags;
+ do {
+ /* Do not reserve space for vacant tags */
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+ if (selmon->showtags)
+ x += tagw[i];
+ } while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags) && selmon->showtags) {
+ click = ClkTagBar;
+ arg.ui = 1 << i;
+ } else if (ev->x < x + TEXTW(selmon->ltsymbol) && selmon->showlayout)
+ click = ClkLtSymbol;
+ else if (ev->x < x + TEXTW(selmon->ltsymbol) + TEXTW(selmon->monmark))
+ click = ClkMonNum;
+ else if (ev->x > selmon->ww - statusw && selmon->showstatus) {
+ x = selmon->ww - statusw;
+ click = ClkStatusText;
+ statussig = 0;
+ for (text = s = stext; *s && x <= ev->x; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ x += TEXTW(text) - lrpad;
+ *s = ch;
+ text = s + 1;
+ if (x >= ev->x)
+ break;
+ /* reset on matching signal raw byte */
+ if (ch == statussig)
+ statussig = 0;
+ else
+ statussig = ch;
+ }
+ }
+ } else if (selmon->showtitle)
+ 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)
+changefocusopacity(const Arg *arg)
{
- 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);
+ if (!selmon->sel)
+ return;
+ selmon->sel->opacity+=arg->f;
+ if(selmon->sel->opacity > 1.0)
+ selmon->sel->opacity = 1.0;
+
+ if(selmon->sel->opacity < 0.1)
+ selmon->sel->opacity = 0.1;
+
+ opacity(selmon->sel, selmon->sel->opacity);
}
void
-cleanup(void)
+changeunfocusopacity(const Arg *arg)
{
- 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);
- for (i = 0; i < CurLast; i++)
- drw_cur_free(drw, cursor[i]);
- for (i = 0; i < LENGTH(colors); 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]);
+ if (!selmon->sel)
+ return;
+ selmon->sel->unfocusopacity+=arg->f;
+ if(selmon->sel->unfocusopacity > 1.0)
+ selmon->sel->unfocusopacity = 1.0;
+
+ if(selmon->sel->unfocusopacity < 0.1)
+ selmon->sel->unfocusopacity = 0.1;
+
+ opacity(selmon->sel, selmon->sel->unfocusopacity);
}
void
-cleanupmon(Monitor *mon)
+checkotherwm(void)
{
- Monitor *m;
+ 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);
+}
- 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
+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);
+ for (i = 0; i < CurLast; i++)
+ drw_cur_free(drw, cursor[i]);
+ for (i = 0; i < LENGTH(colors); 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
-clearcmd(const Arg *arg)
+cleanupmon(Monitor *mon)
{
- unsigned int i;
+ Monitor *m;
- for (i = 0; i < LENGTH(cmdkeysym); i++)
- {
- cmdkeysym[i] = 0;
- cmdmod[i] = 0;
- }
+ 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)
{
- XClientMessageEvent *cme = &e->xclient;
- Client *c = wintoclient(cme->window);
-
- if (!c)
- return;
- if (cme->message_type == netatom[NetWMState])
- {
- if (cme->data.l[1] == netatom[NetWMFullscreen] ||
- cme->data.l[2] == netatom[NetWMFullscreen])
- setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
- || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ &&
- !c->isfullscreen)));
- }
- else if (cme->message_type == netatom[NetActiveWindow])
- {
- if (c != selmon->sel && !c->isurgent)
- seturgent(c, 1);
- }
+ XClientMessageEvent *cme = &e->xclient;
+ Client *c = wintoclient(cme->window);
+
+ if (!c)
+ return;
+ if (cme->message_type == netatom[NetWMState]) {
+ if (cme->data.l[1] == netatom[NetWMFullscreen]
+ || cme->data.l[2] == netatom[NetWMFullscreen])
+ setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ if (cme->data.l[1] == netatom[NetWMSticky]
+ || cme->data.l[2] == netatom[NetWMSticky])
+ setsticky(c, (cme->data.l[0] == 1 || (cme->data.l[0] == 2 && !c->issticky)));
+ } else if (cme->message_type == netatom[NetActiveWindow]) {
+ if (!ISVISIBLE(c)) {
+ c->mon->seltags ^= 1;
+ c->mon->tagset[c->mon->seltags] = c->tags;
+ }
+ pop(c);
+ }
}
void
configure(Client *c)
{
- XConfigureEvent ce;
+ XConfigureEvent ce;
- ce.type = ConfigureNotify;
- ce.display = dpy;
- ce.event = c->win;
- ce.window = c->win;
- ce.x = c->x;
- ce.y = c->y;
- ce.width = c->w;
- ce.height = c->h;
- ce.border_width = c->bw;
- ce.above = None;
- ce.override_redirect = False;
- XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
+ ce.type = ConfigureNotify;
+ ce.display = dpy;
+ ce.event = c->win;
+ ce.window = c->win;
+ ce.x = c->x;
+ ce.y = c->y;
+ ce.width = c->w;
+ ce.height = c->h;
+ ce.border_width = c->bw;
+ ce.above = None;
+ ce.override_redirect = False;
+ XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}
void
configurenotify(XEvent *e)
{
- Monitor *m;
- Client *c;
- XConfigureEvent *ev = &e->xconfigure;
- int dirty;
-
- /* TODO: updategeom handling sucks, needs to be simplified */
- if (ev->window == root)
- {
- dirty = (sw != ev->width || sh != ev->height);
- sw = ev->width;
- sh = ev->height;
- if (updategeom() || dirty)
- {
- drw_resize(drw, sw, bh);
- updatebars();
- for (m = mons; m; m = m->next)
- {
- for (c = m->clients; c; c = c->next)
- if (c->isfullscreen)
- resizeclient(c, m->mx, m->my, m->mw, m->mh);
- XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
- }
- focus(NULL);
- arrange(NULL);
- }
- }
+ Monitor *m;
+ Client *c;
+ XConfigureEvent *ev = &e->xconfigure;
+ int dirty;
+
+ /* TODO: updategeom handling sucks, needs to be simplified */
+ if (ev->window == root) {
+ dirty = (sw != ev->width || sh != ev->height);
+ sw = ev->width;
+ sh = ev->height;
+ if (updategeom() || dirty) {
+ drw_resize(drw, sw, bh);
+ updatebars();
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next)
+ if (c->isfullscreen)
+ resizeclient(c, m->mx, m->my, m->mw, m->mh);
+ XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
+ }
+ focus(NULL);
+ arrange(NULL);
+ }
+ }
}
void
configurerequest(XEvent *e)
{
- Client *c;
- Monitor *m;
- XConfigureRequestEvent *ev = &e->xconfigurerequest;
- XWindowChanges wc;
-
- if ((c = wintoclient(ev->window)))
- {
- if (ev->value_mask & CWBorderWidth)
- c->bw = ev->border_width;
- else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange)
- {
- m = c->mon;
- if (ev->value_mask & CWX)
- {
- c->oldx = c->x;
- c->x = m->mx + ev->x;
- }
- if (ev->value_mask & CWY)
- {
- c->oldy = c->y;
- c->y = m->my + ev->y;
- }
- if (ev->value_mask & CWWidth)
- {
- c->oldw = c->w;
- c->w = ev->width;
- }
- if (ev->value_mask & CWHeight)
- {
- c->oldh = c->h;
- c->h = ev->height;
- }
- if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
- c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
- if ((c->y + c->h) > m->my + m->mh && c->isfloating)
- c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
- if ((ev->value_mask & (CWX | CWY)) &&
- !(ev->value_mask & (CWWidth | CWHeight)))
- configure(c);
- if (ISVISIBLE(c))
- XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
- }
- else
- configure(c);
- }
- else
- {
- wc.x = ev->x;
- wc.y = ev->y;
- wc.width = ev->width;
- wc.height = ev->height;
- wc.border_width = ev->border_width;
- wc.sibling = ev->above;
- wc.stack_mode = ev->detail;
- XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
- }
- XSync(dpy, False);
-}
-
-void
-copyvalidchars(char *text, char *rawtext)
-{
- int i = -1, j = 0;
-
- while (rawtext[++i])
- {
- if ((unsigned char)rawtext[i] >= ' ')
- {
- text[j++] = rawtext[i];
- }
- }
- text[j] = '\0';
-}
-
-Monitor *createmon(void)
-{
- Monitor *m;
- int i;
-
- m = ecalloc(1, sizeof(Monitor));
- m->tagset[0] = m->tagset[1] = 1;
- m->mfact = mfact;
- m->nmaster = nmaster;
- m->showbar = showbar;
- m->barmask = showbar * TAGMASK;
- m->topbar = topbar;
- m->gappih = gappih;
- m->gappiv = gappiv;
- m->gappoh = gappoh;
- m->gappov = gappov;
- m->ltcur = 0;
- m->lt[0] = &layouts[0];
- m->lt[1] = &layouts[1 % LENGTH(layouts)];
- strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
- if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
- die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+ Client *c;
+ Monitor *m;
+ XConfigureRequestEvent *ev = &e->xconfigurerequest;
+ XWindowChanges wc;
+
+ if ((c = wintoclient(ev->window))) {
+ if (ev->value_mask & CWBorderWidth)
+ c->bw = ev->border_width;
+ else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
+ m = c->mon;
+ if (ev->value_mask & CWX) {
+ c->oldx = c->x;
+ c->x = m->mx + ev->x;
+ }
+ if (ev->value_mask & CWY) {
+ c->oldy = c->y;
+ c->y = m->my + ev->y;
+ }
+ if (ev->value_mask & CWWidth) {
+ c->oldw = c->w;
+ c->w = ev->width;
+ }
+ if (ev->value_mask & CWHeight) {
+ c->oldh = c->h;
+ c->h = ev->height;
+ }
+ if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
+ c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
+ if ((c->y + c->h) > m->my + m->mh && c->isfloating)
+ c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
+ if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
+ configure(c);
+ if (ISVISIBLE(c))
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ } else
+ configure(c);
+ } else {
+ wc.x = ev->x;
+ wc.y = ev->y;
+ wc.width = ev->width;
+ wc.height = ev->height;
+ wc.border_width = ev->border_width;
+ wc.sibling = ev->above;
+ wc.stack_mode = ev->detail;
+ XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
+ }
+ XSync(dpy, False);
+}
+
+Monitor *
+createmon(void)
+{
+ Monitor *m;
+ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->showtitle = showtitle;
+ m->showtags = showtags;
+ m->showlayout = showlayout;
+ m->showstatus = showstatus;
+ m->showfloating = showfloating;
+ m->topbar = topbar;
+ m->ltcur = 0;
+ m->borderpx = borderpx;
+ m->gappih = gappih;
+ m->gappiv = gappiv;
+ m->gappoh = gappoh;
+ m->gappov = gappov;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ m->pertag = ecalloc(1, sizeof(Pertag));
m->pertag->curtag = m->pertag->prevtag = 1;
- for (i=0; i <= LENGTH(tags); i++) {
- /* init nmaster */
- m->pertag->nmasters[i] = m->nmaster;
- /* init mfacts */
+ for (i = 0; i <= LENGTH(tags); i++) {
+ m->pertag->nmasters[i] = m->nmaster;
m->pertag->mfacts[i] = m->mfact;
- /* init layouts */
m->pertag->ltidxs[i][0] = m->lt[0];
m->pertag->ltidxs[i][1] = m->lt[1];
m->pertag->sellts[i] = m->sellt;
+
+ m->pertag->showbars[i] = m->showbar;
}
- return m;
+
+ /* this is actually set in updategeom, to avoid a race condition */
+ // snprintf(m->monmark, sizeof(m->monmark), "(%d)", m->num);
+ return m;
}
void
destroynotify(XEvent *e)
{
- Client *c;
- XDestroyWindowEvent *ev = &e->xdestroywindow;
+ Client *c;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
- if ((c = wintoclient(ev->window)))
- unmanage(c, 1);
-
- else if ((c = swallowingclient(ev->window)))
- unmanage(c->swallowing, 1);
+ if ((c = wintoclient(ev->window)))
+ unmanage(c, 1);
+ else if ((c = swallowingclient(ev->window)))
+ unmanage(c->swallowing, 1);
}
void
detach(Client *c)
{
- Client **tc;
+ Client **tc;
+
+ for (int i = 1; i < LENGTH(tags); i++)
+ if (c == c->mon->tagmarked[i])
+ c->mon->tagmarked[i] = NULL;
- for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next)
- ;
- *tc = c->next;
+ for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
+ *tc = c->next;
}
void
detachstack(Client *c)
{
- Client **tc, *t;
+ Client **tc, *t;
- for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext)
- ;
- *tc = c->snext;
+ for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
+ *tc = c->snext;
- if (c == c->mon->sel)
- {
- for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext)
- ;
- c->mon->sel = t;
- }
+ if (c == c->mon->sel) {
+ for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
+ c->mon->sel = t;
+ }
}
-Monitor *dirtomon(int dir)
+Monitor *
+dirtomon(int dir)
{
- Monitor *m = NULL;
+ Monitor *m = NULL;
- if (dir > 0)
- {
- if (!(m = selmon->next))
- m = mons;
- }
- else if (selmon == mons)
- for (m = mons; m->next; m = m->next)
- ;
- else
- for (m = mons; m->next != selmon; m = m->next)
- ;
- return m;
+ if (dir > 0) {
+ if (!(m = selmon->next))
+ m = mons;
+ } else if (selmon == mons)
+ for (m = mons; m->next; m = m->next);
+ else
+ for (m = mons; m->next != selmon; m = m->next);
+ return m;
+}
+
+Monitor *
+numtomon(int num)
+{
+ Monitor *m = NULL;
+ int i = 0;
+
+ for(m = mons, i=0; m->next && i < num; m = m->next){
+ i++;
+ }
+ return m;
}
void
drawbar(Monitor *m)
{
- int x = 0, w, tw = 0, moveright = 0;
- int boxs = drw->fonts->h / 9;
- int boxw = drw->fonts->h / 6 + 2;
- unsigned int i, j, occ = 0, urg = 0;
- Client *c;
+ int x, w, tw = 0;
+ int boxs = drw->fonts->h / 9;
+ int boxw = drw->fonts->h / 6 + 2;
+ unsigned int i, occ = 0, urg = 0;
+ Client *c;
+ char tagdisp[64];
+ char *masterclientontag[LENGTH(tags)];
- if (!(m->tagset[m->seltags] & m->barmask))
- return;
- if (barlayout[0] == '\0')
- barlayout = "tln|s";
-
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_text(drw, 0, 0, m->ww, bh, 0, "", 0); /* draw background */
-
- for (i = 0; i < strlen(barlayout); i++) {
- switch (barlayout[i]) {
- case 'l':
- w = TEXTW(m->ltsymbol);
- drw_setscheme(drw, scheme[SchemeNorm]);
- if (moveright) {
- x -= w;
- drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
- } else
- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
- break;
- case 'n':
- tw = TEXTW(m->sel->name);
- if (moveright)
- x -= tw;
- if (m->sel) {
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
- drw_text(drw, x, 0, moveright ? tw : m->ww, bh, lrpad / 2, m->sel->name, 0);
- if (m->sel->isfloating)
- drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
- } else {
- drw_rect(drw, x, 0, tw, bh, 1, 1);
- }
+ if (!m->showbar)
+ return;
- if (!moveright)
- x += tw;
- break;
- case 's':
- if (m == selmon) { /* status is only drawn on selected monitor */
- drw_setscheme(drw, scheme[SchemeNorm]);
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
- if (moveright) {
- x -= tw;
- drw_text(drw, x, 0, tw, bh, 0, stext, 0);
- } else
- x = drw_text(drw, x, 0, tw, bh, 0, stext, 0);
- }
- break;
- case 't':
- for (c = m->clients; c; c = c->next) {
- occ |= c->tags == 255 ? 0 : c->tags;
- if (c->isurgent)
- urg |= c->tags;
- }
- /* tags */
- if (moveright) {
- tw = 0;
- for (j = 0; j < LENGTH(tags); j++) {
- tw += TEXTW(tags[j]);
- }
- x -= tw;
- }
- for (j = 0; j < LENGTH(tags); j++) {
- /* do not draw vacant tags */
- if (!(occ & 1 << j || m->tagset[m->seltags] & 1 << j))
- continue;
-
- w = TEXTW(tags[j]);
- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << j ? SchemeSel : SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[j], urg & 1 << j);
- if (keymode == ModeCommand && selmon->tagset[selmon->seltags] & (1 << j)) {
- drw_rect(drw, x + ulinepad, bh - ulinestroke - ulinevoffset, w - (ulinepad * 2), ulinestroke,
- m == selmon && selmon->sel && selmon->sel->tags & 1 << j,
- urg & 1 << j);
- }
-
- x += w;
- }
- if (moveright)
- x -= tw;
- break;
- case '|':
- moveright = 1;
- x = m->ww;
- break;
- }
- }
+ /* draw status first so it can be overdrawn by tags later */
+ if ((m == selmon && selmon->showstatus) || (statusall && selmon->showstatus)) { /* status is only drawn on selected monitor */
+ char *text, *s, ch;
+ if (m == selmon)
+ drw_setscheme(drw, scheme[SchemeStatusSel]);
+ else
+ drw_setscheme(drw, scheme[SchemeStatusNorm]);
+ x = 0;
+ for (text = s = stext; *s; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ tw = TEXTW(text) - lrpad;
+ drw_text(drw, m->ww - statusw + x - 2 * sp, 0, tw, bh, 0, text, 0);
+ x += tw;
+ *s = ch;
+ text = s + 1;
+ }
+ }
+ tw = TEXTW(text) - lrpad + 2;
+ drw_text(drw, m->ww - statusw + x - 2 * sp, 0, tw, bh, 0, text, 0);
+ tw = statusw;
+ }
- drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+ for (i = 0; i < LENGTH(tags); i++)
+ masterclientontag[i] = NULL;
+
+ for (c = m->clients; c; c = c->next) {
+ occ |= c->tags == TAGMASK ? 0 : c->tags;
+ if (c->isurgent && selmon->showtags)
+ urg |= c->tags;
+ for (i = 0; i < LENGTH(tags); i++)
+ if (!masterclientontag[i] && c->tags & (1<<i)) {
+ XClassHint ch = { NULL, NULL };
+ XGetClassHint(dpy, c->win, &ch);
+ masterclientontag[i] = ch.res_class;
+ if (lcaselbl)
+ masterclientontag[i][0] = tolower(masterclientontag[i][0]);
+ }
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+ /* Do not draw vacant tags */
+ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+ if (selmon->showtags) {
+ if (taglbl && masterclientontag[i])
+ snprintf(tagdisp, 64, ptagf, tags[i], masterclientontag[i]);
+ else
+ snprintf(tagdisp, 64, etagf, tags[i]);
+ masterclientontag[i] = tagdisp;
+ tagw[i] = w = TEXTW(masterclientontag[i]);
+ if (m == selmon)
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]);
+ else
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeInv : SchemeTagsNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, masterclientontag[i], urg & 1 << i);
+ x += w;
+ }
+ }
+
+ /* draw layout indicator if selmon->showlayout */
+ if (selmon->showlayout) {
+ w = TEXTW(m->ltsymbol);
+ drw_setscheme(drw, scheme[SchemeTagsNorm]);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+ w = TEXTW(m->monmark);
+ drw_setscheme(drw, scheme[SchemeTagsNorm]);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->monmark, 0);
+ }
+
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel && selmon->showtitle) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]);
+ drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating && selmon->showfloating) {
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ if (m->sel->isalwaysontop)
+ drw_rect(drw, x + boxs, bh - boxw, boxw, boxw, 0, 0);
+ }
+ if (m->sel->issticky)
+ drw_polygon(drw, x + boxs, m->sel->isfloating ? boxs * 2 + boxw : boxs, stickyiconbb.x, stickyiconbb.y, boxw, boxw * stickyiconbb.y / stickyiconbb.x, stickyicon, LENGTH(stickyicon), Nonconvex, m->sel->tags & m->tagset[m->seltags]);
+ } else {
+ // drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_setscheme(drw, scheme[SchemeInfoNorm]);
+ drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
+ }
+ }
+ drw_map(drw, m->barwin, 0, 0, m->ww, bh);
}
void
drawbars(void)
{
- Monitor *m;
+ Monitor *m;
- for (m = mons; m; m = m->next)
- drawbar(m);
+ for (m = mons; m; m = m->next)
+ drawbar(m);
}
void
enternotify(XEvent *e)
{
- Client *c;
- Monitor *m;
- XCrossingEvent *ev = &e->xcrossing;
-
- if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) &&
- ev->window != root)
- return;
- c = wintoclient(ev->window);
- m = c ? c->mon : wintomon(ev->window);
- if (m != selmon)
- {
- unfocus(selmon->sel, 1);
- selmon = m;
- }
- else if (!c || c == selmon->sel)
- return;
- focus(c);
+ Client *c;
+ Monitor *m;
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
+ return;
+ c = wintoclient(ev->window);
+ m = c ? c->mon : wintomon(ev->window);
+ if (m != selmon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ } else if (!c || c == selmon->sel)
+ return;
+ focus(c);
}
void
expose(XEvent *e)
{
- Monitor *m;
- XExposeEvent *ev = &e->xexpose;
+ Monitor *m;
+ XExposeEvent *ev = &e->xexpose;
- if (ev->count == 0 && (m = wintomon(ev->window)))
- drawbar(m);
+ if (ev->count == 0 && (m = wintomon(ev->window)))
+ drawbar(m);
}
void
focus(Client *c)
{
- if (!c || !ISVISIBLE(c))
- {
- for (c = selmon->stack;
- c && (!ISVISIBLE(c) || (c->issticky && !selmon->sel->issticky));
- c = c->snext)
- ;
-
- if (!c) /* No windows found; check for available stickies */
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext)
- ;
- }
-
- if (selmon->sel && selmon->sel != c)
- unfocus(selmon->sel, 0);
- if (c)
- {
- if (c->mon != selmon)
- selmon = c->mon;
- if (c->isurgent)
- seturgent(c, 0);
- detachstack(c);
- attachstack(c);
- grabbuttons(c, 1);
- if (c == mark)
+ if (!c || !ISVISIBLE(c))
+ for (c = selmon->stack; c && (!ISVISIBLE(c) || (c->issticky && !selmon->sel->issticky)); c = c->snext);
+ if (selmon->sel && selmon->sel != c)
+ unfocus(selmon->sel, 0);
+ if (c) {
+ if (c->cantfocus)
+ return;
+ if (c->mon != selmon)
+ selmon = c->mon;
+ if (c->isurgent)
+ seturgent(c, 0);
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, 1);
+ if (c == mark)
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColMark].pixel);
+ else if(c->isfloating)
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
else
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
- setfocus(c);
- }
- else
- {
- XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
- XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
- }
- selmon->sel = c;
- drawbars();
+ setfocus(c);
+ c->opacity = MIN(1.0, MAX(0, c->opacity));
+ opacity(c, c->opacity);
+ } else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+ selmon->sel = c;
+ selmon->pertag->sel[selmon->pertag->curtag] = c;
+ drawbars();
}
/* there are some broken focus acquiring clients needing extra handling */
void
focusin(XEvent *e)
{
- XFocusChangeEvent *ev = &e->xfocus;
+ XFocusChangeEvent *ev = &e->xfocus;
- if (selmon->sel && ev->window != selmon->sel->win)
- setfocus(selmon->sel);
+ if (selmon->sel && ev->window != selmon->sel->win)
+ setfocus(selmon->sel);
+}
+
+void
+focusmaster(const Arg *arg)
+{
+ Client *master;
+
+ if (selmon->nmaster > 1)
+ return;
+ if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
+ return;
+
+ master = nexttiled(selmon->clients);
+
+ if (!master)
+ return;
+
+ int i;
+ for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
+ i++;
+
+ if (selmon->sel == master) {
+ if (selmon->tagmarked[i] && ISVISIBLE(selmon->tagmarked[i]))
+ focus(selmon->tagmarked[i]);
+ } else {
+ selmon->tagmarked[i] = selmon->sel;
+ focus(master);
+ }
}
void
focusmon(const Arg *arg)
{
- Monitor *m;
+ Monitor *m;
- if (!mons->next)
- return;
- if ((m = dirtomon(arg->i)) == selmon)
- return;
- unfocus(selmon->sel, 0);
- selmon = m;
- focus(NULL);
+ if (!mons->next)
+ return;
+ if ((m = dirtomon(arg->i)) == selmon)
+ return;
+ unfocus(selmon->sel, 0);
+ selmon = m;
+ focus(NULL);
}
void
-focusstack(const Arg *arg)
+layoutmenu(const Arg *arg) {
+ FILE *p;
+ char c[3], *s;
+ int i;
+
+ if (!(p = popen(layoutmenu_cmd, "r")))
+ return;
+ s = fgets(c, sizeof(c), p);
+ pclose(p);
+
+ if (!s || *s == '\0' || c[0] == '\0')
+ return;
+
+ i = atoi(c);
+ setlayout(&((Arg) { .v = &layouts[i] }));
+}
+
+void
+focusnthmon(const Arg *arg)
{
- int i = stackpos(arg);
- Client *c, *p;
+ Monitor *m;
+
+ if (!mons->next)
+ return;
+
+ if ((m = numtomon(arg->i)) == selmon)
+ return;
+ unfocus(selmon->sel, 0);
+ selmon = m;
+ focus(NULL);
+}
- if (i < 0 || !selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
- return;
+static void
+focusnext(const Arg *arg) {
+ Monitor *m;
+ Client *c;
+ m = selmon;
+ c = m->sel;
- for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c));
- i -= ISVISIBLE(c) ? 1 : 0, p = c, c = c->next)
- ;
- focus(c ? c : p);
- restack(selmon);
+ if (arg->i) {
+ if (c->next)
+ c = c->next;
+ else
+ c = m->clients;
+ } else {
+ Client *last = c;
+ if (last == m->clients)
+ last = NULL;
+ for (c = m->clients; c->next != last; c = c->next);
+ }
+ focus(c);
+ return;
}
-Atom getatomprop(Client *c, Atom prop)
+void
+focusstack(const Arg *arg)
{
- int di;
- unsigned long dl;
- unsigned char *p = NULL;
- Atom da, atom = None;
+ int i = stackpos(arg);
+ Client *c, *p;
- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
- &da, &di, &dl, &dl, &p) == Success &&
- p)
- {
- atom = *(Atom *)p;
- XFree(p);
- }
- return atom;
+ if (i < 0 || (selmon->sel->isfullscreen && lockfullscreen))
+ return;
+
+ for(p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c) || c->cantfocus);
+ i -= (ISVISIBLE(c) && !c->cantfocus) ? 1 : 0, p = c, c = c->next);
+ focus(c ? c : p);
+ restack(selmon);
}
-#ifndef __OpenBSD__
-int
-getdwmblockspid()
+Atom
+getatomprop(Client *c, Atom prop)
{
- char buf[16];
- FILE *fp = popen("pidof -s dwmblocks", "r");
- fgets(buf, sizeof(buf), fp);
- pid_t pid = strtoul(buf, NULL, 10);
- pclose(fp);
- dwmblockspid = pid;
- return pid != 0 ? 0 : -1;
+ int di;
+ unsigned long dl;
+ unsigned char *p = NULL;
+ Atom da, atom = None;
+
+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
+ &da, &di, &dl, &dl, &p) == Success && p) {
+ atom = *(Atom *)p;
+ XFree(p);
+ }
+ return atom;
+}
+
+pid_t
+getstatusbarpid()
+{
+ char buf[32], *str = buf, *c;
+ FILE *fp;
+
+ if (statuspid > 0) {
+ snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid);
+ if ((fp = fopen(buf, "r"))) {
+ fgets(buf, sizeof(buf), fp);
+ while ((c = strchr(str, '/')))
+ str = c + 1;
+ fclose(fp);
+ if (!strcmp(str, STATUSBAR))
+ return statuspid;
+ }
+ }
+ if (!(fp = popen("pidof -s "STATUSBAR, "r")))
+ return -1;
+ fgets(buf, sizeof(buf), fp);
+ pclose(fp);
+ return strtol(buf, NULL, 10);
}
-#endif
int
getrootptr(int *x, int *y)
{
- int di;
- unsigned int dui;
- Window dummy;
+ int di;
+ unsigned int dui;
+ Window dummy;
- return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
+ return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
}
-long getstate(Window w)
+long
+getstate(Window w)
{
- int format;
- long result = -1;
- unsigned char *p = NULL;
- unsigned long n, extra;
- Atom real;
+ int format;
+ long result = -1;
+ unsigned char *p = NULL;
+ unsigned long n, extra;
+ Atom real;
- if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False,
- wmatom[WMState], &real, &format, &n, &extra,
- (unsigned char **)&p) != Success)
- return -1;
- if (n != 0)
- result = *p;
- XFree(p);
- return result;
+ if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
+ &real, &format, &n, &extra, (unsigned char **)&p) != Success)
+ return -1;
+ if (n != 0)
+ result = *p;
+ XFree(p);
+ return result;
}
int
gettextprop(Window w, Atom atom, char *text, unsigned int size)
{
- char **list = NULL;
- int n;
- XTextProperty name;
-
- if (!text || size == 0)
- return 0;
- text[0] = '\0';
- if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
- return 0;
- if (name.encoding == XA_STRING)
- {
- strncpy(text, (char *)name.value, size - 1);
- }
- else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success &&
- n > 0 && *list)
- {
- strncpy(text, *list, size - 1);
- XFreeStringList(list);
- }
- text[size - 1] = '\0';
- XFree(name.value);
- return 1;
+ char **list = NULL;
+ int n;
+ XTextProperty name;
+
+ if (!text || size == 0)
+ return 0;
+ text[0] = '\0';
+ if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
+ return 0;
+ if (name.encoding == XA_STRING) {
+ strncpy(text, (char *)name.value, size - 1);
+ } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
+ strncpy(text, *list, size - 1);
+ XFreeStringList(list);
+ }
+ text[size - 1] = '\0';
+ XFree(name.value);
+ return 1;
}
void
grabbuttons(Client *c, int focused)
{
- updatenumlockmask();
- {
- unsigned int i, j;
- unsigned int modifiers[] = {0, LockMask, numlockmask,
- numlockmask | LockMask};
- XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
- if (!focused)
- XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
- GrabModeSync, GrabModeSync, None, None);
- for (i = 0; i < LENGTH(buttons); i++)
- if (buttons[i].click == ClkClientWin)
- for (j = 0; j < LENGTH(modifiers); j++)
- XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j],
- c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync,
- None, None);
- }
+ updatenumlockmask();
+ {
+ unsigned int i, j;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+ if (!focused)
+ XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
+ BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (buttons[i].click == ClkClientWin)
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabButton(dpy, buttons[i].button,
+ buttons[i].mask | modifiers[j],
+ c->win, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None, None);
+ }
}
void
grabkeys(void)
{
- if (keymode == ModeCommand)
- {
- XUngrabKey(dpy, AnyKey, AnyModifier, root);
- XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
- return;
- }
-
- XUngrabKeyboard(dpy, CurrentTime);
- updatenumlockmask();
- {
- unsigned int i, j, k;
- unsigned int modifiers[] = {0, LockMask, numlockmask,
- numlockmask | LockMask};
- int start, end, skip;
- KeySym *syms;
-
- XUngrabKey(dpy, AnyKey, AnyModifier, root);
- XDisplayKeycodes(dpy, &start, &end);
- syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
- if (!syms)
- return;
- for (k = start; k <= end; k++)
- for (i = 0; i < LENGTH(keys); i++)
- /* skip modifier codes, we do that ourselves */
- if (keys[i].keysym == syms[(k - start) * skip])
- for (j = 0; j < LENGTH(modifiers); j++)
- XGrabKey(dpy, k, keys[i].mod | modifiers[j], root, True,
- GrabModeAsync, GrabModeAsync);
- XFree(syms);
- }
+ updatenumlockmask();
+ {
+ /* unsigned int i, j, k; */
+ unsigned int i, c, k;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+ int start, end, skip;
+ KeySym *syms;
+
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ XDisplayKeycodes(dpy, &start, &end);
+ syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+ if (!syms)
+ return;
+
+ for (k = start; k <= end; k++)
+ for (i = 0; i < LENGTH(keychords); i++)
+ /* skip modifier codes, we do that ourselves */
+ if (keychords[i]->keys[currentkey].keysym == syms[(k - start) * skip])
+ for (c = 0; c < LENGTH(modifiers); c++)
+ XGrabKey(dpy, k,
+ keychords[i]->keys[currentkey].mod | modifiers[c],
+ root, True,
+ GrabModeAsync, GrabModeAsync);
+ if(currentkey > 0)
+ XGrabKey(dpy, XKeysymToKeycode(dpy, XK_Escape), AnyModifier, root, True, GrabModeAsync, GrabModeAsync);
+ XFree(syms);
+ }
}
+
void
incnmaster(const Arg *arg)
{
- selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
- arrange(selmon);
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
}
#ifdef XINERAMA
-static int isuniquegeom(XineramaScreenInfo *unique, size_t n,
- XineramaScreenInfo *info)
+static int
+isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
{
- while (n--)
- if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org &&
- unique[n].width == info->width && unique[n].height == info->height)
- return 0;
- return 1;
+ while (n--)
+ if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
+ && unique[n].width == info->width && unique[n].height == info->height)
+ return 0;
+ return 1;
}
#endif /* XINERAMA */
void
keypress(XEvent *e)
{
- unsigned int i;
- KeySym keysym;
- XKeyEvent *ev;
+ /* unsigned int i; */
+ XEvent event = *e;
+ unsigned int ran = 0;
+ KeySym keysym;
+ XKeyEvent *ev;
- if (keymode == ModeCommand)
- {
- keypresscmd(e);
- return;
- }
+ Keychord *arr1[sizeof(keychords) / sizeof(Keychord*)];
+ Keychord *arr2[sizeof(keychords) / sizeof(Keychord*)];
+ memcpy(arr1, keychords, sizeof(keychords));
+ Keychord **rpointer = arr1;
+ Keychord **wpointer = arr2;
- ev = &e->xkey;
- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
- for (i = 0; i < LENGTH(keys); i++)
- if (keysym == keys[i].keysym &&
- CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) && keys[i].func)
- keys[i].func(&(keys[i].arg));
-}
+ size_t r = sizeof(keychords)/ sizeof(Keychord*);
-void
-keypresscmd(XEvent *e)
-{
- unsigned int i, j;
- int matches = 0;
- KeySym keysym;
- XKeyEvent *ev;
-
- ev = &e->xkey;
+ while(1){
+ ev = &event.xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
- if (XK_Shift_L <= keysym && keysym <= XK_Hyper_R)
- {
- return;
- }
-
- for (i = 0; i < LENGTH(cmdkeys); i++)
- {
- if (keysym == cmdkeys[i].keysym && CLEANMASK(cmdkeys[i].mod) == CLEANMASK(ev->state) && cmdkeys[i].func)
- {
- cmdkeys[i].func(&(cmdkeys[i].arg));
- return;
- }
- }
-
- for (j = 0; j < LENGTH(cmdkeysym); j++)
- {
- if (cmdkeysym[j] == 0)
- {
- cmdkeysym[j] = keysym;
- cmdmod[j] = ev->state;
- break;
- }
- }
-
- for (i = 0; i < LENGTH(commands); i++)
- {
- matches = 0;
- for (j = 0; j < LENGTH(cmdkeysym); j++)
- {
- if (cmdkeysym[j] == commands[i].keysym[j] && CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j]))
- matches++;
- }
- if (matches == LENGTH(cmdkeysym))
- {
- if (commands[i].func)
- commands[i].func(&(commands[i].arg));
- clearcmd(NULL);
- return;
+ size_t w = 0;
+ for (int i = 0; i < r; i++){
+ if(keysym == (*(rpointer + i))->keys[currentkey].keysym
+ && CLEANMASK((*(rpointer + i))->keys[currentkey].mod) == CLEANMASK(ev->state)
+ && (*(rpointer + i))->func){
+ if((*(rpointer + i))->n == currentkey +1){
+ (*(rpointer + i))->func(&((*(rpointer + i))->arg));
+ ran = 1;
+ } else {
+ *(wpointer + w) = *(rpointer + i);
+ w++;
}
+ }
}
+ currentkey++;
+ if(w == 0 || ran == 1)
+ break;
+ grabkeys();
+ while (running && !XNextEvent(dpy, &event) && !ran)
+ if(event.type == KeyPress)
+ break;
+ r = w;
+ Keychord **holder = rpointer;
+ rpointer = wpointer;
+ wpointer = holder;
+ }
+ currentkey = 0;
+ grabkeys();
+}
+
+void
+killthis(Client *c) {
+ if (!sendevent(c, wmatom[WMDelete])) {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+ XKillClient(dpy, c->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
}
void
killclient(const Arg *arg)
{
- Client *c;
-
- if (!selmon->sel || !selmon->sel->allowkill)
- return;
+ Client *c;
- if (!arg->ui || arg->ui == 0)
- {
- killthis(selmon->sel);
- return;
- }
-
- for (c = selmon->clients; c; c = c->next)
- {
- if (!ISVISIBLE(c) || (arg->ui == 1 && c == selmon->sel))
- continue;
- killthis(c);
- }
-}
-
-void
-killthis(Client *c)
-{
- if (!sendevent(c, wmatom[WMDelete]))
- {
- XGrabServer(dpy);
- XSetErrorHandler(xerrordummy);
- XSetCloseDownMode(dpy, DestroyAll);
- XKillClient(dpy, c->win);
- XSync(dpy, False);
- XSetErrorHandler(xerror);
- XUngrabServer(dpy);
- }
-}
-
-void
-layoutmenu(const Arg *arg) {
- FILE *p;
- char c[3], *s;
- int i;
-
- if (!(p = popen(layoutmenu_cmd, "r")))
- return;
- s = fgets(c, sizeof(c), p);
- pclose(p);
-
- if (!s || *s == '\0' || c[0] == '\0')
- return;
-
- i = atoi(c);
- setlayout(&((Arg) { .v = &layouts[i] }));
-}
-
-void
-layoutscroll(const Arg *arg)
-{
- if (!arg || !arg->i)
+ if (!selmon->sel || !selmon->sel->allowkill)
return;
- int switchto = selmon->ltcur + arg->i;
- int l = LENGTH(layouts);
- if (switchto == l)
- switchto = 0;
- else if(switchto < 0)
- switchto = l - 1;
+ if (!arg->ui || arg->ui == 0) {
+ killthis(selmon->sel);
+ return;
+ }
- selmon->ltcur = switchto;
- Arg arg2 = {.v= &layouts[switchto] };
- setlayout(&arg2);
+ for (c = selmon->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || (arg->ui == 1 && c == selmon->sel))
+ continue;
+ killthis(c);
+ }
}
+
void
manage(Window w, XWindowAttributes *wa)
{
- Client *c, *t = NULL, *term = NULL;
- Window trans = None;
- XWindowChanges wc;
-
- c = ecalloc(1, sizeof(Client));
- c->win = w;
- c->pid = winpid(w);
- /* geometry */
- c->x = c->oldx = wa->x;
- c->y = c->oldy = wa->y;
- c->w = c->oldw = wa->width;
- c->h = c->oldh = wa->height;
- c->oldbw = wa->border_width;
- c->cfact = 1.0;
-
- updatetitle(c);
- if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans)))
- {
- c->mon = t->mon;
- c->tags = t->tags;
- }
- else
- {
- c->mon = selmon;
- applyrules(c);
- term = termforwin(c);
- }
-
- if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
- c->x = c->mon->wx + c->mon->ww - WIDTH(c);
- if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
- c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
- c->x = MAX(c->x, c->mon->wx);
- c->y = MAX(c->y, c->mon->wy);
- c->bw = borderpx;
-
- wc.border_width = c->bw;
- XConfigureWindow(dpy, w, CWBorderWidth, &wc);
- if (c == mark)
+ Client *c, *t = NULL, *term = NULL;
+ Window trans = None;
+ XWindowChanges wc;
+
+ c = ecalloc(1, sizeof(Client));
+ c->win = w;
+ c->pid = winpid(w);
+ /* geometry */
+ c->x = c->oldx = wa->x;
+ c->y = c->oldy = wa->y;
+ c->w = c->oldw = wa->width;
+ c->h = c->oldh = wa->height;
+ c->oldbw = wa->border_width;
+ c->resizehints = resizehints;
+ c->cfact = 1.0;
+
+ updatetitle(c);
+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+ c->mon = t->mon;
+ c->tags = t->tags;
+ } else {
+ c->mon = selmon;
+ applyrules(c);
+ term = termforwin(c);
+ }
+ opacity(c, c->opacity);
+
+ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+ c->x = c->mon->wx + c->mon->ww - WIDTH(c);
+ if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
+ c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
+ c->x = MAX(c->x, c->mon->wx);
+ c->y = MAX(c->y, c->mon->wy);
+ c->bw = c->mon->borderpx;
+ if (c->isfloating)
+ c->bw = fborderpx;
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ if (c == mark)
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColMark].pixel);
+ else if(c->isfloating)
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
else
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
- configure(c); /* propagates border_width, if size doesn't change */
- updatewindowtype(c);
- updatesizehints(c);
- updatewmhints(c);
- {
- int format;
- unsigned long *data, n, extra;
- Monitor *m;
- Atom atom;
- if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False,
- XA_CARDINAL, &atom, &format, &n, &extra,
- (unsigned char **)&data) == Success &&
- n == 2)
- {
- c->tags = *data;
- for (m = mons; m; m = m->next)
- {
- if (m->num == *(data + 1))
- {
- c->mon = m;
- break;
- }
- }
- }
- if (n > 0)
- XFree(data);
- }
- c->sfx = c->x;
- c->sfy = c->y;
- c->sfw = c->w;
- c->sfh = c->h;
- setclienttagprop(c);
-
- c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
- c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
- XSelectInput(dpy, w,
- EnterWindowMask | FocusChangeMask | PropertyChangeMask |
- StructureNotifyMask);
- grabbuttons(c, 0);
- c->wasfloating = 0;
- c->expandmask = 0;
- if (!c->isfloating)
- c->isfloating = c->oldstate = trans != None || c->isfixed;
- if (c->isfloating)
- XRaiseWindow(dpy, c->win);
- attach(c);
- attachstack(c);
- XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32,
- PropModeAppend, (unsigned char *)&(c->win), 1);
- XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w,
- c->h); /* some windows require this */
- setclientstate(c, NormalState);
- if (selmon->sel && selmon->sel->isfullscreen && !c->isfloating)
- setfullscreen(selmon->sel, 0);
- if (c->mon == selmon)
- unfocus(selmon->sel, 0);
- c->mon->sel = c;
- XMapWindow(dpy, c->win);
- if (term)
- swallow(term, c);
- arrange(c->mon);
- focus(NULL);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatewindowtype(c);
+ updatesizehints(c);
+ updatewmhints(c);
+ {
+ int format;
+ unsigned long *data, n, extra;
+ Monitor *m;
+ Atom atom;
+ if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL,
+ &atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2) {
+ c->tags = *data;
+ for (m = mons; m; m = m->next) {
+ if (m->num == *(data+1)) {
+ c->mon = m;
+ break;
+ }
+ }
+ }
+ if (n > 0)
+ XFree(data);
+ }
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ setclienttagprop(c);
+ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
+ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
+ XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ grabbuttons(c, 0);
+ c->wasfloating = 0;
+ c->expandmask = 0;
+ if (!c->isfloating)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
+ if(c->isfloating)
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
+ attach(c);
+ attachstack(c);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+ XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
+ setclientstate(c, NormalState);
+ if(selmon->sel && selmon->sel->isfullscreen && !c->isfloating)
+ setfullscreen(selmon->sel, 0);
+ if (c->mon == selmon)
+ unfocus(selmon->sel, 0);
+ c->mon->sel = c;
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ if (term)
+ swallow(term, c);
+ focus(NULL);
}
void
mappingnotify(XEvent *e)
{
- XMappingEvent *ev = &e->xmapping;
+ XMappingEvent *ev = &e->xmapping;
- XRefreshKeyboardMapping(ev);
- if (ev->request == MappingKeyboard)
- grabkeys();
+ XRefreshKeyboardMapping(ev);
+ if (ev->request == MappingKeyboard)
+ grabkeys();
}
void
maprequest(XEvent *e)
{
- static XWindowAttributes wa;
- XMapRequestEvent *ev = &e->xmaprequest;
+ static XWindowAttributes wa;
+ XMapRequestEvent *ev = &e->xmaprequest;
- if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
- return;
- if (!wintoclient(ev->window))
- manage(ev->window, &wa);
+ if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
+ return;
+ if (!wintoclient(ev->window))
+ manage(ev->window, &wa);
}
void
monocle(Monitor *m)
{
- unsigned int n;
- int oh, ov, ih, iv;
- Client *c;
+ unsigned int n = 0;
+ Client *c;
- getgaps(m, &oh, &ov, &ih, &iv, &n);
-
- if (n > 0) /* override layout symbol */
- snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
- for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
- resize(c, m->wx + ov, m->wy + oh, m->ww - 2 * c->bw - 2 * ov,
- m->wh - 2 * c->bw - 2 * oh, 0);
+ for (c = m->clients; c; c = c->next)
+ if (ISVISIBLE(c))
+ n++;
+ if (n > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
}
void
motionnotify(XEvent *e)
{
- static Monitor *mon = NULL;
- Monitor *m;
- XMotionEvent *ev = &e->xmotion;
+ static Monitor *mon = NULL;
+ Monitor *m;
+ XMotionEvent *ev = &e->xmotion;
- if (ev->window != root)
- return;
- if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon)
- {
- unfocus(selmon->sel, 1);
- selmon = m;
- focus(NULL);
- }
- mon = m;
+ if (ev->window != root)
+ return;
+ if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ focus(NULL);
+ }
+ mon = m;
}
void
@@ -1833,594 +1887,730 @@ gesture(const Arg *arg) {
void
movemouse(const Arg *arg)
{
- int x, y, ocx, ocy, nx, ny;
- Client *c;
- Monitor *m;
- XEvent ev;
-
- if (!(c = selmon->sel))
- return;
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
- return;
- restack(selmon);
- ocx = c->x;
- ocy = c->y;
- if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
- return;
- if (!getrootptr(&x, &y))
- return;
- do
- {
- XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
- switch (ev.type)
- {
- case ConfigureRequest:
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
- break;
- case MotionNotify:
- nx = ocx + (ev.xmotion.x - x);
- ny = ocy + (ev.xmotion.y - y);
- if ((m = recttomon(nx, ny, c->w, c->h)))
- {
- if (m != selmon)
- sendmon(c, m);
- if (abs(selmon->wx - nx) < snap)
- nx = selmon->wx;
- else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
- nx = selmon->wx + selmon->ww - WIDTH(c);
- if (abs(selmon->wy - ny) < snap)
- ny = selmon->wy;
- else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
- ny = selmon->wy + selmon->wh - HEIGHT(c);
- if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, nx, ny, c->w, c->h, 1);
- else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
- if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
- sendmon(c, m);
- selmon = m;
- focus(NULL);
- }
-
- Client *cc = c->mon->clients;
- while (1) {
- if (cc == 0) break;
- if(
- cc != c && !cc->isfloating && ISVISIBLE(cc) &&
- ev.xmotion.x_root > cc->x &&
- ev.xmotion.x_root < cc->x + cc->w &&
- ev.xmotion.y_root > cc->y &&
- ev.xmotion.y_root < cc->y + cc->h ) {
- break;
- }
- cc = cc->next;
- }
-
- if (cc) {
- Client *cl1, *cl2, ocl1;
-
- if (!selmon->lt[selmon->sellt]->arrange) return;
-
- cl1 = c;
- cl2 = cc;
- ocl1 = *cl1;
- strcpy(cl1->name, cl2->name);
- cl1->win = cl2->win;
- cl1->x = cl2->x;
- cl1->y = cl2->y;
- cl1->w = cl2->w;
- cl1->h = cl2->h;
-
- cl2->win = ocl1.win;
- strcpy(cl2->name, ocl1.name);
- cl2->x = ocl1.x;
- cl2->y = ocl1.y;
- cl2->w = ocl1.w;
- cl2->h = ocl1.h;
-
- selmon->sel = cl2;
-
- c = cc;
- focus(c);
-
- arrange(cl1->mon);
- }
- }
+ int x, y, ocx, ocy, nx, ny;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ return;
+ if (!getrootptr(&x, &y))
+ return;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ nx = ocx + (ev.xmotion.x - x);
+ ny = ocy + (ev.xmotion.y - y);
+ if ((m = recttomon(nx, ny, c->w, c->h))) {
+ if (m != selmon)
+ sendmon(c, m);
+ if (abs(selmon->wx - nx) < snap)
+ nx = selmon->wx;
+ else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
+ nx = selmon->wx + selmon->ww - WIDTH(c);
+ if (abs(selmon->wy - ny) < snap)
+ ny = selmon->wy;
+ else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
+ ny = selmon->wy + selmon->wh - HEIGHT(c);
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+ resize(c, nx, ny, c->w, c->h, 1);
+ else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
+ if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+
+ Client *cc = c->mon->clients;
+ while (1) {
+ if (cc == 0) break;
+ if(
+ cc != c && !cc->isfloating && ISVISIBLE(cc) &&
+ ev.xmotion.x_root > cc->x &&
+ ev.xmotion.x_root < cc->x + cc->w &&
+ ev.xmotion.y_root > cc->y &&
+ ev.xmotion.y_root < cc->y + cc->h ) {
+ break;
}
- break;
+
+ cc = cc->next;
+ }
+
+ if (cc) {
+ Client *cl1, *cl2, ocl1;
+
+ if (!selmon->lt[selmon->sellt]->arrange) return;
+
+ cl1 = c;
+ cl2 = cc;
+ ocl1 = *cl1;
+ strcpy(cl1->name, cl2->name);
+ cl1->win = cl2->win;
+ cl1->x = cl2->x;
+ cl1->y = cl2->y;
+ cl1->w = cl2->w;
+ cl1->h = cl2->h;
+
+ cl2->win = ocl1.win;
+ strcpy(cl2->name, ocl1.name);
+ cl2->x = ocl1.x;
+ cl2->y = ocl1.y;
+ cl2->w = ocl1.w;
+ cl2->h = ocl1.h;
+
+ selmon->sel = cl2;
+
+ c = cc;
+ focus(c);
+
+ arrange(cl1->mon);
+ }
}
- } while (ev.type != ButtonRelease);
- XUngrabPointer(dpy, CurrentTime);
- if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon)
- {
- sendmon(c, m);
- selmon = m;
- focus(NULL);
- }
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+}
+
+void
+movecenter(const Arg *arg)
+{
+ if (selmon->sel) {
+ selmon->sel->x = selmon->sel->mon->mx + (selmon->sel->mon->mw - WIDTH(selmon->sel)) / 2;
+ selmon->sel->y = selmon->sel->mon->my + (selmon->sel->mon->mh - HEIGHT(selmon->sel)) / 2;
+ arrange(selmon);
+ }
}
Client *
nexttiled(Client *c)
{
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next)
- ;
- return c;
+ for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
+ return c;
}
void
-pop(Client *c)
+opacity(Client *c, double opacity)
{
- detach(c);
- attach(c);
- focus(c);
- arrange(c->mon);
+ if(opacity > 0 && opacity < 1) {
+ unsigned long real_opacity[] = { opacity * 0xffffffff };
+ XChangeProperty(dpy, c->win, netatom[NetWMWindowsOpacity], XA_CARDINAL,
+ 32, PropModeReplace, (unsigned char *)real_opacity,
+ 1);
+ } else
+ XDeleteProperty(dpy, c->win, netatom[NetWMWindowsOpacity]);
}
void
-pushstack(const Arg *arg)
+pop(Client *c)
{
- int i = stackpos(arg);
- Client *sel = selmon->sel, *c, *p;
+ int i;
+ for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
+ i++;
- if (i < 0 || !sel)
- return;
- else if (i == 0)
- {
- detach(sel);
- attach(sel);
- }
- else
- {
- for (p = NULL, c = selmon->clients; c; p = c, c = c->next)
- if (!(i -= (ISVISIBLE(c) && c != sel)))
- break;
- c = c ? c : p;
- detach(sel);
- sel->next = c->next;
- c->next = sel;
- }
- arrange(selmon);
+ c->mon->tagmarked[i] = nexttiled(c->mon->clients);
+ detach(c);
+ attach(c);
+ focus(c);
+ arrange(c->mon);
}
void
propertynotify(XEvent *e)
{
- Client *c;
- Window trans;
- XPropertyEvent *ev = &e->xproperty;
+ Client *c;
+ Window trans;
+ XPropertyEvent *ev = &e->xproperty;
+
+ if ((ev->window == root) && (ev->atom == XA_WM_NAME))
+ updatestatus();
+ else if (ev->state == PropertyDelete)
+ return; /* ignore */
+ else if ((c = wintoclient(ev->window))) {
+ switch(ev->atom) {
+ default: break;
+ case XA_WM_TRANSIENT_FOR:
+ if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
+ (c->isfloating = (wintoclient(trans)) != NULL))
+ arrange(c->mon);
+ break;
+ case XA_WM_NORMAL_HINTS:
+ c->hintsvalid = 0;
+ break;
+ case XA_WM_HINTS:
+ updatewmhints(c);
+ drawbars();
+ break;
+ }
+ if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
+ updatetitle(c);
+ if (c == c->mon->sel && selmon->showtitle)
+ drawbar(c->mon);
+ }
+ if (ev->atom == netatom[NetWMWindowType])
+ updatewindowtype(c);
+ }
+}
- if ((ev->window == root) && (ev->atom == XA_WM_NAME))
- {
- updatestatus();
- }
- else if (ev->state == PropertyDelete)
- {
- return; /* ignore */
- }
- else if ((c = wintoclient(ev->window)))
- {
- switch (ev->atom)
- {
- default:
- break;
- case XA_WM_TRANSIENT_FOR:
- if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
- (c->isfloating = (wintoclient(trans)) != NULL))
- arrange(c->mon);
- break;
- case XA_WM_NORMAL_HINTS:
- updatesizehints(c);
- break;
- case XA_WM_HINTS:
- updatewmhints(c);
- drawbars();
- break;
- }
- if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName])
- {
- updatetitle(c);
- if (c == c->mon->sel)
- drawbar(c->mon);
- }
- if (ev->atom == netatom[NetWMWindowType])
- updatewindowtype(c);
- }
+void
+pushstack(const Arg *arg) {
+ int i = stackpos(arg);
+ Client *sel = selmon->sel, *c, *p;
+
+ if(i < 0)
+ return;
+ else if(i == 0) {
+ detach(sel);
+ attach(sel);
+ }
+ else {
+ for(p = NULL, c = selmon->clients; c; p = c, c = c->next)
+ if(!(i -= (ISVISIBLE(c) && c != sel)))
+ break;
+ c = c ? c : p;
+ detach(sel);
+ sel->next = c->next;
+ c->next = sel;
+ }
+ arrange(selmon);
}
void
quit(const Arg *arg)
{
- if (arg->i)
- restart = 1;
- running = 0;
+ if(arg->i) restart = 1;
+ running = 0;
}
-Monitor *recttomon(int x, int y, int w, int h)
+Monitor *
+recttomon(int x, int y, int w, int h)
{
- Monitor *m, *r = selmon;
- int a, area = 0;
+ Monitor *m, *r = selmon;
+ int a, area = 0;
- for (m = mons; m; m = m->next)
- if ((a = INTERSECT(x, y, w, h, m)) > area)
- {
- area = a;
- r = m;
- }
- return r;
+ for (m = mons; m; m = m->next)
+ if ((a = INTERSECT(x, y, w, h, m)) > area) {
+ area = a;
+ r = m;
+ }
+ return r;
+}
+
+void
+resetlayout(const Arg *arg)
+{
+ Arg default_layout = {.v = &layouts[0]};
+ Arg default_mfact = {.f = mfact + 1};
+
+ setlayout(&default_layout);
+ setmfact(&default_mfact);
+}
+
+void
+resetnmaster(const Arg *arg)
+{
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = 1;
+ arrange(selmon);
}
void
resize(Client *c, int x, int y, int w, int h, int interact)
{
- if (applysizehints(c, &x, &y, &w, &h, interact))
- resizeclient(c, x, y, w, h);
+ if (applysizehints(c, &x, &y, &w, &h, interact))
+ resizeclient(c, x, y, w, h);
}
void
resizeclient(Client *c, int x, int y, int w, int h)
{
- XWindowChanges wc;
+ XWindowChanges wc;
+
+ c->oldx = c->x; c->x = wc.x = x;
+ c->oldy = c->y; c->y = wc.y = y;
+ c->oldw = c->w; c->w = wc.width = w;
+ c->oldh = c->h; c->h = wc.height = h;
+ c->expandmask = 0;
+ wc.border_width = c->bw;
- c->oldx = c->x;
- c->x = wc.x = x;
- c->oldy = c->y;
- c->y = wc.y = y;
- c->oldw = c->w;
- c->w = wc.width = w;
- c->oldh = c->h;
- c->h = wc.height = h;
- c->expandmask = 0;
- wc.border_width = c->bw;
- XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth,
- &wc);
- configure(c);
- XSync(dpy, False);
+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+ XSync(dpy, False);
}
void
resizemouse(const Arg *arg)
{
- int x, y, ocw, och, nw, nh;
- Client *c;
- Monitor *m;
- XEvent ev;
-
- if (!(c = selmon->sel))
- return;
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
- return;
- restack(selmon);
- ocw = c->w;
- och = c->h;
- if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
- return;
- if(!getrootptr(&x, &y))
- return;
- do
- {
- XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
- switch (ev.type)
- {
- case ConfigureRequest:
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
- break;
- case MotionNotify:
- nw = MAX(ocw + (ev.xmotion.x - x), 1);
- nh = MAX(och + (ev.xmotion.y - y), 1);
- if ((m = recttomon(c->x, c->y, nw, nh)))
- {
- if (m != selmon)
- sendmon(c, m);
- if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
- togglefloating(NULL);
- }
- if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, c->x, c->y, nw, nh, 1);
- break;
- }
- } while (ev.type != ButtonRelease);
- XUngrabPointer(dpy, CurrentTime);
- while (XCheckMaskEvent(dpy, EnterWindowMask, &ev))
- ;
- if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon)
- {
- sendmon(c, m);
- selmon = m;
- focus(NULL);
- }
+ int x, y, ocw, och, nw, nh;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocw = c->w;
+ och = c->h;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ return;
+ if(!getrootptr(&x, &y))
+ return;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ nw = MAX(ocw + (ev.xmotion.x - x), 1);
+ nh = MAX(och + (ev.xmotion.y - y), 1);
+ if ((m = recttomon(c->x, c->y, nw, nh))) {
+ if (m != selmon)
+ sendmon(c, m);
+ if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+ && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
+ }
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+ resize(c, c->x, c->y, nw, nh, 1);
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
}
void
restack(Monitor *m)
{
- Client *c;
- XEvent ev;
- XWindowChanges wc;
-
- drawbar(m);
- if (!m->sel)
- return;
- if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
- XRaiseWindow(dpy, m->sel->win);
- if (m->lt[m->sellt]->arrange)
- {
- wc.stack_mode = Below;
- wc.sibling = m->barwin;
- for (c = m->stack; c; c = c->snext)
- if (!c->isfloating && ISVISIBLE(c))
- {
- XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
- wc.sibling = c->win;
- }
- }
- XSync(dpy, False);
- while (XCheckMaskEvent(dpy, EnterWindowMask, &ev))
- ;
+ Client *c;
+ XEvent ev;
+ XWindowChanges wc;
+
+ drawbar(m);
+ if (!m->sel)
+ return;
+ if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
+ XRaiseWindow(dpy, m->sel->win);
+
+ /* raise the aot window */
+ for(Monitor *m_search = mons; m_search; m_search = m_search->next){
+ for(c = m_search->clients; c; c = c->next){
+ if(c->isalwaysontop){
+ XRaiseWindow(dpy, c->win);
+ break;
+ }
+ }
+ }
+
+ if (m->lt[m->sellt]->arrange) {
+ wc.stack_mode = Below;
+ wc.sibling = m->barwin;
+ for (c = m->stack; c; c = c->snext)
+ if (!c->isfloating && ISVISIBLE(c)) {
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ wc.sibling = c->win;
+ }
+ }
+ XSync(dpy, False);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
run(void)
{
- XEvent ev;
- /* main event loop */
- XSync(dpy, False);
- while (running && !XNextEvent(dpy, &ev))
- if (handler[ev.type])
- handler[ev.type](&ev); /* call handler */
+ XEvent ev;
+ /* main event loop */
+ XSync(dpy, False);
+ while (running && !XNextEvent(dpy, &ev))
+ if (handler[ev.type])
+ handler[ev.type](&ev); /* call handler */
}
void
runAutostart(void)
{
- system("killall -q dwmblocks; dwmblocks &");
+ system("killall -q -9 dwmblocks; dwmblocks &");
}
void
scan(void)
{
- unsigned int i, num;
- Window d1, d2, *wins = NULL;
- XWindowAttributes wa;
-
- if (XQueryTree(dpy, root, &d1, &d2, &wins, &num))
- {
- for (i = 0; i < num; i++)
- {
- if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect ||
- XGetTransientForHint(dpy, wins[i], &d1))
- continue;
- if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
- manage(wins[i], &wa);
- }
- for (i = 0; i < num; i++)
- { /* now the transients */
- if (!XGetWindowAttributes(dpy, wins[i], &wa))
- continue;
- if (XGetTransientForHint(dpy, wins[i], &d1) &&
- (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
- manage(wins[i], &wa);
- }
- if (wins)
- XFree(wins);
+ unsigned int i, num;
+ Window d1, d2, *wins = NULL;
+ XWindowAttributes wa;
+
+ if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+ for (i = 0; i < num; i++) {
+ if (!XGetWindowAttributes(dpy, wins[i], &wa)
+ || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
+ continue;
+ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+ manage(wins[i], &wa);
+ }
+ for (i = 0; i < num; i++) { /* now the transients */
+ if (!XGetWindowAttributes(dpy, wins[i], &wa))
+ continue;
+ if (XGetTransientForHint(dpy, wins[i], &d1)
+ && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
+ manage(wins[i], &wa);
+ }
+ if (wins)
+ XFree(wins);
+ }
+}
+
+static void
+scratchpad_hide(const Arg *arg)
+{
+ if(scratchpad_hide_flag < 4) {
+ if(arg->i == 1) {
+ if(selmon->sel) {
+ selmon->sel->tags = SCRATCHPAD_MASK_1;
+ selmon->sel->isfloating = 1;
+ focus(NULL);
+ arrange(selmon);
+ scratchpad_hide_flag++;
+ }
+ } else if(arg->i == 2) {
+ if(selmon->sel) {
+ selmon->sel->tags = SCRATCHPAD_MASK_2;
+ selmon->sel->isfloating = 1;
+ focus(NULL);
+ arrange(selmon);
+ scratchpad_hide_flag++;
+ }
+ } else if(arg->i == 3) {
+ if(selmon->sel) {
+ selmon->sel->tags = SCRATCHPAD_MASK_3;
+ selmon->sel->isfloating = 1;
+ focus(NULL);
+ arrange(selmon);
+ scratchpad_hide_flag++;
+ }
}
+ }
}
-void
-sendmon(Client *c, Monitor *m)
+static void
+scratchpad_remove()
{
- Monitor *oldm = selmon;
- if (c->mon == m)
- return;
- unfocus(c, 1);
- detach(c);
- detachstack(c);
- c->mon = m;
- c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
- attach(c);
- attachstack(c);
- setclienttagprop(c);
- if (oldm != m)
- arrange(oldm);
- arrange(m);
- focus(c);
- restack(m);
+ if(selmon->sel && (scratchpad_last_showed_1 != NULL || scratchpad_last_showed_2 != NULL ||scratchpad_last_showed_3 != NULL) && (selmon->sel == scratchpad_last_showed_1 || selmon->sel == scratchpad_last_showed_2 || selmon->sel == scratchpad_last_showed_3)) {
+ if(scratchpad_last_showed_1 == selmon->sel) {
+ scratchpad_last_showed_1 = NULL;
+ scratchpad_hide_flag--;
+ } else if (scratchpad_last_showed_2 == selmon->sel) {
+ scratchpad_last_showed_2 = NULL;
+ scratchpad_hide_flag--;
+ } else if (scratchpad_last_showed_3 == selmon->sel) {
+ scratchpad_last_showed_3 = NULL;
+ scratchpad_hide_flag--;
+ }
+ }
}
-void
-setclientstate(Client *c, long state)
+static void
+scratchpad_show(const Arg *arg)
+{
+ if(arg->i == 1) {
+ if(scratchpad_last_showed_1 == NULL) {
+ scratchpad_show_first(arg->i);
+ } else {
+ if(scratchpad_last_showed_1->tags != SCRATCHPAD_MASK_1) {
+ scratchpad_last_showed_1->tags = SCRATCHPAD_MASK_1;
+ focus(NULL);
+ arrange(selmon);
+ } else {
+ scratchpad_show_first(arg->i);
+ }
+ }
+ } else if(arg->i == 2) {
+ if(scratchpad_last_showed_2 == NULL) {
+ scratchpad_show_first(arg->i);
+ } else {
+ if(scratchpad_last_showed_2->tags != SCRATCHPAD_MASK_2) {
+ scratchpad_last_showed_2->tags = SCRATCHPAD_MASK_2;
+ focus(NULL);
+ arrange(selmon);
+ } else {
+ scratchpad_show_first(arg->i);
+ }
+ }
+ } else if(arg->i == 3) {
+ if(scratchpad_last_showed_3 == NULL) {
+ scratchpad_show_first(arg->i);
+ } else {
+ if(scratchpad_last_showed_3->tags != SCRATCHPAD_MASK_3) {
+ scratchpad_last_showed_3->tags = SCRATCHPAD_MASK_3;
+ focus(NULL);
+ arrange(selmon);
+ } else {
+ scratchpad_show_first(arg->i);
+ }
+ }
+ }
+}
+
+static void
+scratchpad_show_client(Client *c)
{
- long data[] = {state, None};
+ c->tags = selmon->tagset[selmon->seltags];
+ focus(c);
+ arrange(selmon);
+}
- XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
- PropModeReplace, (unsigned char *)data, 2);
+static void
+scratchpad_show_first(int scratchNum)
+{
+ for(Client *c = selmon->clients; c !=NULL; c = c->next) {
+ if(c->tags == SCRATCHPAD_MASK_1 && scratchNum == 1) {
+ scratchpad_last_showed_1 = c;
+ scratchpad_show_client(c);
+ } else if(c->tags == SCRATCHPAD_MASK_2 && scratchNum == 2) {
+ scratchpad_last_showed_2 = c;
+ scratchpad_show_client(c);
+ } else if(c->tags == SCRATCHPAD_MASK_3 && scratchNum == 3) {
+ scratchpad_last_showed_3 = c;
+ scratchpad_show_client(c);
+ }
+ }
}
void
-setinsertmode()
+sendmon(Client *c, Monitor *m)
{
- keymode = ModeInsert;
- clearcmd(NULL);
- grabkeys();
+ Monitor *oldm = selmon;
+ if (c->mon == m)
+ return;
+ unfocus(c, 1);
+ detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
+ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
+ attach(c);
+ attachstack(c);
+ setclienttagprop(c);
+ if (oldm != m)
+ arrange(oldm);
+ arrange(m);
+ focus(c);
+ restack(m);
+}
+
+void
+setborderpx(const Arg *arg)
+{
+ Client *c;
+ int prev_borderpx = selmon->borderpx;
+
+ if (arg->i == 0)
+ selmon->borderpx = borderpx;
+ else if (selmon->borderpx + arg->i < 0)
+ selmon->borderpx = 0;
+ else
+ selmon->borderpx += arg->i;
+
+ for (c = selmon->clients; c; c = c->next)
+ {
+ if (c->bw + arg->i < 0)
+ c->bw = selmon->borderpx = 0;
+ else
+ c->bw = selmon->borderpx;
+ if (c->isfloating || !selmon->lt[selmon->sellt]->arrange)
+ {
+ if (arg->i != 0 && prev_borderpx + arg->i >= 0)
+ resize(c, c->x, c->y, c->w-(arg->i*2), c->h-(arg->i*2), 0);
+ else if (arg->i != 0)
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ else if (prev_borderpx > borderpx)
+ resize(c, c->x, c->y, c->w + 2*(prev_borderpx - borderpx), c->h + 2*(prev_borderpx - borderpx), 0);
+ else if (prev_borderpx < borderpx)
+ resize(c, c->x, c->y, c->w-2*(borderpx - prev_borderpx), c->h-2*(borderpx - prev_borderpx), 0);
+ }
+ }
+ arrange(selmon);
}
void
-setkeymode(const Arg *arg)
+setclientstate(Client *c, long state)
{
- if (!arg)
- return;
- keymode = arg->ui;
- clearcmd(NULL);
- updatestatus();
- grabkeys();
+ long data[] = { state, None };
+
+ XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
+ PropModeReplace, (unsigned char *)data, 2);
}
int
sendevent(Client *c, Atom proto)
{
- int n;
- Atom *protocols;
- int exists = 0;
- XEvent ev;
+ int n;
+ Atom *protocols;
+ int exists = 0;
+ XEvent ev;
- if (XGetWMProtocols(dpy, c->win, &protocols, &n))
- {
- while (!exists && n--)
- exists = protocols[n] == proto;
- XFree(protocols);
- }
- if (exists)
- {
- ev.type = ClientMessage;
- ev.xclient.window = c->win;
- ev.xclient.message_type = wmatom[WMProtocols];
- ev.xclient.format = 32;
- ev.xclient.data.l[0] = proto;
- ev.xclient.data.l[1] = CurrentTime;
- XSendEvent(dpy, c->win, False, NoEventMask, &ev);
- }
- return exists;
+ if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+ while (!exists && n--)
+ exists = protocols[n] == proto;
+ XFree(protocols);
+ }
+ if (exists) {
+ ev.type = ClientMessage;
+ ev.xclient.window = c->win;
+ ev.xclient.message_type = wmatom[WMProtocols];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = proto;
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+ }
+ return exists;
}
void
setfocus(Client *c)
{
- if (!c->neverfocus)
- {
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, 32,
- PropModeReplace, (unsigned char *)&(c->win), 1);
- }
- sendevent(c, wmatom[WMTakeFocus]);
+ if (!c->neverfocus) {
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ XChangeProperty(dpy, root, netatom[NetActiveWindow],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(c->win), 1);
+ }
+ sendevent(c, wmatom[WMTakeFocus]);
}
void
setfullscreen(Client *c, int fullscreen)
{
- if (fullscreen && !c->isfullscreen)
- {
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
- PropModeReplace, (unsigned char *)&netatom[NetWMFullscreen],
- 1);
- c->isfullscreen = 1;
- c->oldstate = c->isfloating;
- c->oldbw = c->bw;
- c->bw = 0;
- c->isfloating = 1;
- resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
- XRaiseWindow(dpy, c->win);
- }
- else if (!fullscreen && c->isfullscreen)
- {
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
- PropModeReplace, (unsigned char *)0, 0);
- c->isfullscreen = 0;
- c->isfloating = c->oldstate;
- c->bw = c->oldbw;
- c->x = c->oldx;
- c->y = c->oldy;
- c->w = c->oldw;
- c->h = c->oldh;
- resizeclient(c, c->x, c->y, c->w, c->h);
- arrange(c->mon);
- }
+ if (fullscreen && !c->isfullscreen) {
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+ c->isfullscreen = 1;
+ c->oldstate = c->isfloating;
+ c->oldbw = c->bw;
+ c->bw = 0;
+ c->isfloating = 1;
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ } else if (!fullscreen && c->isfullscreen){
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)0, 0);
+ c->isfullscreen = 0;
+ c->isfloating = c->oldstate;
+ c->bw = c->oldbw;
+ c->x = c->oldx;
+ c->y = c->oldy;
+ c->w = c->oldw;
+ c->h = c->oldh;
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ arrange(c->mon);
+ }
}
-int
-stackpos(const Arg *arg)
-{
- int n, i;
- Client *c, *l;
-
- if (!selmon->clients)
- return -1;
-
- if (arg->i == PREVSEL)
- {
- for (l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel);
- l = l->snext)
- ;
- if (!l)
- return -1;
- for (i = 0, c = selmon->clients; c != l;
- i += ISVISIBLE(c) ? 1 : 0, c = c->next)
- ;
- return i;
- }
- else if (ISINC(arg->i))
- {
- if (!selmon->sel)
- return -1;
- for (i = 0, c = selmon->clients; c != selmon->sel;
- i += ISVISIBLE(c) ? 1 : 0, c = c->next)
- ;
- for (n = i; c; n += ISVISIBLE(c) ? 1 : 0, c = c->next)
- ;
- return MOD(i + GETINC(arg->i), n);
- }
- else if (arg->i < 0)
- {
- for (i = 0, c = selmon->clients; c; i += ISVISIBLE(c) ? 1 : 0, c = c->next)
- ;
- return MAX(i + arg->i, 0);
- }
- else
- return arg->i;
+void
+layoutscroll(const Arg *arg)
+{
+ if (!arg || !arg->i)
+ return;
+ int switchto = selmon->ltcur + arg->i;
+ int l = LENGTH(layouts);
+
+ if (switchto == l)
+ switchto = 0;
+ else if(switchto < 0)
+ switchto = l - 1;
+
+ selmon->ltcur = switchto;
+ Arg arg2 = {.v= &layouts[switchto] };
+ setlayout(&arg2);
}
void
+ setsticky(Client *c, int sticky)
+ {
+
+ if(sticky && !c->issticky) {
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) &netatom[NetWMSticky], 1);
+ c->issticky = 1;
+ } else if(!sticky && c->issticky){
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *)0, 0);
+ c->issticky = 0;
+ arrange(c->mon);
+ }
+ }
+
+
+void
setlayout(const Arg *arg)
{
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
- {
- selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
- selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
- if (!selmon->lt[selmon->sellt]->arrange)
- {
- for (Client *c = selmon->clients; c; c = c->next)
- {
- if (!c->isfloating)
- {
- /*restore last known float dimensions*/
- resize(c, selmon->mx + c->sfx, selmon->my + c->sfy,
- c->sfw, c->sfh, 0);
- }
- }
- }
- }
- if (arg && arg->v)
- selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
- selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
- strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
- if (selmon->sel)
- arrange(selmon);
- else
- drawbar(selmon);
-
- setinsertmode();
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
+ if (!selmon->lt[selmon->sellt]->arrange) {
+ for (Client *c = selmon->clients ; c ; c = c->next) {
+ if(!c->isfloating) {
+ /*restore last known float dimensions*/
+ resize(c, selmon->mx + c->sfx, selmon->my + c->sfy,
+ c->sfw, c->sfh, 0);
+ }
+ }
+ }
+ }
+ if (arg && arg->v)
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
+ if (selmon->sel)
+ arrange(selmon);
+ else
+ drawbar(selmon);
}
void
-setcfact(const Arg *arg)
-{
- float f;
- Client *c;
+setcfact(const Arg *arg) {
+ float f;
+ Client *c;
- c = selmon->sel;
+ c = selmon->sel;
- if (!arg || !c || !selmon->lt[selmon->sellt]->arrange)
- return;
- f = arg->f + c->cfact;
- if (arg->f == 0.0)
- f = 1.0;
- else if (f < 0.25 || f > 4.0)
- return;
- c->cfact = f;
- arrange(selmon);
+ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ f = arg->f + c->cfact;
+ if(arg->f == 0.0)
+ f = 1.0;
+ else if(f < 0.25 || f > 4.0)
+ return;
+ c->cfact = f;
+ arrange(selmon);
}
void
@@ -2440,208 +2630,199 @@ setmark(Client *c)
}
}
-
/* arg > 1.0 will set mfact absolutely */
void
setmfact(const Arg *arg)
{
- float f;
+ float f;
- if (!arg || !selmon->lt[selmon->sellt]->arrange)
- return;
- f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
- if (f < 0.05 || f > 0.95)
- return;
+ if (!arg || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+ if (f < 0.05 || f > 0.95)
+ return;
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
- arrange(selmon);
+ arrange(selmon);
}
void
setup(void)
{
- int i;
- XSetWindowAttributes wa;
- Atom utf8string;
-
- /* clean up any zombies immediately */
- sigchld(0);
-
- signal(SIGHUP, sighup);
- signal(SIGTERM, sigterm);
-
- /* init screen */
- screen = DefaultScreen(dpy);
- sw = DisplayWidth(dpy, screen);
- sh = DisplayHeight(dpy, screen);
- root = RootWindow(dpy, screen);
- xinitvisual();
- drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
- if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
- die("no fonts could be loaded.");
- lrpad = drw->fonts->h;
- bh = drw->fonts->h + 2;
- sp = sidepad;
- vp = (topbar == 1) ? vertpad : -vertpad;
- updategeom();
- /* init atoms */
- utf8string = XInternAtom(dpy, "UTF8_STRING", False);
- wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
- wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
- wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
- wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
- netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
- netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
- netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
- netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
- netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
- netatom[NetWMFullscreen] =
- XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
- netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
- netatom[NetWMWindowTypeDialog] =
- XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
- netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
- netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
- /* init cursors */
- cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
- cursor[CurResize] = drw_cur_create(drw, XC_sizing);
- cursor[CurMove] = drw_cur_create(drw, XC_fleur);
- /* init appearance */
- scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
- for (i = 0; i < LENGTH(colors); i++)
- scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 4);
- /* init bars */
- updatebars();
- updatestatus();
- /* supporting window for NetWMCheck */
- wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
- XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
- PropModeReplace, (unsigned char *)&wmcheckwin, 1);
- XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
- PropModeReplace, (unsigned char *)"dwm", 3);
- XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
- PropModeReplace, (unsigned char *)&wmcheckwin, 1);
- /* EWMH support per view */
- XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
- PropModeReplace, (unsigned char *)netatom, NetLast);
- XDeleteProperty(dpy, root, netatom[NetClientList]);
- XDeleteProperty(dpy, root, netatom[NetClientInfo]);
- /* select events */
- wa.cursor = cursor[CurNormal]->cursor;
- wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
- ButtonPressMask | PointerMotionMask | EnterWindowMask |
- LeaveWindowMask | StructureNotifyMask | PropertyChangeMask | KeyPressMask;
- XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
- XSelectInput(dpy, root, wa.event_mask);
- grabkeys();
- focus(NULL);
+ int i;
+ XSetWindowAttributes wa;
+ Atom utf8string;
+ struct sigaction sa;
+
+ /* do not transform children into zombies when they terminate */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ /* clean up any zombies (inherited from .xinitrc etc) immediately */
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+
+ signal(SIGHUP, sighup);
+ signal(SIGTERM, sigterm);
+
+ /* init screen */
+ screen = DefaultScreen(dpy);
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ root = RootWindow(dpy, screen);
+ xinitvisual();
+ drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+ bh = drw->fonts->h + user_bh;
+ sp = sidepad;
+ vp = (topbar == 1) ? vertpad : - vertpad;
+ updategeom();
+ /* init atoms */
+ utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+ wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
+ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
+ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+ netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+ netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ netatom[NetWMSticky] = XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+ netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
+ netatom[NetWMWindowsOpacity] = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
+ /* init cursors */
+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+ cursor[CurMove] = drw_cur_create(drw, XC_fleur);
+ /* init appearance */
+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ for (i = 0; i < LENGTH(colors); i++)
+ scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 5);
+ /* init bars */
+ updatebars();
+ updatestatus();
+ /* supporting window for NetWMCheck */
+ wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
+ XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
+ PropModeReplace, (unsigned char *) "dwm", 3);
+ XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ /* EWMH support per view */
+ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) netatom, NetLast);
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ XDeleteProperty(dpy, root, netatom[NetClientInfo]);
+ /* select events */
+ wa.cursor = cursor[CurNormal]->cursor;
+ wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
+ |ButtonPressMask|PointerMotionMask|EnterWindowMask
+ |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
+ XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
+ XSelectInput(dpy, root, wa.event_mask);
+ grabkeys();
+ focus(NULL);
}
void
seturgent(Client *c, int urg)
{
- XWMHints *wmh;
+ XWMHints *wmh;
- c->isurgent = urg;
- if (!(wmh = XGetWMHints(dpy, c->win)))
- return;
- wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
- XSetWMHints(dpy, c->win, wmh);
- XFree(wmh);
+ c->isurgent = urg;
+ if (!(wmh = XGetWMHints(dpy, c->win)))
+ return;
+ wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
+ XSetWMHints(dpy, c->win, wmh);
+ XFree(wmh);
}
void
showhide(Client *c)
{
- if (!c)
- return;
- if (ISVISIBLE(c))
- {
- if ((c->tags & SPTAGMASK) && c->isfloating)
- {
- c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
- c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
- }
- /* show clients top down */
- XMoveWindow(dpy, c->win, c->x, c->y);
- if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) &&
- !c->isfullscreen)
- resize(c, c->x, c->y, c->w, c->h, 0);
- showhide(c->snext);
- }
- else
- {
- /* hide clients bottom up */
- showhide(c->snext);
- XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
- }
+ if (!c)
+ return;
+ if (ISVISIBLE(c)) {
+ if ((c->tags & SPTAGMASK) && c->isfloating) {
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
+ }
+ /* show clients top down */
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
+ resize(c, c->x, c->y, c->w, c->h, 0);
+ showhide(c->snext);
+ } else {
+ /* hide clients bottom up */
+ showhide(c->snext);
+ XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
+ }
}
void
sighup(int unused)
{
- Arg a = {.i = 1};
- quit(&a);
+ Arg a = {.i = 1};
+ quit(&a);
}
void
sigterm(int unused)
{
- Arg a = {.i = 0};
- quit(&a);
+ Arg a = {.i = 0};
+ quit(&a);
}
-#ifndef __OpenBSD__
void
-sigdwmblocks(const Arg *arg)
+sigstatusbar(const Arg *arg)
{
- union sigval sv;
- sv.sival_int = 0 | (dwmblockssig << 8) | arg->i;
- if (!dwmblockspid)
- if (getdwmblockspid() == -1)
- return;
+ union sigval sv;
- if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1)
- {
- if (errno == ESRCH)
- {
- if (!getdwmblockspid())
- sigqueue(dwmblockspid, SIGUSR1, sv);
- }
- }
-}
-#endif
+ if (!statussig)
+ return;
+ sv.sival_int = arg->i;
+ if ((statuspid = getstatusbarpid()) <= 0)
+ return;
-void
-sigchld(int unused)
-{
- if (signal(SIGCHLD, sigchld) == SIG_ERR)
- die("can't install SIGCHLD handler:");
- while (0 < waitpid(-1, NULL, WNOHANG))
- ;
+ sigqueue(statuspid, SIGRTMIN+statussig, sv);
}
-#define SPAWN_CWD_DELIM " []{}()<>\"':"
-
void
spawn(const Arg *arg)
{
- setinsertmode();
- if (fork() == 0)
- {
- if (dpy)
- close(ConnectionNumber(dpy));
- setsid();
- execvp(((char **)arg->v)[0], (char **)arg->v);
- die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
- }
+ struct sigaction sa;
+
+ if (arg->v == dmenucmd)
+ dmenumon[0] = '0' + selmon->num;
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
+ }
}
void
setclienttagprop(Client *c)
{
- long data[] = {(long)c->tags, (long)c->mon->num};
- XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
- PropModeReplace, (unsigned char *)data, 2);
+ long data[] = { (long) c->tags, (long) c->mon->num };
+ XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 2);
}
void
@@ -2683,7 +2864,13 @@ swapclient(const Arg *arg)
void
swapfocus(const Arg *arg)
{
- Client *t;
+ Client *c, *t;
+
+ for(c = selmon->clients; c && c != prevclient; c = c->next) ;
+ if(c == prevclient) {
+ focus(prevclient);
+ restack(prevclient->mon);
+ }
if (!selmon->sel || !mark || selmon->sel == mark)
return;
@@ -2712,18 +2899,47 @@ togglemark(const Arg *arg)
setmark(selmon->sel == mark ? 0 : selmon->sel);
}
+int
+stackpos(const Arg *arg) {
+ int n, i;
+ Client *c, *l;
+
+ if(!selmon->clients)
+ return -1;
+
+ if(arg->i == PREVSEL) {
+ for(l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext);
+ if(!l)
+ return -1;
+ for(i = 0, c = selmon->clients; c != l; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
+ return i;
+ }
+ else if(ISINC(arg->i)) {
+ if(!selmon->sel)
+ return -1;
+ for(i = 0, c = selmon->clients; c != selmon->sel; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
+ for(n = i; c; n += ISVISIBLE(c) ? 1 : 0, c = c->next);
+ return MOD(i + GETINC(arg->i), n);
+ }
+ else if(arg->i < 0) {
+ for(i = 0, c = selmon->clients; c; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
+ return MAX(i + arg->i, 0);
+ }
+ else
+ return arg->i;
+}
+
void
tag(const Arg *arg)
{
- Client *c;
- if (selmon->sel && arg->ui & TAGMASK)
- {
- c = selmon->sel;
- selmon->sel->tags = arg->ui & TAGMASK;
- setclienttagprop(c);
- focus(NULL);
- arrange(selmon);
- }
+ Client *c;
+ if (selmon->sel && arg->ui & TAGMASK) {
+ c = selmon->sel;
+ selmon->sel->tags = arg->ui & TAGMASK;
+ setclienttagprop(c);
+ focus(NULL);
+ arrange(selmon);
+ }
}
void
@@ -2742,699 +2958,950 @@ spawntag(const Arg *arg)
void
tagmon(const Arg *arg)
{
- if (!selmon->sel || !mons->next)
- return;
- sendmon(selmon->sel, dirtomon(arg->i));
+ if (!selmon->sel || !mons->next)
+ return;
+ sendmon(selmon->sel, dirtomon(arg->i));
+}
+
+
+void
+tagnthmon(const Arg *arg)
+{
+ if (!selmon->sel || !mons->next)
+ return;
+ sendmon(selmon->sel, numtomon(arg->i));
+}
+
+
+void
+toggleall(const Arg *arg)
+{
+ int i;
+ unsigned int tmptag;
+
+ Monitor* m;
+ for(m = mons; m; m = m->next){
+
+ if ((arg->ui & TAGMASK) == m->tagset[m->seltags])
+ return;
+ m->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK) {
+ m->tagset[m->seltags] = arg->ui & TAGMASK;
+ m->pertag->prevtag = m->pertag->curtag;
+
+ if (arg->ui == ~0)
+ m->pertag->curtag = 0;
+ else {
+ for (i = 0; !(arg->ui & 1 << i); i++) ;
+ m->pertag->curtag = i + 1;
+ }
+ } else {
+ tmptag = m->pertag->prevtag;
+ m->pertag->prevtag = m->pertag->curtag;
+ m->pertag->curtag = tmptag;
+ }
+
+ m->nmaster = m->pertag->nmasters[m->pertag->curtag];
+ m->mfact = m->pertag->mfacts[m->pertag->curtag];
+ m->sellt = m->pertag->sellts[m->pertag->curtag];
+ m->lt[m->sellt] = m->pertag->ltidxs[m->pertag->curtag][m->sellt];
+ m->lt[m->sellt^1] = m->pertag->ltidxs[m->pertag->curtag][m->sellt^1];
+
+ if (m->showbar != m->pertag->showbars[m->pertag->curtag])
+ togglebar(NULL);
+
+ focus(NULL);
+ arrange(m);
+ }
}
void
togglebar(const Arg *arg)
{
- unsigned int ctag = selmon->tagset[selmon->seltags];
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
+ updatebarpos(selmon);
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
+ arrange(selmon);
+}
- if (arg->i == 1 || ctag == TAGMASK)
- {
- selmon->showbar = !selmon->showbar;
- selmon->barmask = selmon->showbar * TAGMASK;
- }
- else
- {
- selmon->barmask ^= ctag;
- }
- updatebarpos(selmon);
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp,
- selmon->ww - 2 * sp, bh);
- arrange(selmon);
+void
+toggleallowkill(const Arg *arg)
+{
+ if (!selmon->sel) return;
+ selmon->sel->allowkill = !selmon->sel->allowkill;
+}
+
+void
+togglebartags(const Arg *arg)
+{
+ selmon->showtags = !selmon->showtags;
+ arrange(selmon);
+}
+
+void
+togglebartitle(const Arg *arg)
+{
+ selmon->showtitle = !selmon->showtitle;
+ arrange(selmon);
+}
+
+void
+togglebarlt(const Arg *arg)
+{
+ selmon->showlayout = !selmon->showlayout;
+ arrange(selmon);
+}
+
+void
+togglebarstatus(const Arg *arg)
+{
+ selmon->showstatus = !selmon->showstatus;
+ arrange(selmon);
+}
+
+void
+togglebarfloat(const Arg *arg)
+{
+ selmon->showfloating = !selmon->showfloating;
+ arrange(selmon);
}
void
toggleborder(const Arg *arg)
{
- selmon->sel->bw = (selmon->sel->bw == borderpx ? 0 : borderpx);
- arrange(selmon);
+ selmon->sel->bw = (selmon->sel->bw == borderpx ? 0 : borderpx);
+ arrange(selmon);
}
void
-toggleallowkill(const Arg *arg)
+toggletopbar(const Arg *arg)
{
- if (!selmon->sel) return;
- selmon->sel->allowkill = !selmon->sel->allowkill;
+ selmon->topbar = !selmon->topbar;
+ updatebarpos(selmon);
+
+ if (selmon->topbar)
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
+ else
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by - vp, selmon->ww - 2 * sp, bh);
+
+ arrange(selmon);
}
void
togglefloating(const Arg *arg)
{
- if (!selmon->sel)
- return;
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
- return;
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
- if (selmon->sel->isfloating)
- {
- /*restore last known float dimensions*/
- resize(selmon->sel, selmon->mx + selmon->sel->sfx, selmon->my + selmon->sel->sfy,
- selmon->sel->sfw, selmon->sel->sfh, 0);
- }
- else
- {
- if (selmon->sel->isfullscreen)
- setfullscreen(selmon->sel, 0);
- /*save last known float dimensions*/
- selmon->sel->sfx = selmon->sel->x - selmon->mx;
- selmon->sel->sfy = selmon->sel->y - selmon->my;
- selmon->sel->sfw = selmon->sel->w;
- selmon->sel->sfh = selmon->sel->h;
+ if (!selmon->sel)
+ return;
+ if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
+ selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
+ if(selmon->sel->isfloating)
+ XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColFloat].pixel);
+ else
+ XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColBorder].pixel);
+ if (selmon->sel->isfloating) {
+ selmon->sel->bw = fborderpx;
+ configure(selmon->sel);
+ int borderdiff = (fborderpx - borderpx) * 2;
+ /*restore last known float dimensions*/
+ resize(selmon->sel, selmon->mx + selmon->sel->sfx, selmon->my + selmon->sel->sfy,
+ selmon->sel->sfw - borderdiff, selmon->sel->sfh - borderdiff, 0);
+ } else {
+ selmon->sel->isalwaysontop = 0; /* disabled, turn this off too */
+ selmon->sel->bw = borderpx;
+ configure(selmon->sel);
+ if (selmon->sel->isfullscreen)
+ setfullscreen(selmon->sel, 0);
+ /*save last known float dimensions*/
+ selmon->sel->sfx = selmon->sel->x - selmon->mx;
+ selmon->sel->sfy = selmon->sel->y - selmon->my;
+ selmon->sel->sfw = selmon->sel->w;
+ selmon->sel->sfh = selmon->sel->h;
+ }
+
+ resetcanfocusfloating();
+
+ selmon->sel->x = selmon->sel->mon->mx + (selmon->sel->mon->mw - WIDTH(selmon->sel)) / 2;
+ selmon->sel->y = selmon->sel->mon->my + (selmon->sel->mon->mh - HEIGHT(selmon->sel)) / 2;
+
+ arrange(selmon);
+}
+
+void
+togglealwaysontop(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ if (selmon->sel->isfullscreen)
+ return;
+
+ if(selmon->sel->isalwaysontop){
+ selmon->sel->isalwaysontop = 0;
+ } else {
+ /* disable others */
+ for(Monitor *m = mons; m; m = m->next)
+ for(Client *c = m->clients; c; c = c->next)
+ c->isalwaysontop = 0;
+
+ /* turn on, make it float too */
+ selmon->sel->isfloating = 1;
+ selmon->sel->isalwaysontop = 1;
+ }
+ arrange(selmon);
+}
+
+
+void
+resetcanfocusfloating()
+{
+ unsigned int i, n;
+ Client *c;
+
+ for (n = 0, c = selmon->clients; c; c = c->next, n++);
+ if (n == 0)
+ return;
+
+ for (i = 0, c = selmon->clients; c; c = c->next, i++)
+ if (c->isfloating)
+ c->cantfocus = 0;
+
+ arrange(selmon);
+}
+
+void
+togglecanfocusfloating(const Arg *arg)
+{
+ unsigned int n;
+ Client *c, *cf = NULL;
+
+ if (!selmon->sel)
+ return;
+
+ for (c = selmon->clients; c; c = c->next)
+ if (c->cantfocus == 1) {
+ cf = c;
+ }
+
+ if (cf) {
+ resetcanfocusfloating();
+ focus(cf);
+ } else {
+ for (n = 0, c = selmon->clients; c; c = c->next)
+ if (c->isfloating)
+ c->cantfocus = !c->cantfocus;
+ else
+ n++;
+
+ if (n && selmon->sel->isfloating) {
+ c = nexttiled(selmon->clients);
+ focus(c);
}
- arrange(selmon);
+ }
+
+ arrange(selmon);
}
void
togglefullscr(const Arg *arg)
{
- if (selmon->sel)
- setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
+ if(selmon->sel)
+ setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
}
void
-togglesticky(const Arg *arg)
+togglescratch(const Arg *arg)
{
- if (!selmon->sel)
- return;
- selmon->sel->issticky = !selmon->sel->issticky;
- arrange(selmon);
+ Client *c;
+ unsigned int found = 0;
+ unsigned int scratchtag = SPTAG(arg->ui);
+ Arg sparg = {.v = scratchpads[arg->ui].cmd};
+
+ for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next);
+ if (found) {
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
+ focus(NULL);
+ arrange(selmon);
+ }
+ if (ISVISIBLE(c)) {
+ focus(c);
+ restack(selmon);
+ }
+ } else {
+ selmon->tagset[selmon->seltags] |= scratchtag;
+ spawn(&sparg);
+ }
}
void
-togglescratch(const Arg *arg)
+togglesticky(const Arg *arg)
{
- Client *c;
- unsigned int found = 0;
- unsigned int scratchtag = SPTAG(arg->ui);
- Arg sparg = {.v = scratchpads[arg->ui].cmd};
-
- for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next)
- ;
- if (found)
- {
- unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
- if (newtagset)
- {
- selmon->tagset[selmon->seltags] = newtagset;
- focus(NULL);
- arrange(selmon);
- }
- if (ISVISIBLE(c))
- {
- focus(c);
- restack(selmon);
- }
- }
- else
- {
- selmon->tagset[selmon->seltags] |= scratchtag;
- spawn(&sparg);
- }
+ if (!selmon->sel)
+ return;
+ setsticky(selmon->sel, !selmon->sel->issticky);
+ arrange(selmon);
}
void
toggletag(const Arg *arg)
{
- unsigned int newtags;
+ unsigned int newtags;
- if (!selmon->sel)
- return;
- newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
- if (newtags)
- {
- selmon->sel->tags = newtags;
- setclienttagprop(selmon->sel);
- focus(NULL);
- arrange(selmon);
- }
+ if (!selmon->sel)
+ return;
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ selmon->sel->tags = newtags;
+ setclienttagprop(selmon->sel);
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+ntoggleview(const Arg *arg)
+{
+ const Arg n = {.i = +1};
+ const int mon = selmon->num;
+ do {
+ focusmon(&n);
+ toggleview(arg);
+ }
+ while (selmon->num != mon);
}
void
toggleview(const Arg *arg)
{
- unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
- int i;
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+ int i;
- if (newtagset)
- {
- if (newtagset == ~0)
- {
- selmon->pertag->prevtag = selmon->pertag->curtag;
- selmon->pertag->curtag = 0;
- }
- /* test if the user did not select the same tag */
- if (!(newtagset & 1 << (selmon->pertag->curtag - 1)))
- {
- selmon->pertag->prevtag = selmon->pertag->curtag;
- for (i = 0; !(newtagset & 1 << i); i++)
- ;
- selmon->pertag->curtag = i + 1;
- }
- selmon->tagset[selmon->seltags] = newtagset;
-
- /* apply settings for this view */
- selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
- selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
- selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
- selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
- selmon->lt[selmon->sellt ^ 1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt ^ 1];
- focus(NULL);
- arrange(selmon);
- }
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
+
+ if (newtagset == ~0) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = 0;
+ }
+
+ /* test if the user did not select the same tag */
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ for (i = 0; !(newtagset & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+
+ /* apply settings for this view */
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+
+ focus(NULL);
+ arrange(selmon);
+ }
}
void
unfocus(Client *c, int setfocus)
{
- if (!c)
- return;
- grabbuttons(c, 0);
- if (c == mark)
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColMark].pixel);
- else
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
- if (setfocus)
- {
- XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
- XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
- }
+ if (!c)
+ return;
+ prevclient = c;
+ grabbuttons(c, 0);
+ c->unfocusopacity = MIN(1.0, MAX(0, c->unfocusopacity));
+ opacity(c, c->unfocusopacity);
+ if (c == mark)
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColMark].pixel);
+ else if (c->isfloating)
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
+ else
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
}
void
unmanage(Client *c, int destroyed)
{
- Monitor *m = c->mon;
- XWindowChanges wc;
-
- if (c->swallowing)
- {
- unswallow(c);
- return;
- }
-
- Client *s = swallowingclient(c->win);
- if (s)
- {
- free(s->swallowing);
- s->swallowing = NULL;
- arrange(m);
- focus(NULL);
- return;
- }
+ int i;
+ Monitor *m = c->mon;
+ XWindowChanges wc;
if (c == mark)
setmark(0);
- detach(c);
- detachstack(c);
- if (!destroyed)
- {
- wc.border_width = c->oldbw;
- XGrabServer(dpy); /* avoid race conditions */
- XSetErrorHandler(xerrordummy);
- XSelectInput(dpy, c->win, NoEventMask);
- XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
- XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
- setclientstate(c, WithdrawnState);
- XSync(dpy, False);
- XSetErrorHandler(xerror);
- XUngrabServer(dpy);
- }
- free(c);
+ for (i = 0; i < LENGTH(tags) + 1; i++)
+ if (c->mon->pertag->sel[i] == c)
+ c->mon->pertag->sel[i] = NULL;
- if (!s)
- {
- arrange(m);
- focus(NULL);
- updateclientlist();
- }
+ if (c->swallowing) {
+ unswallow(c);
+ return;
+ }
+
+ Client *s = swallowingclient(c->win);
+ if (s) {
+ free(s->swallowing);
+ s->swallowing = NULL;
+ arrange(m);
+ focus(NULL);
+ return;
+ }
+
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+ wc.border_width = c->oldbw;
+ XGrabServer(dpy); /* avoid race conditions */
+ XSetErrorHandler(xerrordummy);
+ XSelectInput(dpy, c->win, NoEventMask);
+ XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+ setclientstate(c, WithdrawnState);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+
+ if(scratchpad_last_showed_1 == c) {
+ scratchpad_last_showed_1 = NULL;
+ }
+ if(scratchpad_last_showed_2 == c) {
+ scratchpad_last_showed_2 = NULL;
+ }
+ if(scratchpad_last_showed_3 == c) {
+ scratchpad_last_showed_3 = NULL;
+ }
+
+ free(c);
+ if (!s) {
+ arrange(m);
+ focus(NULL);
+ updateclientlist();
+ }
}
void
unmapnotify(XEvent *e)
{
- Client *c;
- XUnmapEvent *ev = &e->xunmap;
+ Client *c;
+ XUnmapEvent *ev = &e->xunmap;
- if ((c = wintoclient(ev->window)))
- {
- if (ev->send_event)
- setclientstate(c, WithdrawnState);
- else
- unmanage(c, 0);
- }
+ if ((c = wintoclient(ev->window))) {
+ if (ev->send_event)
+ setclientstate(c, WithdrawnState);
+ else
+ unmanage(c, 0);
+ }
}
void
updatebars(void)
{
- Monitor *m;
- XSetWindowAttributes wa = {.override_redirect = True,
- .background_pixel = 0,
- .border_pixel = 0,
- .colormap = cmap,
- .event_mask = ButtonPressMask | ExposureMask};
- XClassHint ch = {"dwm", "dwm"};
- for (m = mons; m; m = m->next)
- {
- if (m->barwin)
- continue;
- m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp,
- bh, 0, depth, InputOutput, visual,
- CWOverrideRedirect | CWBackPixel | CWBorderPixel |
- CWColormap | CWEventMask,
- &wa);
- XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
- XMapRaised(dpy, m->barwin);
- XSetClassHint(dpy, m->barwin, &ch);
- }
+ Monitor *m;
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+ .background_pixel = 0,
+ .border_pixel = 0,
+ .colormap = cmap,
+ .event_mask = ButtonPressMask|ExposureMask
+ };
+
+ XClassHint ch = {"dwm", "dwm"};
+ for (m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
+ m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, depth,
+ InputOutput, visual,
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->barwin);
+ XSetClassHint(dpy, m->barwin, &ch);
+ }
}
void
updatebarpos(Monitor *m)
{
- m->wy = m->my;
- m->wh = m->mh;
- if ((m->tagset[m->seltags] & m->barmask))
- {
- m->wh = m->wh - vertpad - bh;
- m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
- m->wy = m->topbar ? m->wy + bh + vp : m->wy;
- }
- else
- m->by = -bh - vp;
+ m->wy = m->my;
+ m->wh = m->mh;
+ if (m->showbar) {
+ m->wh = m->wh - vertpad - bh;
+ m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
+ m->wy = m->topbar ? m->wy + bh + vp : m->wy;
+ } else
+ m->by = -bh - vp;
}
void
-updateclientlist()
+updateclientlist(void)
{
- Client *c;
- Monitor *m;
+ Client *c;
+ Monitor *m;
- XDeleteProperty(dpy, root, netatom[NetClientList]);
- for (m = mons; m; m = m->next)
- for (c = m->clients; c; c = c->next)
- XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32,
- PropModeAppend, (unsigned char *)&(c->win), 1);
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ for (m = mons; m; m = m->next)
+ for (c = m->clients; c; c = c->next)
+ XChangeProperty(dpy, root, netatom[NetClientList],
+ XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
}
int
updategeom(void)
{
- int dirty = 0;
+ int dirty = 0;
#ifdef XINERAMA
- if (XineramaIsActive(dpy))
- {
- int i, j, n, nn;
- Client *c;
- Monitor *m;
- XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
- XineramaScreenInfo *unique = NULL;
-
- for (n = 0, m = mons; m; m = m->next, n++)
- ;
- /* only consider unique geometries as separate screens */
- unique = ecalloc(nn, sizeof(XineramaScreenInfo));
- for (i = 0, j = 0; i < nn; i++)
- if (isuniquegeom(unique, j, &info[i]))
- memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
- XFree(info);
- nn = j;
-
- /* new monitors if nn > n */
- for (i = n; i < nn; i++)
- {
- for (m = mons; m && m->next; m = m->next)
- ;
- if (m)
- m->next = createmon();
- else
- mons = createmon();
- }
- for (i = 0, m = mons; i < nn && m; m = m->next, i++)
- if (i >= n || unique[i].x_org != m->mx || unique[i].y_org != m->my ||
- unique[i].width != m->mw || unique[i].height != m->mh)
- {
- dirty = 1;
- m->num = i;
- m->mx = m->wx = unique[i].x_org;
- m->my = m->wy = unique[i].y_org;
- m->mw = m->ww = unique[i].width;
- m->mh = m->wh = unique[i].height;
- updatebarpos(m);
- }
- /* removed monitors if n > nn */
- for (i = nn; i < n; i++)
- {
- for (m = mons; m && m->next; m = m->next)
- ;
- while ((c = m->clients))
- {
- dirty = 1;
- m->clients = c->next;
- detachstack(c);
- c->mon = mons;
- attach(c);
- attachstack(c);
- }
- if (m == selmon)
- selmon = mons;
- cleanupmon(m);
- }
- free(unique);
- }
- else
+ if (XineramaIsActive(dpy)) {
+ int i, j, n, nn;
+ Client *c;
+ Monitor *m;
+ XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+ XineramaScreenInfo *unique = NULL;
+
+ for (n = 0, m = mons; m; m = m->next, n++);
+ /* only consider unique geometries as separate screens */
+ unique = ecalloc(nn, sizeof(XineramaScreenInfo));
+ for (i = 0, j = 0; i < nn; i++)
+ if (isuniquegeom(unique, j, &info[i]))
+ memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
+ XFree(info);
+ nn = j;
+
+ /* new monitors if nn > n */
+ for (i = n; i < nn; i++) {
+ for (m = mons; m && m->next; m = m->next);
+ if (m)
+ m->next = createmon();
+ else
+ mons = createmon();
+ }
+ for (i = 0, m = mons; i < nn && m; m = m->next, i++)
+ if (i >= n
+ || unique[i].x_org != m->mx || unique[i].y_org != m->my
+ || unique[i].width != m->mw || unique[i].height != m->mh)
+ {
+ dirty = 1;
+ m->num = i;
+ /* this is ugly, but it is a race condition otherwise */
+ snprintf(m->monmark, sizeof(m->monmark), "(%d)", m->num);
+ m->mx = m->wx = unique[i].x_org;
+ m->my = m->wy = unique[i].y_org;
+ m->mw = m->ww = unique[i].width;
+ m->mh = m->wh = unique[i].height;
+ updatebarpos(m);
+ }
+ /* removed monitors if n > nn */
+ for (i = nn; i < n; i++) {
+ for (m = mons; m && m->next; m = m->next);
+ while ((c = m->clients)) {
+ dirty = 1;
+ m->clients = c->next;
+ detachstack(c);
+ c->mon = mons;
+ attach(c);
+ attachstack(c);
+ }
+ if (m == selmon)
+ selmon = mons;
+ cleanupmon(m);
+ }
+ free(unique);
+ } else
#endif /* XINERAMA */
- { /* default monitor setup */
- if (!mons)
- mons = createmon();
- if (mons->mw != sw || mons->mh != sh)
- {
- dirty = 1;
- mons->mw = mons->ww = sw;
- mons->mh = mons->wh = sh;
- updatebarpos(mons);
- }
- }
- if (dirty)
- {
- selmon = mons;
- selmon = wintomon(root);
- }
- return dirty;
+ { /* default monitor setup */
+ if (!mons)
+ mons = createmon();
+ if (mons->mw != sw || mons->mh != sh) {
+ dirty = 1;
+ mons->mw = mons->ww = sw;
+ mons->mh = mons->wh = sh;
+ updatebarpos(mons);
+ }
+ }
+ if (dirty) {
+ selmon = mons;
+ selmon = wintomon(root);
+ }
+ return dirty;
}
void
updatenumlockmask(void)
{
- unsigned int i, j;
- XModifierKeymap *modmap;
+ unsigned int i, j;
+ XModifierKeymap *modmap;
- numlockmask = 0;
- modmap = XGetModifierMapping(dpy);
- for (i = 0; i < 8; i++)
- for (j = 0; j < modmap->max_keypermod; j++)
- if (modmap->modifiermap[i * modmap->max_keypermod + j] ==
- XKeysymToKeycode(dpy, XK_Num_Lock))
- numlockmask = (1 << i);
- XFreeModifiermap(modmap);
+ numlockmask = 0;
+ modmap = XGetModifierMapping(dpy);
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < modmap->max_keypermod; j++)
+ if (modmap->modifiermap[i * modmap->max_keypermod + j]
+ == XKeysymToKeycode(dpy, XK_Num_Lock))
+ numlockmask = (1 << i);
+ XFreeModifiermap(modmap);
}
void
updatesizehints(Client *c)
{
- long msize;
- XSizeHints size;
-
- if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
- /* size is uninitialized, ensure that size.flags aren't used */
- size.flags = PSize;
- if (size.flags & PBaseSize)
- {
- c->basew = size.base_width;
- c->baseh = size.base_height;
- }
- else if (size.flags & PMinSize)
- {
- c->basew = size.min_width;
- c->baseh = size.min_height;
- }
- else
- c->basew = c->baseh = 0;
- if (size.flags & PResizeInc)
- {
- c->incw = size.width_inc;
- c->inch = size.height_inc;
- }
- else
- c->incw = c->inch = 0;
- if (size.flags & PMaxSize)
- {
- c->maxw = size.max_width;
- c->maxh = size.max_height;
- }
- else
- c->maxw = c->maxh = 0;
- if (size.flags & PMinSize)
- {
- c->minw = size.min_width;
- c->minh = size.min_height;
- }
- else if (size.flags & PBaseSize)
- {
- c->minw = size.base_width;
- c->minh = size.base_height;
- }
- else
- c->minw = c->minh = 0;
- if (size.flags & PAspect)
- {
- c->mina = (float)size.min_aspect.y / size.min_aspect.x;
- c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
- }
- else
- c->maxa = c->mina = 0.0;
- c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+ long msize;
+ XSizeHints size;
+
+ if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
+ /* size is uninitialized, ensure that size.flags aren't used */
+ size.flags = PSize;
+ if (size.flags & PBaseSize) {
+ c->basew = size.base_width;
+ c->baseh = size.base_height;
+ } else if (size.flags & PMinSize) {
+ c->basew = size.min_width;
+ c->baseh = size.min_height;
+ } else
+ c->basew = c->baseh = 0;
+ if (size.flags & PResizeInc) {
+ c->incw = size.width_inc;
+ c->inch = size.height_inc;
+ } else
+ c->incw = c->inch = 0;
+ if (size.flags & PMaxSize) {
+ c->maxw = size.max_width;
+ c->maxh = size.max_height;
+ } else
+ c->maxw = c->maxh = 0;
+ if (size.flags & PMinSize) {
+ c->minw = size.min_width;
+ c->minh = size.min_height;
+ } else if (size.flags & PBaseSize) {
+ c->minw = size.base_width;
+ c->minh = size.base_height;
+ } else
+ c->minw = c->minh = 0;
+ if (size.flags & PAspect) {
+ c->mina = (float)size.min_aspect.y / size.min_aspect.x;
+ c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
+ } else
+ c->maxa = c->mina = 0.0;
+ c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+ c->hintsvalid = 1;
}
void
updatestatus(void)
{
- if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
- strcpy(stext, "dwm-" VERSION);
- else
- copyvalidchars(stext, rawstext);
- drawbar(selmon);
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)) && selmon->showstatus) {
+ strcpy(stext, "dwm-"VERSION);
+ statusw = TEXTW(stext) - lrpad + 2;
+ } else {
+ char *text, *s, ch;
+
+ statusw = 0;
+ for (text = s = stext; *s; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ statusw += TEXTW(text) - lrpad;
+ *s = ch;
+ text = s + 1;
+ }
+ }
+ statusw += TEXTW(text) - lrpad + 2;
+ }
+
+ statusall ? drawbars() : drawbar(selmon);
}
void
updatetitle(Client *c)
{
- if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
- gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
- if (c->name[0] == '\0') /* hack to mark broken clients */
- strcpy(c->name, broken);
+ if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
+ gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
+ if (c->name[0] == '\0') /* hack to mark broken clients */
+ strcpy(c->name, broken);
}
void
updatewindowtype(Client *c)
{
- Atom state = getatomprop(c, netatom[NetWMState]);
- Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
+ Atom state = getatomprop(c, netatom[NetWMState]);
+ Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
- if (state == netatom[NetWMFullscreen])
- setfullscreen(c, 1);
- if (wtype == netatom[NetWMWindowTypeDialog])
- c->isfloating = 1;
+ if (state == netatom[NetWMFullscreen])
+ setfullscreen(c, 1);
+ if (state == netatom[NetWMSticky]) {
+ setsticky(c, 1);
+ }
+ if (wtype == netatom[NetWMWindowTypeDialog])
+ c->isfloating = 1;
}
void
updatewmhints(Client *c)
{
- XWMHints *wmh;
+ XWMHints *wmh;
- if ((wmh = XGetWMHints(dpy, c->win)))
- {
- if (c == selmon->sel && wmh->flags & XUrgencyHint)
- {
- wmh->flags &= ~XUrgencyHint;
- XSetWMHints(dpy, c->win, wmh);
- }
- else
- c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
- if (wmh->flags & InputHint)
- c->neverfocus = !wmh->input;
- else
- c->neverfocus = 0;
- XFree(wmh);
- }
+ if ((wmh = XGetWMHints(dpy, c->win))) {
+ if (c == selmon->sel && wmh->flags & XUrgencyHint) {
+ wmh->flags &= ~XUrgencyHint;
+ XSetWMHints(dpy, c->win, wmh);
+ } else
+ c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
+ if (wmh->flags & InputHint)
+ c->neverfocus = !wmh->input;
+ else
+ c->neverfocus = 0;
+ XFree(wmh);
+ }
+}
+
+void
+nview(const Arg *arg)
+{
+ const Arg n = {.i = +1};
+ const int mon = selmon->num;
+ do {
+ focusmon(&n);
+ view(arg);
+ }
+ while (selmon->num != mon);
}
void
view(const Arg *arg)
{
- int i;
- unsigned int tmptag;
-
- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
- return;
- selmon->seltags ^= 1; /* toggle sel tagset */
- if (arg->ui & TAGMASK)
- {
- selmon->pertag->prevtag = selmon->pertag->curtag;
- selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
- if (arg->ui == ~0)
- selmon->pertag->curtag = 0;
- else
- {
- for (i = 0; !(arg->ui & 1 << i); i++)
- ;
- selmon->pertag->curtag = i + 1;
- }
- }
- else
- {
- tmptag = selmon->pertag->prevtag;
- selmon->pertag->prevtag = selmon->pertag->curtag;
- selmon->pertag->curtag = tmptag;
- }
- selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
- selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
- selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
- selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
- selmon->lt[selmon->sellt ^ 1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt ^ 1];
- updatebarpos(selmon);
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp,
- selmon->ww - 2 * sp, bh);
- focus(NULL);
- arrange(selmon);
+ int i;
+ unsigned int tmptag;
+
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK) {
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+
+ if (arg->ui == ~0)
+ selmon->pertag->curtag = 0;
+ else {
+ for (i = 0; !(arg->ui & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+ } else {
+ tmptag = selmon->pertag->prevtag;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = tmptag;
+ }
+
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+
+ focus(selmon->pertag->sel[selmon->pertag->curtag]);
+ arrange(selmon);
}
pid_t
winpid(Window w)
{
- pid_t result = 0;
-
- xcb_res_client_id_spec_t spec = {0};
- spec.client = w;
- spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
-
- xcb_generic_error_t *e = NULL;
- xcb_res_query_client_ids_cookie_t c =
- xcb_res_query_client_ids(xcon, 1, &spec);
- xcb_res_query_client_ids_reply_t *r =
- xcb_res_query_client_ids_reply(xcon, c, &e);
-
- if (!r)
- return (pid_t)0;
-
- xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
- for (; i.rem; xcb_res_client_id_value_next(&i))
- {
- spec = i.data->spec;
- if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID)
- {
- uint32_t *t = xcb_res_client_id_value_value(i.data);
- result = *t;
- break;
- }
- }
- free(r);
+ pid_t result = 0;
+
+#ifdef __linux__
+ xcb_res_client_id_spec_t spec = {0};
+ spec.client = w;
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
+
+ xcb_generic_error_t *e = NULL;
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
+
+ if (!r)
+ return (pid_t)0;
- if (result == (pid_t)-1)
- result = 0;
- return result;
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
+ spec = i.data->spec;
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
+ result = *t;
+ break;
+ }
+ }
+
+ free(r);
+
+ if (result == (pid_t)-1)
+ result = 0;
+
+#endif /* __linux__ */
+
+#ifdef __OpenBSD__
+ Atom type;
+ int format;
+ unsigned long len, bytes;
+ unsigned char *prop;
+ pid_t ret;
+
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
+ return 0;
+
+ ret = *(pid_t*)prop;
+ XFree(prop);
+ result = ret;
+#endif /* __OpenBSD__ */
+ return result;
}
pid_t
getparentprocess(pid_t p)
{
- unsigned int v = 0;
+ unsigned int v = 0;
+
+#ifdef __linux__
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
-#if defined(__linux__)
- FILE *f;
- char buf[256];
- snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+ if (!(f = fopen(buf, "r")))
+ return 0;
- if (!(f = fopen(buf, "r")))
- return (pid_t)0;
+ fscanf(f, "%*u %*s %*c %u", &v);
+ fclose(f);
+#endif /* __linux__*/
+
+#ifdef __OpenBSD__
+ int n;
+ kvm_t *kd;
+ struct kinfo_proc *kp;
- if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1)
- v = (pid_t)0;
- fclose(f);
-#elif defined(__FreeBSD__)
- struct kinfo_proc *proc = kinfo_getproc(p);
- if (!proc)
- return (pid_t)0;
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
+ if (!kd)
+ return 0;
- v = proc->ki_ppid;
- free(proc);
-#endif
- return (pid_t)v;
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
+ v = kp->p_ppid;
+#endif /* __OpenBSD__ */
+
+ return (pid_t)v;
}
int
isdescprocess(pid_t p, pid_t c)
{
- while (p != c && c != 0)
- c = getparentprocess(c);
+ while (p != c && c != 0)
+ c = getparentprocess(c);
- return (int)c;
+ return (int)c;
}
Client *
termforwin(const Client *w)
{
- Client *c;
- Monitor *m;
+ Client *c;
+ Monitor *m;
- if (!w->pid || w->isterminal)
- return NULL;
+ if (!w->pid || w->isterminal)
+ return NULL;
- for (m = mons; m; m = m->next)
- {
- for (c = m->clients; c; c = c->next)
- {
- if (c->isterminal && !c->swallowing && c->pid &&
- isdescprocess(c->pid, w->pid))
- return c;
- }
- }
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+ }
+ }
- return NULL;
+ return NULL;
}
Client *
swallowingclient(Window w)
{
- Client *c;
- Monitor *m;
+ Client *c;
+ Monitor *m;
- for (m = mons; m; m = m->next)
- {
- for (c = m->clients; c; c = c->next)
- {
- if (c->swallowing && c->swallowing->win == w)
- return c;
- }
- }
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->swallowing && c->swallowing->win == w)
+ return c;
+ }
+ }
- return NULL;
+ return NULL;
+}
+
+void
+viewall(const Arg *arg)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ m->tagset[m->seltags] = arg->ui;
+ arrange(m);
+ }
+ focus(NULL);
}
Client *
wintoclient(Window w)
{
- Client *c;
- Monitor *m;
+ Client *c;
+ Monitor *m;
- for (m = mons; m; m = m->next)
- for (c = m->clients; c; c = c->next)
- if (c->win == w)
- return c;
- return NULL;
+ for (m = mons; m; m = m->next)
+ for (c = m->clients; c; c = c->next)
+ if (c->win == w)
+ return c;
+ return NULL;
}
-Monitor *wintomon(Window w)
+Monitor *
+wintomon(Window w)
{
- int x, y;
- Client *c;
- Monitor *m;
+ int x, y;
+ Client *c;
+ Monitor *m;
+
+ if (w == root && getrootptr(&x, &y))
+ return recttomon(x, y, 1, 1);
+ for (m = mons; m; m = m->next)
+ if (w == m->barwin)
+ return m;
+ if ((c = wintoclient(w)))
+ return c->mon;
+ return selmon;
+}
+
+/* Selects for the view of the focused window. The list of tags */
+/* to be displayed is matched to the focused window tag list. */
+void
+winview(const Arg* arg){
+ Window win, win_r, win_p, *win_c;
+ unsigned nc;
+ int unused;
+ Client* c;
+ Arg a;
+
+ if (!XGetInputFocus(dpy, &win, &unused)) return;
+ while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc)
+ && win_p != win_r) win = win_p;
- if (w == root && getrootptr(&x, &y))
- return recttomon(x, y, 1, 1);
- for (m = mons; m; m = m->next)
- if (w == m->barwin)
- return m;
- if ((c = wintoclient(w)))
- return c->mon;
- return selmon;
+ if (!(c = wintoclient(win))) return;
+
+ a.ui = c->tags;
+ view(&a);
}
/* There's no way to check accesses to destroyed windows, thus those cases are
@@ -3443,177 +3910,168 @@ Monitor *wintomon(Window w)
int
xerror(Display *dpy, XErrorEvent *ee)
{
- if (ee->error_code == BadWindow ||
- (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) ||
- (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) ||
- (ee->request_code == X_PolyFillRectangle &&
- ee->error_code == BadDrawable) ||
- (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) ||
- (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) ||
- (ee->request_code == X_GrabButton && ee->error_code == BadAccess) ||
- (ee->request_code == X_GrabKey && ee->error_code == BadAccess) ||
- (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
- return 0;
- fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
- ee->request_code, ee->error_code);
- return xerrorxlib(dpy, ee); /* may call exit */
+ if (ee->error_code == BadWindow
+ || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
+ || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
+ || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
+ || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
+ || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
+ || (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
+ || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
+ || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
+ return 0;
+ fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
+ ee->request_code, ee->error_code);
+ return xerrorxlib(dpy, ee); /* may call exit */
}
int
-xerrordummy(Display *dpy, XErrorEvent *ee) { return 0; }
+xerrordummy(Display *dpy, XErrorEvent *ee)
+{
+ return 0;
+}
/* Startup Error handler to check if another window manager
* is already running. */
int
xerrorstart(Display *dpy, XErrorEvent *ee)
{
- die("dwm: another window manager is already running");
- return -1;
+ die("dwm: another window manager is already running");
+ return -1;
}
void
xinitvisual()
{
XVisualInfo *infos;
- XRenderPictFormat *fmt;
- int nitems;
- int i;
+ XRenderPictFormat *fmt;
+ int nitems;
+ int i;
- XVisualInfo tpl = {.screen = screen, .depth = 32, .class = TrueColor};
- long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
+ 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++)
- {
+ 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)
- {
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
visual = infos[i].visual;
- depth = infos[i].depth;
- cmap = XCreateColormap(dpy, root, visual, AllocNone);
- useargb = 1;
- break;
+ depth = infos[i].depth;
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
+ useargb = 1;
+ break;
}
}
- XFree(infos);
+ XFree(infos);
- if (!visual)
- {
+ if (! visual) {
visual = DefaultVisual(dpy, screen);
- depth = DefaultDepth(dpy, screen);
- cmap = DefaultColormap(dpy, screen);
+ depth = DefaultDepth(dpy, screen);
+ cmap = DefaultColormap(dpy, screen);
}
}
void
zoom(const Arg *arg)
{
- Client *c = selmon->sel;
-
- if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
- return;
- if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
- return;
- pop(c);
-}
-
-void
-xrdb(const Arg *arg)
-{
- load_xresources();
-
- for (int i = 0; i < LENGTH(colors); i++)
- scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
+ Client *c = selmon->sel;
+ prevclient = nexttiled(selmon->clients);
- focus(NULL);
- arrange(NULL);
+ if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
+ return;
+ if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
+ if (!c || !(c = prevclient = nexttiled(c->next)))
+ return;
+ pop(c);
}
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", "dwm", 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;
- }
- }
+ 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", "dwm", 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 *display;
+ char *resm;
+ XrmDatabase db;
+ ResourcePref *p;
- display = XOpenDisplay(NULL);
- resm = XResourceManagerString(display);
- if (!resm)
- return;
+ 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);
+ db = XrmGetStringDatabase(resm);
+ for (p = resources; p < resources + LENGTH(resources); p++)
+ resource_load(db, p->name, p->type, p->dst);
+ XCloseDisplay(display);
}
int
main(int argc, char *argv[])
{
- if (argc == 2 && !strcmp("-v", argv[1]))
- die("dwm-" VERSION);
- else if (argc != 1)
- die("usage: dwm [-v]");
- if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
- fputs("warning: no locale support\n", stderr);
- if (!(dpy = XOpenDisplay(NULL)))
- die("dwm: cannot open display");
- if (!(xcon = XGetXCBConnection(dpy)))
- die("dwm: cannot get xcb connection\n");
- checkotherwm();
- XrmInitialize();
- load_xresources();
- setup();
+ if (argc == 2 && !strcmp("-v", argv[1]))
+ die("dwm-"VERSION);
+ else if (argc != 1)
+ die("usage: dwm [-v]");
+ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
+ fputs("warning: no locale support\n", stderr);
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("dwm: cannot open display");
+ if (!(xcon = XGetXCBConnection(dpy)))
+ die("dwm: cannot get xcb connection\n");
+ checkotherwm();
+ XrmInitialize();
+ load_xresources();
+ setup();
#ifdef __OpenBSD__
- if (pledge("stdio rpath proc exec", NULL) == -1)
- die("pledge");
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
+ die("pledge");
#endif /* __OpenBSD__ */
- scan();
- runAutostart();
- run();
- if (restart)
- execvp(argv[0], argv);
- cleanup();
- XCloseDisplay(dpy);
- return EXIT_SUCCESS;
+ scan();
+ runAutostart();
+ run();
+ if(restart) execvp(argv[0], argv);
+ cleanup();
+ XCloseDisplay(dpy);
+ return EXIT_SUCCESS;
}
diff --git a/dwm/exresize.c b/dwm/exresize.c
index e3f0424..d0a1e9e 100644
--- a/dwm/exresize.c
+++ b/dwm/exresize.c
@@ -41,26 +41,26 @@ exresize(const Arg *arg) {
ny = c->y - y/2;
if (!((abs(c->x + c->w/2 - (selmon->wx + selmon->ww/2)) < snap))) {
- if ((nw == selmon->ww) ||
+ if ((nw == selmon->ww) ||
(nx < selmon->wx) ||
(abs(selmon->wx - c->x) < snap))
nx = selmon->wx;
- else if ((nx+nw > (selmon->wx + selmon->ww)) ||
+ else if ((nx+nw > (selmon->wx + selmon->ww)) ||
(abs((selmon->wx + selmon->ww) - (c->x + c->w)) < snap))
nx = (selmon->wx + selmon->ww) - nw - c->bw*2;
- } else
+ } else
nx = selmon->wx + selmon->ww/2 - nw/2;
if (!((abs(c->y + c->h/2 - (selmon->wy + selmon->wh/2)) < snap))) {
- if ((nh == selmon->wh) ||
+ if ((nh == selmon->wh) ||
(ny < selmon->wy) ||
(abs(selmon->wy - c->y) < snap))
ny = selmon->wy;
else if ((ny+nh > (selmon->wy + selmon->wh)) ||
(abs((selmon->wy + selmon->wh) - (c->y + c->h)) < snap))
ny = (selmon->wy + selmon->wh) - nh - c->bw*2;
- } else
+ } else
ny = selmon->wy + selmon->wh/2 - nh/2;
diff --git a/dwm/layoutmenu b/dwm/layoutmenu
index 230573f..9d162e7 100755
--- a/dwm/layoutmenu
+++ b/dwm/layoutmenu
@@ -1,7 +1,5 @@
#!/bin/sh
-command -v xmenu >/dev/null || exit 1
-
cat <<EOF | xmenu
0 []= Tile
1 [M] Monocle
@@ -17,5 +15,6 @@ cat <<EOF | xmenu
11 ::: Gaplessgrid
12 |M| Centeredmaster
13 >M> Centeredfloatingmaster
-14 ><> Float
+14 [S] Stairs
+15 ><> Float
EOF
diff --git a/dwm/patches/alwaysontop-6.2.diff b/dwm/patches/alwaysontop-6.2.diff
new file mode 100644
index 0000000..1feb033
--- /dev/null
+++ b/dwm/patches/alwaysontop-6.2.diff
@@ -0,0 +1,109 @@
+# From 9cd160c4ba9c345c24644a7da77cc4f04fc93c4e Mon Sep 17 00:00:00 2001
+# From: Rob Pilling <robpilling@gmail.com>
+# Date: Mon, 27 Jul 2020 20:11:08 +0100
+# Subject: [PATCH] alwaysontop
+#
+# ---
+# config.def.h | 1 +
+# dwm.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
+# 2 files changed, 44 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..c3c7edd 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -78,6 +78,7 @@ static Key keys[] = {
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
++ { MODKEY|ShiftMask, XK_space, togglealwaysontop, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..8d54b26 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -92,7 +92,7 @@ struct Client {
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh;
+ int bw, oldbw;
+ unsigned int tags;
+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int isfixed, iscentered, isfloating, isalwaysontop, isurgent, neverfocus, oldstate, isfullscreen;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglealwaysontop(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -732,8 +733,11 @@ drawbar(Monitor *m)
+ if (m->sel) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+- if (m->sel->isfloating)
++ if (m->sel->isfloating) {
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
++ if (m->sel->isalwaysontop)
++ drw_rect(drw, x + boxs, bh - boxw, boxw, boxw, 0, 0);
++ }
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, x, 0, w, bh, 1, 1);
+@@ -1356,6 +1360,17 @@ restack(Monitor *m)
+ return;
+ if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
+ XRaiseWindow(dpy, m->sel->win);
++
++ /* raise the aot window */
++ for(Monitor *m_search = mons; m_search; m_search = m_search->next){
++ for(c = m_search->clients; c; c = c->next){
++ if(c->isalwaysontop){
++ XRaiseWindow(dpy, c->win);
++ break;
++ }
++ }
++ }
++
+ if (m->lt[m->sellt]->arrange) {
+ wc.stack_mode = Below;
+ wc.sibling = m->barwin;
+@@ -1716,6 +1731,32 @@ togglefloating(const Arg *arg)
+ if (selmon->sel->isfloating)
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, 0);
++ else
++ selmon->sel->isalwaysontop = 0; /* disabled, turn this off too */
++ arrange(selmon);
++}
++
++void
++togglealwaysontop(const Arg *arg)
++{
++ if (!selmon->sel)
++ return;
++ if (selmon->sel->isfullscreen)
++ return;
++
++ if(selmon->sel->isalwaysontop){
++ selmon->sel->isalwaysontop = 0;
++ }else{
++ /* disable others */
++ for(Monitor *m = mons; m; m = m->next)
++ for(Client *c = m->clients; c; c = c->next)
++ c->isalwaysontop = 0;
++
++ /* turn on, make it float too */
++ selmon->sel->isfloating = 1;
++ selmon->sel->isalwaysontop = 1;
++ }
++
+ arrange(selmon);
+ }
+
+--
+2.31.1
diff --git a/dwm/patches/dwm-accessnthmon.diff b/dwm/patches/dwm-accessnthmon.diff
new file mode 100644
index 0000000..a65ec15
--- /dev/null
+++ b/dwm/patches/dwm-accessnthmon.diff
@@ -0,0 +1,100 @@
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..8595a71 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -49,7 +49,10 @@ static const Layout layouts[] = {
+ { 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} },
++ { 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 } }
+diff --git a/dwm.c b/dwm.c
+index b0b3466..96fa0bd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -161,6 +161,7 @@ static void destroynotify(XEvent *e);
+ static void detach(Client *c);
+ static void detachstack(Client *c);
+ static Monitor *dirtomon(int dir);
++static Monitor *numtomon(int num);
+ static void drawbar(Monitor *m);
+ static void drawbars(void);
+ static void enternotify(XEvent *e);
+@@ -168,6 +169,7 @@ 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 Atom getatomprop(Client *c, Atom prop);
+ static int getrootptr(int *x, int *y);
+@@ -209,6 +211,7 @@ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
+ 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);
+@@ -693,6 +696,18 @@ dirtomon(int dir)
+ return m;
+ }
+
++Monitor *
++numtomon(int num)
++{
++ Monitor *m = NULL;
++ int i = 0;
++
++ for(m = mons, i=0; m->next && i < num; m = m->next){
++ i++;
++ }
++ return m;
++}
++
+ void
+ drawbar(Monitor *m)
+ {
+@@ -830,6 +845,21 @@ focusmon(const Arg *arg)
+ focus(NULL);
+ }
+
++void
++focusnthmon(const Arg *arg)
++{
++ Monitor *m;
++
++ if (!mons->next)
++ return;
++
++ if ((m = numtomon(arg->i)) == selmon)
++ return;
++ unfocus(selmon->sel, 0);
++ selmon = m;
++ focus(NULL);
++}
++
+ void
+ focusstack(const Arg *arg)
+ {
+@@ -1671,6 +1701,14 @@ tagmon(const Arg *arg)
+ sendmon(selmon->sel, dirtomon(arg->i));
+ }
+
++void
++tagnthmon(const Arg *arg)
++{
++ if (!selmon->sel || !mons->next)
++ return;
++ sendmon(selmon->sel, numtomon(arg->i));
++}
++
+ void
+ tile(Monitor *m)
+ {
diff --git a/dwm/patches/dwm-actualfullscreen-20211013-cb3f58a.diff b/dwm/patches/dwm-actualfullscreen-20211013-cb3f58a.diff
new file mode 100644
index 0000000..364b3bd
--- /dev/null
+++ b/dwm/patches/dwm-actualfullscreen-20211013-cb3f58a.diff
@@ -0,0 +1,67 @@
+# From eea13010ffc3983392857ee1e3804e3aa1064d7a Mon Sep 17 00:00:00 2001
+# From: Soenke Lambert <s.lambert@mittwald.de>
+# Date: Wed, 13 Oct 2021 18:21:09 +0200
+# Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f]
+#
+# This actually fullscreens a window, instead of just hiding the statusbar
+# and applying the monocle layout.
+# ---
+# config.def.h | 1 +
+# dwm.1 | 3 +++
+# dwm.c | 8 ++++++++
+# 3 files changed, 12 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..8cd3204 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -78,6 +78,7 @@ static Key keys[] = {
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+diff --git a/dwm.1 b/dwm.1
+index 13b3729..a368d05 100644
+--- a/dwm.1
++++ b/dwm.1
+@@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only).
+ .B Mod1\-Shift\-c
+ Close focused window.
+ .TP
++.B Mod1\-Shift\-f
++Toggle fullscreen for focused window.
++.TP
+ .B Mod1\-Shift\-space
+ Toggle focused window between tiled and floating state.
+ .TP
+diff --git a/dwm.c b/dwm.c
+index 4465af1..c1b899a 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -211,6 +211,7 @@ static void tagmon(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 toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++togglefullscr(const Arg *arg)
++{
++ if(selmon->sel)
++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
++}
++
+ void
+ toggletag(const Arg *arg)
+ {
+--
+2.30.2
diff --git a/dwm/patches/dwm-allowkillrule-6.4.diff b/dwm/patches/dwm-allowkillrule-6.4.diff
new file mode 100644
index 0000000..33365d7
--- /dev/null
+++ b/dwm/patches/dwm-allowkillrule-6.4.diff
@@ -0,0 +1,98 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2022-10-04 19:38:18.000000000 +0200
++++ b/config.def.h 2023-05-06 22:19:27.298742237 +0200
+@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1;
+ 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 allowkill = 1; /* allow killing clients by default? */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+ static const char col_gray1[] = "#222222";
+@@ -26,9 +27,9 @@ static const Rule rules[] = {
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+- /* class instance title tags mask isfloating monitor */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ /* class instance title tags mask allowkill isfloating monitor */
++ { "Gimp", NULL, NULL, 0, 1, 1, -1 },
++ { "Firefox", NULL, NULL, 1 << 8, 1, 0, -1 },
+ };
+
+ /* layout(s) */
+@@ -78,6 +79,7 @@ static const Key keys[] = {
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
++ { MODKEY, XK_q, toggleallowkill,{0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2022-10-04 19:38:18.000000000 +0200
++++ b/dwm.c 2023-05-06 22:18:43.239357744 +0200
+@@ -93,6 +93,7 @@ struct Client {
+ int bw, oldbw;
+ unsigned int tags;
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int allowkill;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -137,6 +138,7 @@ typedef struct {
+ const char *instance;
+ const char *title;
+ unsigned int tags;
++ int allowkill;
+ int isfloating;
+ int monitor;
+ } Rule;
+@@ -212,6 +214,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void toggleallowkill(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -288,6 +291,7 @@ applyrules(Client *c)
+ /* rule matching */
+ c->isfloating = 0;
+ c->tags = 0;
++ c->allowkill = allowkill;
+ XGetClassHint(dpy, c->win, &ch);
+ class = ch.res_class ? ch.res_class : broken;
+ instance = ch.res_name ? ch.res_name : broken;
+@@ -300,6 +304,7 @@ applyrules(Client *c)
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
++ c->allowkill = r->allowkill;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+@@ -1006,7 +1011,7 @@ keypress(XEvent *e)
+ void
+ killclient(const Arg *arg)
+ {
+- if (!selmon->sel)
++ if (!selmon->sel || !selmon->sel->allowkill)
+ return;
+ if (!sendevent(selmon->sel, wmatom[WMDelete])) {
+ XGrabServer(dpy);
+@@ -1704,6 +1709,13 @@ togglebar(const Arg *arg)
+ }
+
+ void
++toggleallowkill(const Arg *arg)
++{
++ if (!selmon->sel) return;
++ selmon->sel->allowkill = !selmon->sel->allowkill;
++}
++
++void
+ togglefloating(const Arg *arg)
+ {
+ if (!selmon->sel)
diff --git a/dwm/patches/dwm-alpha-20230401-348f655.diff b/dwm/patches/dwm-alpha-20230401-348f655.diff
new file mode 100644
index 0000000..8096f04
--- /dev/null
+++ b/dwm/patches/dwm-alpha-20230401-348f655.diff
@@ -0,0 +1,287 @@
+# From ad5887df95fda706291c81ee143d0786a1717b12 Mon Sep 17 00:00:00 2001
+# From: getimiskon <getimiskon@disroot.org>
+# Date: Sat, 1 Apr 2023 16:22:01 +0300
+# Subject: [PATCH] Allow dwm to have translucent bars, while keeping all the
+# text on it opaque, just like the alpha-patch for st. Updated for 348f655.
+#
+# ---
+# config.def.h | 7 +++++++
+# config.mk | 2 +-
+# drw.c | 26 ++++++++++++-----------
+# drw.h | 9 +++++---
+# dwm.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++------
+# 5 files changed, 81 insertions(+), 22 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..8b3789a 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -12,11 +12,18 @@ static const char col_gray2[] = "#444444";
+ static const char col_gray3[] = "#bbbbbb";
+ static const char col_gray4[] = "#eeeeee";
+ static const char col_cyan[] = "#005577";
++static const unsigned int baralpha = 0xd0;
++static const unsigned int borderalpha = OPAQUE;
+ static const char *colors[][3] = {
+ /* fg bg border */
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ };
++static const unsigned int alphas[][3] = {
++ /* fg bg border*/
++ [SchemeNorm] = { OPAQUE, baralpha, borderalpha },
++ [SchemeSel] = { OPAQUE, baralpha, borderalpha },
++};
+
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+diff --git a/config.mk b/config.mk
+index ba64d3d..d609c42 100644
+--- a/config.mk
++++ b/config.mk
+@@ -23,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2
+
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/drw.c b/drw.c
+index a58a2b4..d18e8d8 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
+@@ -181,21 +184,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;
+@@ -205,7 +209,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;
+ }
+
+@@ -263,9 +267,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 6471431..2143533 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 *visual, unsigned int depth, Colormap cmap);
+ void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+ void drw_free(Drw *drw);
+
+@@ -39,8 +42,8 @@ unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int
+ 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/dwm.c b/dwm.c
+index c2bd871..3b34de8 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -56,6 +56,7 @@
+ #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
+ #define TAGMASK ((1 << LENGTH(tags)) - 1)
+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
++#define OPAQUE 0xffU
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+@@ -232,6 +233,7 @@ static Monitor *wintomon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
++static void xinitvisual();
+ static void zoom(const Arg *arg);
+
+ /* variables */
+@@ -268,6 +270,11 @@ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
+
++static int useargb = 0;
++static Visual *visual;
++static int depth;
++static Colormap cmap;
++
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
+@@ -1558,7 +1565,8 @@ setup(void)
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ root = RootWindow(dpy, screen);
+- drw = drw_create(dpy, screen, root, sw, sh);
++ xinitvisual();
++ drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+@@ -1586,7 +1594,7 @@ setup(void)
+ /* init appearance */
+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ for (i = 0; i < LENGTH(colors); i++)
+- scheme[i] = drw_scm_create(drw, colors[i], 3);
++ scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
+ /* init bars */
+ updatebars();
+ updatestatus();
+@@ -1813,16 +1821,18 @@ updatebars(void)
+ Monitor *m;
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+- .background_pixmap = ParentRelative,
++ .background_pixel = 0,
++ .border_pixel = 0,
++ .colormap = cmap,
+ .event_mask = ButtonPressMask|ExposureMask
+ };
+ XClassHint ch = {"dwm", "dwm"};
+ for (m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
+- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+- CopyFromParent, DefaultVisual(dpy, screen),
+- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
++ InputOutput, visual,
++ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->barwin);
+ XSetClassHint(dpy, m->barwin, &ch);
+@@ -2120,6 +2130,43 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
+ return -1;
+ }
+
++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);
++ }
++}
++
+ void
+ zoom(const Arg *arg)
+ {
+--
+2.40.0
diff --git a/dwm/patches/dwm-alttab2+winview-6.4.diff b/dwm/patches/dwm-alttab2+winview-6.4.diff
new file mode 100644
index 0000000..38cb482
--- /dev/null
+++ b/dwm/patches/dwm-alttab2+winview-6.4.diff
@@ -0,0 +1,217 @@
+diff --git a/config.def.h b/config.def.h
+index 9efa774..95499bd 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -2,6 +2,8 @@
+
+ /* appearance */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
++static const unsigned int tabModKey = 0x40;
++static const unsigned int tabCycleKey = 0x17;
+ 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 */
+@@ -95,6 +97,8 @@ static const Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_o, winview, {0} },
++ { Mod1Mask, XK_Tab, alttab, {0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.1 b/dwm.1
+index ddc8321..f8a809e 100644
+--- a/dwm.1
++++ b/dwm.1
+@@ -110,6 +110,9 @@ Increase master area size.
+ .B Mod1\-h
+ Decrease master area size.
+ .TP
++.B Mod1\-o
++Select view of the window in focus. The list of tags to be displayed is matched to the window tag list.
++.TP
+ .B Mod1\-Return
+ Zooms/cycles focused window to/from master area (tiled layouts only).
+ .TP
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..71d0ebc 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -28,6 +28,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <time.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <X11/cursorfont.h>
+@@ -142,6 +143,7 @@ typedef struct {
+ } Rule;
+
+ /* function declarations */
++static void alttab(const Arg *arg);
+ static void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+ static void arrange(Monitor *m);
+@@ -168,6 +170,7 @@ static void expose(XEvent *e);
+ static void focus(Client *c);
+ static void focusin(XEvent *e);
+ static void focusmon(const Arg *arg);
++static void focusnext(const Arg *arg);
+ static void focusstack(const Arg *arg);
+ static Atom getatomprop(Client *c, Atom prop);
+ static int getrootptr(int *x, int *y);
+@@ -229,6 +232,7 @@ static void updatewmhints(Client *c);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
++static void winview(const Arg* arg);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+@@ -268,6 +272,8 @@ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
+
++static int alt_tab_direction = 0;
++
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
+@@ -275,6 +281,79 @@ static Window root, wmcheckwin;
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+ /* function implementations */
++
++static void
++alttab(const Arg *arg) {
++
++ view(&(Arg){ .ui = ~0 });
++ focusnext(&(Arg){ .i = alt_tab_direction });
++
++ int grabbed = 1;
++ int grabbed_keyboard = 1000;
++ for (int i = 0; i < 100; i += 1) {
++ struct timespec ts;
++ ts.tv_sec = 0;
++ ts.tv_nsec = 1000000;
++
++ if (grabbed_keyboard != GrabSuccess) {
++ grabbed_keyboard = XGrabKeyboard(dpy, DefaultRootWindow(dpy), True,
++ GrabModeAsync, GrabModeAsync, CurrentTime);
++ }
++ if (grabbed_keyboard == GrabSuccess) {
++ XGrabButton(dpy, AnyButton, AnyModifier, None, False,
++ BUTTONMASK, GrabModeAsync, GrabModeAsync,
++ None, None);
++ break;
++ }
++ nanosleep(&ts, NULL);
++ if (i == 100 - 1)
++ grabbed = 0;
++ }
++
++ XEvent event;
++ Client *c;
++ Monitor *m;
++ XButtonPressedEvent *ev;
++
++ while (grabbed) {
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case KeyPress:
++ if (event.xkey.keycode == tabCycleKey)
++ focusnext(&(Arg){ .i = alt_tab_direction });
++ break;
++ case KeyRelease:
++ if (event.xkey.keycode == tabModKey) {
++ XUngrabKeyboard(dpy, CurrentTime);
++ XUngrabButton(dpy, AnyButton, AnyModifier, None);
++ grabbed = 0;
++ alt_tab_direction = !alt_tab_direction;
++ winview(0);
++ }
++ break;
++ case ButtonPress:
++ ev = &(event.xbutton);
++ if ((m = wintomon(ev->window)) && m != selmon) {
++ unfocus(selmon->sel, 1);
++ selmon = m;
++ focus(NULL);
++ }
++ if ((c = wintoclient(ev->window)))
++ focus(c);
++ XAllowEvents(dpy, AsyncBoth, CurrentTime);
++ break;
++ case ButtonRelease:
++ XUngrabKeyboard(dpy, CurrentTime);
++ XUngrabButton(dpy, AnyButton, AnyModifier, None);
++ grabbed = 0;
++ alt_tab_direction = !alt_tab_direction;
++ winview(0);
++ break;
++ }
++ }
++ return;
++}
++
+ void
+ applyrules(Client *c)
+ {
+@@ -835,6 +914,28 @@ focusmon(const Arg *arg)
+ focus(NULL);
+ }
+
++static void
++focusnext(const Arg *arg) {
++ Monitor *m;
++ Client *c;
++ m = selmon;
++ c = m->sel;
++
++ if (arg->i) {
++ if (c->next)
++ c = c->next;
++ else
++ c = m->clients;
++ } else {
++ Client *last = c;
++ if (last == m->clients)
++ last = NULL;
++ for (c = m->clients; c->next != last; c = c->next);
++ }
++ focus(c);
++ return;
++}
++
+ void
+ focusstack(const Arg *arg)
+ {
+@@ -2092,6 +2193,26 @@ wintomon(Window w)
+ return selmon;
+ }
+
++/* Selects for the view of the focused window. The list of tags */
++/* to be displayed is matched to the focused window tag list. */
++void
++winview(const Arg* arg){
++ Window win, win_r, win_p, *win_c;
++ unsigned nc;
++ int unused;
++ Client* c;
++ Arg a;
++
++ if (!XGetInputFocus(dpy, &win, &unused)) return;
++ while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc)
++ && win_p != win_r) win = win_p;
++
++ if (!(c = wintoclient(win))) return;
++
++ a.ui = c->tags;
++ view(&a);
++}
++
+ /* There's no way to check accesses to destroyed windows, thus those cases are
+ * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
+ * default error handler, which may call exit. */
diff --git a/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff b/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff
new file mode 100644
index 0000000..03ea9ef
--- /dev/null
+++ b/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff
@@ -0,0 +1,12 @@
+diff -up dwm/dwm.c dwmmod/dwm.c
+--- dwm/dwm.c 2020-06-25 00:21:30.383692180 -0300
++++ dwmmod/dwm.c 2020-06-25 00:20:35.643692330 -0300
+@@ -1057,6 +1057,8 @@ manage(Window w, XWindowAttributes *wa)
+ updatewindowtype(c);
+ updatesizehints(c);
+ updatewmhints(c);
++ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
++ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
+ XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ grabbuttons(c, 0);
+ if (!c->isfloating)
diff --git a/dwm/patches/dwm-bar-height-spacing-6.3.diff b/dwm/patches/dwm-bar-height-spacing-6.3.diff
new file mode 100644
index 0000000..cbdeb9a
--- /dev/null
+++ b/dwm/patches/dwm-bar-height-spacing-6.3.diff
@@ -0,0 +1,25 @@
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..9814500 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1; /* border pixel of 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 user_bh = 2; /* 2 is the default spacing around the bar's font */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+ static const char col_gray1[] = "#222222";
+diff --git a/dwm.c b/dwm.c
+index 4465af1..2c27cb3 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1545,7 +1545,7 @@ setup(void)
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+- bh = drw->fonts->h + 2;
++ bh = drw->fonts->h + user_bh;
+ updategeom();
+ /* init atoms */
+ utf8string = XInternAtom(dpy, "UTF8_STRING", False);
diff --git a/dwm/patches/dwm-barpadding-20211020-a786211.diff b/dwm/patches/dwm-barpadding-20211020-a786211.diff
new file mode 100644
index 0000000..19a3150
--- /dev/null
+++ b/dwm/patches/dwm-barpadding-20211020-a786211.diff
@@ -0,0 +1,117 @@
+# From a3cfb215f7f647d83d67e33df8f33a73e43bd65f Mon Sep 17 00:00:00 2001
+# From: Bakkeby <bakkeby@gmail.com>
+# Date: Wed, 20 Oct 2021 09:14:07 +0200
+# Subject: [PATCH] barpadding: adds space between the statusbar and the edge of
+# the screen
+#
+# ---
+# config.def.h | 2 ++
+# dwm.c | 25 +++++++++++++++----------
+# 2 files changed, 17 insertions(+), 10 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..f0b739f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of 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 vertpad = 10; /* vertical padding of bar */
++static const int sidepad = 10; /* horizontal padding of bar */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+ static const char col_gray1[] = "#222222";
+diff --git a/dwm.c b/dwm.c
+index 5e4d494..df6d0d7 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -242,6 +242,8 @@ 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 vp; /* vertical padding for bar */
++static int sp; /* side padding for bar */
+ static int (*xerrorxlib)(Display *, XErrorEvent *);
+ static unsigned int numlockmask = 0;
+ static void (*handler[LASTEvent]) (XEvent *) = {
+@@ -568,7 +570,7 @@ configurenotify(XEvent *e)
+ for (c = m->clients; c; c = c->next)
+ if (c->isfullscreen)
+ resizeclient(c, m->mx, m->my, m->mw, m->mh);
+- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
++ XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
+ }
+ focus(NULL);
+ arrange(NULL);
+@@ -706,7 +708,7 @@ drawbar(Monitor *m)
+ if (m == selmon) { /* status is only drawn on selected monitor */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
++ drw_text(drw, m->ww - tw - 2 * sp, 0, tw, bh, 0, stext, 0);
+ }
+
+ for (c = m->clients; c; c = c->next) {
+@@ -732,12 +734,12 @@ drawbar(Monitor *m)
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
++ drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+- drw_rect(drw, x, 0, w, bh, 1, 1);
++ drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
+ }
+ }
+ drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+@@ -1547,7 +1549,10 @@ setup(void)
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+ bh = drw->fonts->h + 2;
++ sp = sidepad;
++ vp = (topbar == 1) ? vertpad : - vertpad;
+ updategeom();
++
+ /* init atoms */
+ utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+@@ -1704,7 +1709,7 @@ togglebar(const Arg *arg)
+ {
+ selmon->showbar = !selmon->showbar;
+ updatebarpos(selmon);
+- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
+ arrange(selmon);
+ }
+
+@@ -1814,7 +1819,7 @@ updatebars(void)
+ for (m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
+- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
++ m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen),
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+@@ -1829,11 +1834,11 @@ updatebarpos(Monitor *m)
+ m->wy = m->my;
+ m->wh = m->mh;
+ if (m->showbar) {
+- m->wh -= bh;
+- m->by = m->topbar ? m->wy : m->wy + m->wh;
+- m->wy = m->topbar ? m->wy + bh : m->wy;
++ m->wh = m->wh - vertpad - bh;
++ m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
++ m->wy = m->topbar ? m->wy + bh + vp : m->wy;
+ } else
+- m->by = -bh;
++ m->by = -bh - vp;
+ }
+
+ void
+--
+2.33.0
diff --git a/dwm/patches/dwm-bartoggle-keybinds-6.4.diff b/dwm/patches/dwm-bartoggle-keybinds-6.4.diff
new file mode 100644
index 0000000..d06bedf
--- /dev/null
+++ b/dwm/patches/dwm-bartoggle-keybinds-6.4.diff
@@ -0,0 +1,214 @@
+# This patch adds keybinds to toggle each part of the dwm bar. This include the title, tags, layout indicator, status and floating indicator.
+# It also allows you to show/hide parts by default, similar to showbar.
+#
+# There is also a version without keybinds if you don't want keybinds, see the dwm-bartoggle-6.4.diff patch.
+
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2022-10-04 19:38:18.000000000 +0200
++++ b/config.def.h 2022-10-22 14:40:36.113933644 +0200
+@@ -4,6 +4,11 @@
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
+ static const int showbar = 1; /* 0 means no bar */
++static const int showtitle = 1; /* 0 means no title */
++static const int showtags = 1; /* 0 means no tags */
++static const int showlayout = 1; /* 0 means no layout indicator */
++static const int showstatus = 1; /* 0 means no status bar */
++static const int showfloating = 1; /* 0 means no floating indicator */
+ static const int topbar = 1; /* 0 means bottom bar */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+@@ -78,6 +83,11 @@ static const Key keys[] = {
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
++ { MODKEY, XK_t, togglebartitle, {0} },
++ { MODKEY, XK_s, togglebarstatus,{0} },
++ { MODKEY|ShiftMask, XK_t, togglebartags, {0} },
++ { MODKEY|ShiftMask, XK_s, togglebarlt, {0} },
++ { MODKEY|ShiftMask, XK_f, togglebarfloat, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2022-10-04 19:38:18.000000000 +0200
++++ b/dwm.c 2022-10-22 14:41:29.903932288 +0200
+@@ -123,6 +123,11 @@ struct Monitor {
+ unsigned int sellt;
+ unsigned int tagset[2];
+ int showbar;
++ int showtitle;
++ int showtags;
++ int showlayout;
++ int showstatus;
++ int showfloating;
+ int topbar;
+ Client *clients;
+ Client *sel;
+@@ -211,6 +216,11 @@ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
++static void togglebartags(const Arg *arg);
++static void togglebartitle(const Arg *arg);
++static void togglebarlt(const Arg *arg);
++static void togglebarstatus(const Arg *arg);
++static void togglebarfloat(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+@@ -435,16 +445,17 @@ buttonpress(XEvent *e)
+ if (ev->window == selmon->barwin) {
+ i = x = 0;
+ do
+- x += TEXTW(tags[i]);
++ if (selmon->showtags)
++ x += TEXTW(tags[i]);
+ while (ev->x >= x && ++i < LENGTH(tags));
+- if (i < LENGTH(tags)) {
++ if (i < LENGTH(tags) && selmon->showtags) {
+ click = ClkTagBar;
+ arg.ui = 1 << i;
+- } else if (ev->x < x + TEXTW(selmon->ltsymbol))
++ } else if (ev->x < x + TEXTW(selmon->ltsymbol) && selmon->showlayout)
+ click = ClkLtSymbol;
+- else if (ev->x > selmon->ww - (int)TEXTW(stext))
++ else if (ev->x > selmon->ww - (int)TEXTW(stext) && selmon->showstatus)
+ click = ClkStatusText;
+- else
++ else if (selmon->showtitle)
+ click = ClkWinTitle;
+ } else if ((c = wintoclient(ev->window))) {
+ focus(c);
+@@ -641,6 +652,11 @@ createmon(void)
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
++ m->showtitle = showtitle;
++ m->showtags = showtags;
++ m->showlayout = showlayout;
++ m->showstatus = showstatus;
++ m->showfloating = showfloating;
+ m->topbar = topbar;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+@@ -709,7 +725,7 @@ drawbar(Monitor *m)
+ return;
+
+ /* draw status first so it can be overdrawn by tags later */
+- if (m == selmon) { /* status is only drawn on selected monitor */
++ if (m == selmon && selmon->showstatus) { /* status is only drawn on selected monitor */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+@@ -717,29 +733,35 @@ drawbar(Monitor *m)
+
+ for (c = m->clients; c; c = c->next) {
+ occ |= c->tags;
+- if (c->isurgent)
++ if (c->isurgent && selmon->showtags)
+ urg |= c->tags;
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+- w = TEXTW(tags[i]);
+- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+- if (occ & 1 << i)
+- drw_rect(drw, x + boxs, boxs, boxw, boxw,
+- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+- urg & 1 << i);
+- x += w;
+- }
+- w = TEXTW(m->ltsymbol);
+- drw_setscheme(drw, scheme[SchemeNorm]);
+- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
++ if (selmon->showtags) {
++ w = TEXTW(tags[i]);
++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
++ if (occ & 1 << i && selmon->showfloating)
++ drw_rect(drw, x + boxs, boxs, boxw, boxw,
++ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
++ urg & 1 << i);
++ x += w;
++ }
++ }
++
++ /* draw layout indicator if selmon->showlayout */
++ if (selmon->showlayout) {
++ w = TEXTW(m->ltsymbol);
++ drw_setscheme(drw, scheme[SchemeNorm]);
++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
++ }
+
+ if ((w = m->ww - tw - x) > bh) {
+- if (m->sel) {
++ if (m->sel && selmon->showtitle) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+- if (m->sel->isfloating)
++ if (m->sel->isfloating && selmon->showfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+@@ -1238,7 +1260,7 @@ propertynotify(XEvent *e)
+ }
+ if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
+ updatetitle(c);
+- if (c == c->mon->sel)
++ if (c == c->mon->sel && selmon->showtitle)
+ drawbar(c->mon);
+ }
+ if (ev->atom == netatom[NetWMWindowType])
+@@ -1704,6 +1726,41 @@ togglebar(const Arg *arg)
+ }
+
+ void
++togglebartags(const Arg *arg)
++{
++ selmon->showtags = !selmon->showtags;
++ arrange(selmon);
++}
++
++void
++togglebartitle(const Arg *arg)
++{
++ selmon->showtitle = !selmon->showtitle;
++ arrange(selmon);
++}
++
++void
++togglebarlt(const Arg *arg)
++{
++ selmon->showlayout = !selmon->showlayout;
++ arrange(selmon);
++}
++
++void
++togglebarstatus(const Arg *arg)
++{
++ selmon->showstatus = !selmon->showstatus;
++ arrange(selmon);
++}
++
++void
++togglebarfloat(const Arg *arg)
++{
++ selmon->showfloating = !selmon->showfloating;
++ arrange(selmon);
++}
++
++void
+ togglefloating(const Arg *arg)
+ {
+ if (!selmon->sel)
+@@ -1987,7 +2044,7 @@ updatesizehints(Client *c)
+ void
+ updatestatus(void)
+ {
+- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)) && selmon->showstatus)
+ strcpy(stext, "dwm-"VERSION);
+ drawbar(selmon);
+ }
diff --git a/dwm/patches/dwm-borderrule-20231226-e7f651b.diff b/dwm/patches/dwm-borderrule-20231226-e7f651b.diff
new file mode 100644
index 0000000..6426ba5
--- /dev/null
+++ b/dwm/patches/dwm-borderrule-20231226-e7f651b.diff
@@ -0,0 +1,66 @@
+# From e7f651b1321747fb92521522f0aa07a01160d4af Mon Sep 17 00:00:00 2001
+# From: Jasper Shovelton <Beanie.github@proton.me>
+# Date: Tue, 26 Dec 2023 12:57:35 +0000
+# Subject: [PATCH] Add a `borderpx` value to `rules` in `config.def.h`.
+#
+# ---
+# config.def.h | 6 +++---
+# dwm.c | 5 ++++-
+# 2 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..bdddfa5 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -26,9 +26,9 @@ static const Rule rules[] = {
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+- /* class instance title tags mask isfloating monitor */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ /* class instance title tags mask isfloating monitor border width */
++ { "Gimp", NULL, NULL, 0, 1, -1, -1 },
++ { "Firefox", NULL, NULL, 1 << 8, 0, -1, 0 },
+ };
+
+ /* layout(s) */
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..48403c2 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -139,6 +139,7 @@ typedef struct {
+ unsigned int tags;
+ int isfloating;
+ int monitor;
++ int bw;
+ } Rule;
+
+ /* function declarations */
+@@ -287,6 +288,7 @@ applyrules(Client *c)
+ /* rule matching */
+ c->isfloating = 0;
+ c->tags = 0;
++ c->bw = borderpx;
+ XGetClassHint(dpy, c->win, &ch);
+ class = ch.res_class ? ch.res_class : broken;
+ instance = ch.res_name ? ch.res_name : broken;
+@@ -299,6 +301,8 @@ applyrules(Client *c)
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
++ if (r->bw != -1)
++ c->bw = r->bw;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+@@ -1059,7 +1063,6 @@ manage(Window w, XWindowAttributes *wa)
+ c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
+ c->x = MAX(c->x, c->mon->wx);
+ c->y = MAX(c->y, c->mon->wy);
+- c->bw = borderpx;
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+--
+2.43.0
diff --git a/dwm/patches/dwm-bulkill-20231029-9f88553.diff b/dwm/patches/dwm-bulkill-20231029-9f88553.diff
new file mode 100644
index 0000000..d4e6bc9
--- /dev/null
+++ b/dwm/patches/dwm-bulkill-20231029-9f88553.diff
@@ -0,0 +1,85 @@
+# From 70a21457fdbcbcdf26efb1329dd29872b7fcd8e3 Mon Sep 17 00:00:00 2001
+# From: ysl2 <www.songli.yu@gmail.com>
+# Date: Sun, 29 Oct 2023 15:45:05 +0800
+# Subject: [PATCH] Give killclient an augument to control the beheviour: arg.ui
+# == 0 for normal kill current client; arg.ui == 1 for kill other clients in
+# current tag (except current focusing client); arg.ui == 2 for kill all
+# clients in current tag (include focusing client).
+#
+# ---
+# config.def.h | 2 ++
+# dwm.c | 30 ++++++++++++++++++++++++------
+# 2 files changed, 26 insertions(+), 6 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..d39e6dd 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -74,6 +74,8 @@ static const Key keys[] = {
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
++ { MODKEY|ControlMask, XK_c, killclient, {.ui = 1} }, // kill unselect
++ { MODKEY|ShiftMask|ControlMask, XK_c, killclient, {.ui = 2} }, // killall
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..011744d 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -177,6 +177,7 @@ static void grabbuttons(Client *c, int focused);
+ static void grabkeys(void);
+ static void incnmaster(const Arg *arg);
+ static void keypress(XEvent *e);
++static void killthis(Client *c);
+ static void killclient(const Arg *arg);
+ static void manage(Window w, XWindowAttributes *wa);
+ static void mappingnotify(XEvent *e);
+@@ -1013,21 +1014,38 @@ keypress(XEvent *e)
+ }
+
+ void
+-killclient(const Arg *arg)
+-{
+- if (!selmon->sel)
+- return;
+- if (!sendevent(selmon->sel, wmatom[WMDelete])) {
++killthis(Client *c) {
++ if (!sendevent(c, wmatom[WMDelete])) {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+- XKillClient(dpy, selmon->sel->win);
++ XKillClient(dpy, c->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+ }
+
++void
++killclient(const Arg *arg)
++{
++ Client *c;
++
++ if (!selmon->sel)
++ return;
++
++ if (!arg->ui || arg->ui == 0) {
++ killthis(selmon->sel);
++ return;
++ }
++
++ for (c = selmon->clients; c; c = c->next) {
++ if (!ISVISIBLE(c) || (arg->ui == 1 && c == selmon->sel))
++ continue;
++ killthis(c);
++ }
++}
++
+ void
+ manage(Window w, XWindowAttributes *wa)
+ {
+--
+2.20.1
diff --git a/dwm/patches/dwm-canfocusfloating-20210724-b914109.diff b/dwm/patches/dwm-canfocusfloating-20210724-b914109.diff
new file mode 100644
index 0000000..851e4ed
--- /dev/null
+++ b/dwm/patches/dwm-canfocusfloating-20210724-b914109.diff
@@ -0,0 +1,144 @@
+# From b9141091994ba657af534453ab913663a8258f9a Mon Sep 17 00:00:00 2001
+# From: oxinosg <georgios.oxinos.extern@elinvar.de>
+# Date: Sat, 24 Jul 2021 23:31:30 +0200
+# Subject: [PATCH] [dwm][cantogglefloating] patch that allows disabling focus on
+# floating clients
+#
+# ---
+# config.def.h | 1 +
+# dwm.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----
+# 2 files changed, 63 insertions(+), 5 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..005fb5d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -70,6 +70,7 @@ static Key keys[] = {
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
++ { MODKEY, XK_s, togglecanfocusfloating, {0} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..ae0a0ea 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -92,7 +92,7 @@ struct Client {
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh;
+ int bw, oldbw;
+ unsigned int tags;
+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, cantfocus;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -191,6 +191,7 @@ static Monitor *recttomon(int x, int y, int w, int h);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
+ static void resizeclient(Client *c, int x, int y, int w, int h);
+ static void resizemouse(const Arg *arg);
++static void resetcanfocusfloating();
+ static void restack(Monitor *m);
+ static void run(void);
+ static void scan(void);
+@@ -211,6 +212,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglecanfocusfloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -788,6 +790,8 @@ focus(Client *c)
+ if (selmon->sel && selmon->sel != c)
+ unfocus(selmon->sel, 0);
+ if (c) {
++ if (c->cantfocus)
++ return;
+ if (c->mon != selmon)
+ selmon = c->mon;
+ if (c->isurgent)
+@@ -837,16 +841,16 @@ focusstack(const Arg *arg)
+ if (!selmon->sel)
+ return;
+ if (arg->i > 0) {
+- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
++ for (c = selmon->sel->next; c && (!ISVISIBLE(c) || c->cantfocus); c = c->next);
+ if (!c)
+- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
++ for (c = selmon->clients; c && (!ISVISIBLE(c) || c->cantfocus); c = c->next);
+ } else {
+ for (i = selmon->clients; i != selmon->sel; i = i->next)
+- if (ISVISIBLE(i))
++ if (ISVISIBLE(i) && !i->cantfocus)
+ c = i;
+ if (!c)
+ for (; i; i = i->next)
+- if (ISVISIBLE(i))
++ if (ISVISIBLE(i) && !i->cantfocus)
+ c = i;
+ }
+ if (c) {
+@@ -1716,6 +1720,59 @@ togglefloating(const Arg *arg)
+ if (selmon->sel->isfloating)
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, 0);
++
++ resetcanfocusfloating();
++
++ arrange(selmon);
++}
++
++void
++resetcanfocusfloating()
++{
++ unsigned int i, n;
++ Client *c;
++
++ for (n = 0, c = selmon->clients; c; c = c->next, n++);
++ if (n == 0)
++ return;
++
++ for (i = 0, c = selmon->clients; c; c = c->next, i++)
++ if (c->isfloating)
++ c->cantfocus = 0;
++
++ arrange(selmon);
++}
++
++void
++togglecanfocusfloating(const Arg *arg)
++{
++ unsigned int n;
++ Client *c, *cf = NULL;
++
++ if (!selmon->sel)
++ return;
++
++ for (c = selmon->clients; c; c = c->next)
++ if (c->cantfocus == 1) {
++ cf = c;
++ }
++
++ if (cf) {
++ resetcanfocusfloating();
++ focus(cf);
++ } else {
++ for (n = 0, c = selmon->clients; c; c = c->next)
++ if (c->isfloating)
++ c->cantfocus = !c->cantfocus;
++ else
++ n++;
++
++ if (n && selmon->sel->isfloating) {
++ c = nexttiled(selmon->clients);
++ focus(c);
++ }
++ }
++
+ arrange(selmon);
+ }
+
+--
+2.27.0
diff --git a/dwm/patches/dwm-cfacts-vanitygaps-6.4_combo.diff b/dwm/patches/dwm-cfacts-vanitygaps-6.4_combo.diff
new file mode 100644
index 0000000..371fce0
--- /dev/null
+++ b/dwm/patches/dwm-cfacts-vanitygaps-6.4_combo.diff
@@ -0,0 +1,1018 @@
+diff --git a/config.def.h b/config.def.h
+index 9efa774..357dc6f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -3,6 +3,11 @@
+ /* appearance */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
++static const unsigned int gappih = 20; /* horiz inner gap between windows */
++static const unsigned int gappiv = 10; /* vert inner gap between windows */
++static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
++static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */
++static int smartgaps = 0; /* 1 means no outer gap when there is only one window */
+ static const int showbar = 1; /* 0 means no bar */
+ static const int topbar = 1; /* 0 means bottom bar */
+ static const char *fonts[] = { "monospace:size=10" };
+@@ -37,11 +42,26 @@ 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 */
+
++#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
++#include "vanitygaps.c"
++
+ static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile }, /* first entry is default */
+- { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
++ { "[@]", spiral },
++ { "[\\]", dwindle },
++ { "H[]", deck },
++ { "TTT", bstack },
++ { "===", bstackhoriz },
++ { "HHH", grid },
++ { "###", nrowgrid },
++ { "---", horizgrid },
++ { ":::", gaplessgrid },
++ { "|M|", centeredmaster },
++ { ">M>", centeredfloatingmaster },
++ { "><>", NULL }, /* no layout function means floating behavior */
++ { NULL, NULL },
+ };
+
+ /* key definitions */
+@@ -71,7 +91,26 @@ static const Key keys[] = {
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} },
++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} },
++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} },
+ { MODKEY, XK_Return, zoom, {0} },
++ { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
++ { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..5bbd733 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -87,6 +87,7 @@ typedef struct Client Client;
+ struct Client {
+ char name[256];
+ float mina, maxa;
++ float cfact;
+ int x, y, w, h;
+ int oldx, oldy, oldw, oldh;
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+@@ -119,6 +120,10 @@ struct Monitor {
+ int by; /* bar geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
++ int gappih; /* horizontal gap between windows */
++ int gappiv; /* vertical gap between windows */
++ int gappoh; /* horizontal outer gaps */
++ int gappov; /* vertical outer gaps */
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+@@ -201,6 +206,7 @@ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
+ static void setlayout(const Arg *arg);
++static void setcfact(const Arg *arg);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+ static void seturgent(Client *c, int urg);
+@@ -208,7 +214,6 @@ static void showhide(Client *c);
+ static void spawn(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+-static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+@@ -641,6 +646,10 @@ createmon(void)
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
++ m->gappih = gappih;
++ m->gappiv = gappiv;
++ m->gappoh = gappoh;
++ m->gappov = gappov;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+@@ -1043,6 +1052,7 @@ manage(Window w, XWindowAttributes *wa)
+ c->w = c->oldw = wa->width;
+ c->h = c->oldh = wa->height;
+ c->oldbw = wa->border_width;
++ c->cfact = 1.0;
+
+ updatetitle(c);
+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+@@ -1521,6 +1531,24 @@ setlayout(const Arg *arg)
+ drawbar(selmon);
+ }
+
++void
++setcfact(const Arg *arg) {
++ float f;
++ Client *c;
++
++ c = selmon->sel;
++
++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
++ return;
++ f = arg->f + c->cfact;
++ if(arg->f == 0.0)
++ f = 1.0;
++ else if(f < 0.25 || f > 4.0)
++ return;
++ c->cfact = f;
++ arrange(selmon);
++}
++
+ /* arg > 1.0 will set mfact absolutely */
+ void
+ setmfact(const Arg *arg)
+@@ -1684,34 +1712,6 @@ tagmon(const Arg *arg)
+ sendmon(selmon->sel, dirtomon(arg->i));
+ }
+
+-void
+-tile(Monitor *m)
+-{
+- unsigned int i, n, h, mw, my, ty;
+- Client *c;
+-
+- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+- if (n == 0)
+- return;
+-
+- if (n > m->nmaster)
+- mw = m->nmaster ? m->ww * m->mfact : 0;
+- else
+- mw = m->ww;
+- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+- if (i < m->nmaster) {
+- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
+- if (my + HEIGHT(c) < m->wh)
+- my += HEIGHT(c);
+- } else {
+- h = (m->wh - ty) / (n - i);
+- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
+- if (ty + HEIGHT(c) < m->wh)
+- ty += HEIGHT(c);
+- }
+-}
+-
+ void
+ togglebar(const Arg *arg)
+ {
+diff --git a/vanitygaps.c b/vanitygaps.c
+new file mode 100644
+index 0000000..1a816b6
+--- /dev/null
++++ b/vanitygaps.c
+@@ -0,0 +1,822 @@
++/* Key binding functions */
++static void defaultgaps(const Arg *arg);
++static void incrgaps(const Arg *arg);
++static void incrigaps(const Arg *arg);
++static void incrogaps(const Arg *arg);
++static void incrohgaps(const Arg *arg);
++static void incrovgaps(const Arg *arg);
++static void incrihgaps(const Arg *arg);
++static void incrivgaps(const Arg *arg);
++static void togglegaps(const Arg *arg);
++/* Layouts (delete the ones you do not need) */
++static void bstack(Monitor *m);
++static void bstackhoriz(Monitor *m);
++static void centeredmaster(Monitor *m);
++static void centeredfloatingmaster(Monitor *m);
++static void deck(Monitor *m);
++static void dwindle(Monitor *m);
++static void fibonacci(Monitor *m, int s);
++static void grid(Monitor *m);
++static void nrowgrid(Monitor *m);
++static void spiral(Monitor *m);
++static void tile(Monitor *m);
++/* Internals */
++static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
++static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr);
++static void setgaps(int oh, int ov, int ih, int iv);
++
++/* Settings */
++#if !PERTAG_PATCH
++static int enablegaps = 1;
++#endif // PERTAG_PATCH
++
++void
++setgaps(int oh, int ov, int ih, int iv)
++{
++ if (oh < 0) oh = 0;
++ if (ov < 0) ov = 0;
++ if (ih < 0) ih = 0;
++ if (iv < 0) iv = 0;
++
++ selmon->gappoh = oh;
++ selmon->gappov = ov;
++ selmon->gappih = ih;
++ selmon->gappiv = iv;
++ arrange(selmon);
++}
++
++void
++togglegaps(const Arg *arg)
++{
++ #if PERTAG_PATCH
++ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag];
++ #else
++ enablegaps = !enablegaps;
++ #endif // PERTAG_PATCH
++ arrange(NULL);
++}
++
++void
++defaultgaps(const Arg *arg)
++{
++ setgaps(gappoh, gappov, gappih, gappiv);
++}
++
++void
++incrgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov + arg->i,
++ selmon->gappih + arg->i,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
++incrigaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih + arg->i,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
++incrogaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov + arg->i,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrohgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrovgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov + arg->i,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrihgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih + arg->i,
++ selmon->gappiv
++ );
++}
++
++void
++incrivgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
++getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
++{
++ unsigned int n, oe, ie;
++ #if PERTAG_PATCH
++ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag];
++ #else
++ oe = ie = enablegaps;
++ #endif // PERTAG_PATCH
++ Client *c;
++
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
++ if (smartgaps && n == 1) {
++ oe = 0; // outer gaps disabled when only one client
++ }
++
++ *oh = m->gappoh*oe; // outer horizontal gap
++ *ov = m->gappov*oe; // outer vertical gap
++ *ih = m->gappih*ie; // inner horizontal gap
++ *iv = m->gappiv*ie; // inner vertical gap
++ *nc = n; // number of clients
++}
++
++void
++getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
++{
++ unsigned int n;
++ float mfacts = 0, sfacts = 0;
++ int mtotal = 0, stotal = 0;
++ Client *c;
++
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
++ if (n < m->nmaster)
++ mfacts += c->cfact;
++ else
++ sfacts += c->cfact;
++
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
++ if (n < m->nmaster)
++ mtotal += msize * (c->cfact / mfacts);
++ else
++ stotal += ssize * (c->cfact / sfacts);
++
++ *mf = mfacts; // total factor of master area
++ *sf = sfacts; // total factor of stack area
++ *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split
++ *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split
++}
++
++/***
++ * Layouts
++ */
++
++/*
++ * Bottomstack layout + gaps
++ * https://dwm.suckless.org/patches/bottomstack/
++ */
++static void
++bstack(Monitor *m)
++{
++ unsigned int i, n;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ float mfacts, sfacts;
++ int mrest, srest;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ sh = mh = m->wh - 2*oh;
++ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
++ sw = m->ww - 2*ov - iv * (n - m->nmaster - 1);
++
++ if (m->nmaster && n > m->nmaster) {
++ sh = (mh - ih) * (1 - m->mfact);
++ mh = mh - ih - sh;
++ sx = mx;
++ sy = my + mh + ih;
++ }
++
++ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
++ if (i < m->nmaster) {
++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
++ mx += WIDTH(c) + iv;
++ } else {
++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
++ sx += WIDTH(c) + iv;
++ }
++ }
++}
++
++static void
++bstackhoriz(Monitor *m)
++{
++ unsigned int i, n;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ float mfacts, sfacts;
++ int mrest, srest;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ mh = m->wh - 2*oh;
++ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
++ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
++ sw = m->ww - 2*ov;
++
++ if (m->nmaster && n > m->nmaster) {
++ sh = (mh - ih) * (1 - m->mfact);
++ mh = mh - ih - sh;
++ sy = my + mh + ih;
++ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster);
++ }
++
++ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
++ if (i < m->nmaster) {
++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
++ mx += WIDTH(c) + iv;
++ } else {
++ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
++ sy += HEIGHT(c) + ih;
++ }
++ }
++}
++
++/*
++ * Centred master layout + gaps
++ * https://dwm.suckless.org/patches/centeredmaster/
++ */
++void
++centeredmaster(Monitor *m)
++{
++ unsigned int i, n;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int lx = 0, ly = 0, lw = 0, lh = 0;
++ int rx = 0, ry = 0, rw = 0, rh = 0;
++ float mfacts = 0, lfacts = 0, rfacts = 0;
++ int mtotal = 0, ltotal = 0, rtotal = 0;
++ int mrest = 0, lrest = 0, rrest = 0;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ /* initialize areas */
++ mx = m->wx + ov;
++ my = m->wy + oh;
++ mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
++ mw = m->ww - 2*ov;
++ lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1);
++ rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
++
++ if (m->nmaster && n > m->nmaster) {
++ /* go mfact box in the center if more than nmaster clients */
++ if (n - m->nmaster > 1) {
++ /* ||<-S->|<---M--->|<-S->|| */
++ mw = (m->ww - 2*ov - 2*iv) * m->mfact;
++ lw = (m->ww - mw - 2*ov - 2*iv) / 2;
++ rw = (m->ww - mw - 2*ov - 2*iv) - lw;
++ mx += lw + iv;
++ } else {
++ /* ||<---M--->|<-S->|| */
++ mw = (mw - iv) * m->mfact;
++ lw = 0;
++ rw = m->ww - mw - iv - 2*ov;
++ }
++ lx = m->wx + ov;
++ ly = m->wy + oh;
++ rx = mx + mw + iv;
++ ry = m->wy + oh;
++ }
++
++ /* calculate facts */
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
++ if (!m->nmaster || n < m->nmaster)
++ mfacts += c->cfact;
++ else if ((n - m->nmaster) % 2)
++ lfacts += c->cfact; // total factor of left hand stack area
++ else
++ rfacts += c->cfact; // total factor of right hand stack area
++ }
++
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
++ if (!m->nmaster || n < m->nmaster)
++ mtotal += mh * (c->cfact / mfacts);
++ else if ((n - m->nmaster) % 2)
++ ltotal += lh * (c->cfact / lfacts);
++ else
++ rtotal += rh * (c->cfact / rfacts);
++
++ mrest = mh - mtotal;
++ lrest = lh - ltotal;
++ rrest = rh - rtotal;
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
++ if (!m->nmaster || i < m->nmaster) {
++ /* nmaster clients are stacked vertically, in the center of the screen */
++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
++ my += HEIGHT(c) + ih;
++ } else {
++ /* stack clients are stacked vertically */
++ if ((i - m->nmaster) % 2 ) {
++ resize(c, lx, ly, lw - (2*c->bw), lh * (c->cfact / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
++ ly += HEIGHT(c) + ih;
++ } else {
++ resize(c, rx, ry, rw - (2*c->bw), rh * (c->cfact / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
++ ry += HEIGHT(c) + ih;
++ }
++ }
++ }
++}
++
++void
++centeredfloatingmaster(Monitor *m)
++{
++ unsigned int i, n;
++ float mfacts, sfacts;
++ float mivf = 1.0; // master inner vertical gap factor
++ int oh, ov, ih, iv, mrest, srest;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ sh = mh = m->wh - 2*oh;
++ mw = m->ww - 2*ov - iv*(n - 1);
++ sw = m->ww - 2*ov - iv*(n - m->nmaster - 1);
++
++ if (m->nmaster && n > m->nmaster) {
++ mivf = 0.8;
++ /* go mfact box in the center if more than nmaster clients */
++ if (m->ww > m->wh) {
++ mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1);
++ mh = m->wh * 0.9;
++ } else {
++ mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1);
++ mh = m->wh * m->mfact;
++ }
++ mx = m->wx + (m->ww - mw) / 2;
++ my = m->wy + (m->wh - mh - 2*oh) / 2;
++
++ sx = m->wx + ov;
++ sy = m->wy + oh;
++ sh = m->wh - 2*oh;
++ }
++
++ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < m->nmaster) {
++ /* nmaster clients are stacked horizontally, in the center of the screen */
++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
++ mx += WIDTH(c) + iv*mivf;
++ } else {
++ /* stack clients are stacked horizontally */
++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
++ sx += WIDTH(c) + iv;
++ }
++}
++
++/*
++ * Deck layout + gaps
++ * https://dwm.suckless.org/patches/deck/
++ */
++void
++deck(Monitor *m)
++{
++ unsigned int i, n;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ float mfacts, sfacts;
++ int mrest, srest;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
++ sw = mw = m->ww - 2*ov;
++
++ if (m->nmaster && n > m->nmaster) {
++ sw = (mw - iv) * (1 - m->mfact);
++ mw = mw - iv - sw;
++ sx = mx + mw + iv;
++ sh = m->wh - 2*oh;
++ }
++
++ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
++
++ if (n - m->nmaster > 0) /* override layout symbol */
++ snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < m->nmaster) {
++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
++ my += HEIGHT(c) + ih;
++ } else {
++ resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
++ }
++}
++
++/*
++ * Fibonacci layout + gaps
++ * https://dwm.suckless.org/patches/fibonacci/
++ */
++void
++fibonacci(Monitor *m, int s)
++{
++ unsigned int i, n;
++ int nx, ny, nw, nh;
++ int oh, ov, ih, iv;
++ int nv, hrest = 0, wrest = 0, r = 1;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ nx = m->wx + ov;
++ ny = m->wy + oh;
++ nw = m->ww - 2*ov;
++ nh = m->wh - 2*oh;
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
++ if (r) {
++ if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw))
++ || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) {
++ r = 0;
++ }
++ if (r && i < n - 1) {
++ if (i % 2) {
++ nv = (nh - ih) / 2;
++ hrest = nh - 2*nv - ih;
++ nh = nv;
++ } else {
++ nv = (nw - iv) / 2;
++ wrest = nw - 2*nv - iv;
++ nw = nv;
++ }
++
++ if ((i % 4) == 2 && !s)
++ nx += nw + iv;
++ else if ((i % 4) == 3 && !s)
++ ny += nh + ih;
++ }
++
++ if ((i % 4) == 0) {
++ if (s) {
++ ny += nh + ih;
++ nh += hrest;
++ }
++ else {
++ nh -= hrest;
++ ny -= nh + ih;
++ }
++ }
++ else if ((i % 4) == 1) {
++ nx += nw + iv;
++ nw += wrest;
++ }
++ else if ((i % 4) == 2) {
++ ny += nh + ih;
++ nh += hrest;
++ if (i < n - 1)
++ nw += wrest;
++ }
++ else if ((i % 4) == 3) {
++ if (s) {
++ nx += nw + iv;
++ nw -= wrest;
++ } else {
++ nw -= wrest;
++ nx -= nw + iv;
++ nh += hrest;
++ }
++ }
++ if (i == 0) {
++ if (n != 1) {
++ nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact);
++ wrest = 0;
++ }
++ ny = m->wy + oh;
++ }
++ else if (i == 1)
++ nw = m->ww - nw - iv - 2*ov;
++ i++;
++ }
++
++ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
++ }
++}
++
++void
++dwindle(Monitor *m)
++{
++ fibonacci(m, 1);
++}
++
++void
++spiral(Monitor *m)
++{
++ fibonacci(m, 0);
++}
++
++/*
++ * Gappless grid layout + gaps (ironically)
++ * https://dwm.suckless.org/patches/gaplessgrid/
++ */
++void
++gaplessgrid(Monitor *m)
++{
++ unsigned int i, n;
++ int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
++ int oh, ov, ih, iv;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ /* grid dimensions */
++ for (cols = 0; cols <= n/2; cols++)
++ if (cols*cols >= n)
++ break;
++ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
++ cols = 2;
++ rows = n/cols;
++ cn = rn = 0; // reset column no, row no, client count
++
++ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
++ cw = (m->ww - 2*ov - iv * (cols - 1)) / cols;
++ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
++ crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
++ x = m->wx + ov;
++ y = m->wy + oh;
++
++ for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
++ if (i/rows + 1 > cols - n%cols) {
++ rows = n/cols + 1;
++ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
++ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
++ }
++ resize(c,
++ x,
++ y + rn*(ch + ih) + MIN(rn, rrest),
++ cw + (cn < crest ? 1 : 0) - 2*c->bw,
++ ch + (rn < rrest ? 1 : 0) - 2*c->bw,
++ 0);
++ rn++;
++ if (rn >= rows) {
++ rn = 0;
++ x += cw + ih + (cn < crest ? 1 : 0);
++ cn++;
++ }
++ }
++}
++
++/*
++ * Gridmode layout + gaps
++ * https://dwm.suckless.org/patches/gridmode/
++ */
++void
++grid(Monitor *m)
++{
++ unsigned int i, n;
++ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
++ int oh, ov, ih, iv;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++
++ /* grid dimensions */
++ for (rows = 0; rows <= n/2; rows++)
++ if (rows*rows >= n)
++ break;
++ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
++
++ /* window geoms (cell height/width) */
++ ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1);
++ cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1);
++ chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
++ cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
++ cc = i / rows;
++ cr = i % rows;
++ cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest);
++ cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest);
++ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
++ }
++}
++
++/*
++ * Horizontal grid layout + gaps
++ * https://dwm.suckless.org/patches/horizgrid/
++ */
++void
++horizgrid(Monitor *m) {
++ Client *c;
++ unsigned int n, i;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ int ntop, nbottom = 1;
++ float mfacts = 0, sfacts = 0;
++ int mrest, srest, mtotal = 0, stotal = 0;
++
++ /* Count windows */
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ if (n <= 2)
++ ntop = n;
++ else {
++ ntop = n / 2;
++ nbottom = n - ntop;
++ }
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ sh = mh = m->wh - 2*oh;
++ sw = mw = m->ww - 2*ov;
++
++ if (n > ntop) {
++ sh = (mh - ih) / 2;
++ mh = mh - ih - sh;
++ sy = my + mh + ih;
++ mw = m->ww - 2*ov - iv * (ntop - 1);
++ sw = m->ww - 2*ov - iv * (nbottom - 1);
++ }
++
++ /* calculate facts */
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < ntop)
++ mfacts += c->cfact;
++ else
++ sfacts += c->cfact;
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < ntop)
++ mtotal += mh * (c->cfact / mfacts);
++ else
++ stotal += sw * (c->cfact / sfacts);
++
++ mrest = mh - mtotal;
++ srest = sw - stotal;
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < ntop) {
++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
++ mx += WIDTH(c) + iv;
++ } else {
++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
++ sx += WIDTH(c) + iv;
++ }
++}
++
++/*
++ * nrowgrid layout + gaps
++ * https://dwm.suckless.org/patches/nrowgrid/
++ */
++void
++nrowgrid(Monitor *m)
++{
++ unsigned int n;
++ int ri = 0, ci = 0; /* counters */
++ int oh, ov, ih, iv; /* vanitygap settings */
++ unsigned int cx, cy, cw, ch; /* client geometry */
++ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
++ unsigned int cols, rows = m->nmaster + 1;
++ Client *c;
++
++ /* count clients */
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++
++ /* nothing to do here */
++ if (n == 0)
++ return;
++
++ /* force 2 clients to always split vertically */
++ if (FORCE_VSPLIT && n == 2)
++ rows = 1;
++
++ /* never allow empty rows */
++ if (n < rows)
++ rows = n;
++
++ /* define first row */
++ cols = n / rows;
++ uc = cols;
++ cy = m->wy + oh;
++ ch = (m->wh - 2*oh - ih*(rows - 1)) / rows;
++ uh = ch;
++
++ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) {
++ if (ci == cols) {
++ uw = 0;
++ ci = 0;
++ ri++;
++
++ /* next row */
++ cols = (n - uc) / (rows - ri);
++ uc += cols;
++ cy = m->wy + oh + uh + ih;
++ uh += ch + ih;
++ }
++
++ cx = m->wx + ov + uw;
++ cw = (m->ww - 2*ov - uw) / (cols - ci);
++ uw += cw + iv;
++
++ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0);
++ }
++}
++
++/*
++ * Default tile layout + gaps
++ */
++static void
++tile(Monitor *m)
++{
++ unsigned int i, n;
++ int oh, ov, ih, iv;
++ int mx = 0, my = 0, mh = 0, mw = 0;
++ int sx = 0, sy = 0, sh = 0, sw = 0;
++ float mfacts, sfacts;
++ int mrest, srest;
++ Client *c;
++
++ getgaps(m, &oh, &ov, &ih, &iv, &n);
++ if (n == 0)
++ return;
++
++ sx = mx = m->wx + ov;
++ sy = my = m->wy + oh;
++ mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
++ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
++ sw = mw = m->ww - 2*ov;
++
++ if (m->nmaster && n > m->nmaster) {
++ sw = (mw - iv) * (1 - m->mfact);
++ mw = mw - iv - sw;
++ sx = mx + mw + iv;
++ }
++
++ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
++
++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ if (i < m->nmaster) {
++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
++ my += HEIGHT(c) + ih;
++ } else {
++ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
++ sy += HEIGHT(c) + ih;
++ }
++}
+\ No newline at end of file
diff --git a/dwm/patches/dwm-clientopacity-6.4.diff b/dwm/patches/dwm-clientopacity-6.4.diff
new file mode 100644
index 0000000..4564e08
--- /dev/null
+++ b/dwm/patches/dwm-clientopacity-6.4.diff
@@ -0,0 +1,274 @@
+# From 10dd5df95f551d81d0a814dcdb2bde20e405fb91 Mon Sep 17 00:00:00 2001
+# From: sympodius <mail@sympodius.net>
+# Date: Mon, 13 Mar 2023 16:28:16 +0000
+# Subject: [PATCH] [dwm][patch][clientopacity] Adds opacity on a per client
+# basis
+#
+# ---
+# config.def.h | 80 ++++++++++++++++++++++++++++------------------------
+# dwm.c | 61 ++++++++++++++++++++++++++++++++++++++-
+# 2 files changed, 103 insertions(+), 38 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..9ca812d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of 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 double activeopacity = 0.9f; /* Window opacity when it's focused (0 <= opacity <= 1) */
++static const double inactiveopacity = 0.7f; /* Window opacity when it's inactive (0 <= opacity <= 1) */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+ static const char col_gray1[] = "#222222";
+@@ -26,9 +28,9 @@ static const Rule rules[] = {
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+- /* class instance title tags mask isfloating monitor */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ /* class instance title tags mask isfloating focusopacity unfocusopacity monitor */
++ { "Gimp", NULL, NULL, 0, 1, 1.0, inactiveopacity, -1 },
++ { "Firefox", NULL, NULL, 1 << 8, 0, activeopacity, inactiveopacity, -1 },
+ };
+
+ /* layout(s) */
+@@ -61,40 +63,44 @@ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont,
+ static const char *termcmd[] = { "st", NULL };
+
+ static const Key keys[] = {
+- /* modifier key function argument */
+- { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+- { MODKEY, XK_b, togglebar, {0} },
+- { MODKEY, XK_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, XK_Return, zoom, {0} },
+- { MODKEY, XK_Tab, view, {0} },
+- { MODKEY|ShiftMask, XK_c, killclient, {0} },
+- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+- { MODKEY, XK_space, setlayout, {0} },
+- { MODKEY|ShiftMask, XK_space, togglefloating, {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 } },
+- 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|ShiftMask, XK_q, quit, {0} },
++ /* modifier key function argument */
++ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
++ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
++ { 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, XK_Return, zoom, {0} },
++ { MODKEY, XK_Tab, view, {0} },
++ { MODKEY|ShiftMask, XK_c, killclient, {0} },
++ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
++ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
++ { MODKEY, XK_space, setlayout, {0} },
++ { MODKEY|ShiftMask, XK_space, togglefloating, {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|ShiftMask, XK_a, changefocusopacity, {.f = +0.025}},
++ { MODKEY|ShiftMask, XK_s, changefocusopacity, {.f = -0.025}},
++ { MODKEY|ShiftMask, XK_z, changeunfocusopacity, {.f = +0.025}},
++ { MODKEY|ShiftMask, XK_x, changeunfocusopacity, {.f = -0.025}},
++ 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|ShiftMask, XK_q, quit, {0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index c2bd871..71cf33c 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -62,7 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++ NetWMWindowTypeDialog, NetClientList, NetWMWindowsOpacity, NetLast }; /* EWMH atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+@@ -95,6 +95,8 @@ struct Client {
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ Client *next;
+ Client *snext;
++ double opacity;
++ double unfocusopacity;
+ Monitor *mon;
+ Window win;
+ };
+@@ -138,6 +140,8 @@ typedef struct {
+ const char *title;
+ unsigned int tags;
+ int isfloating;
++ double opacity;
++ double unfocusopacity;
+ int monitor;
+ } Rule;
+
+@@ -149,6 +153,8 @@ static void arrangemon(Monitor *m);
+ static void attach(Client *c);
+ static void attachstack(Client *c);
+ static void buttonpress(XEvent *e);
++static void changefocusopacity(const Arg *arg);
++static void changeunfocusopacity(const Arg *arg);
+ static void checkotherwm(void);
+ static void cleanup(void);
+ static void cleanupmon(Monitor *mon);
+@@ -185,6 +191,7 @@ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
+ static Client *nexttiled(Client *c);
++static void opacity(Client *c, double opacity);
+ static void pop(Client *c);
+ static void propertynotify(XEvent *e);
+ static void quit(const Arg *arg);
+@@ -287,6 +294,8 @@ applyrules(Client *c)
+ /* rule matching */
+ c->isfloating = 0;
+ c->tags = 0;
++ c->opacity = activeopacity;
++ c->unfocusopacity = inactiveopacity;
+ XGetClassHint(dpy, c->win, &ch);
+ class = ch.res_class ? ch.res_class : broken;
+ instance = ch.res_name ? ch.res_name : broken;
+@@ -299,6 +308,8 @@ applyrules(Client *c)
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
++ c->opacity = r->opacity;
++ c->unfocusopacity = r->unfocusopacity;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+@@ -457,6 +468,36 @@ buttonpress(XEvent *e)
+ buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+ }
+
++void
++changefocusopacity(const Arg *arg)
++{
++ if (!selmon->sel)
++ return;
++ selmon->sel->opacity+=arg->f;
++ if(selmon->sel->opacity > 1.0)
++ selmon->sel->opacity = 1.0;
++
++ if(selmon->sel->opacity < 0.1)
++ selmon->sel->opacity = 0.1;
++
++ opacity(selmon->sel, selmon->sel->opacity);
++}
++
++void
++changeunfocusopacity(const Arg *arg)
++{
++ if (!selmon->sel)
++ return;
++ selmon->sel->unfocusopacity+=arg->f;
++ if(selmon->sel->unfocusopacity > 1.0)
++ selmon->sel->unfocusopacity = 1.0;
++
++ if(selmon->sel->unfocusopacity < 0.1)
++ selmon->sel->unfocusopacity = 0.1;
++
++ opacity(selmon->sel, selmon->sel->unfocusopacity);
++}
++
+ void
+ checkotherwm(void)
+ {
+@@ -803,6 +844,8 @@ focus(Client *c)
+ grabbuttons(c, 1);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ setfocus(c);
++ c->opacity = MIN(1.0, MAX(0, c->opacity));
++ opacity(c, c->opacity);
+ } else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+@@ -1052,6 +1095,7 @@ manage(Window w, XWindowAttributes *wa)
+ c->mon = selmon;
+ applyrules(c);
+ }
++ opacity(c, c->opacity);
+
+ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+ c->x = c->mon->wx + c->mon->ww - WIDTH(c);
+@@ -1209,6 +1253,18 @@ nexttiled(Client *c)
+ return c;
+ }
+
++void
++opacity(Client *c, double opacity)
++{
++ if(opacity > 0 && opacity < 1) {
++ unsigned long real_opacity[] = { opacity * 0xffffffff };
++ XChangeProperty(dpy, c->win, netatom[NetWMWindowsOpacity], XA_CARDINAL,
++ 32, PropModeReplace, (unsigned char *)real_opacity,
++ 1);
++ } else
++ XDeleteProperty(dpy, c->win, netatom[NetWMWindowsOpacity]);
++}
++
+ void
+ pop(Client *c)
+ {
+@@ -1579,6 +1635,7 @@ setup(void)
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
++ netatom[NetWMWindowsOpacity] = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
+ /* init cursors */
+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+@@ -1760,6 +1817,8 @@ unfocus(Client *c, int setfocus)
+ if (!c)
+ return;
+ grabbuttons(c, 0);
++ c->unfocusopacity = MIN(1.0, MAX(0, c->unfocusopacity));
++ opacity(c, c->unfocusopacity);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+--
+2.39.2
diff --git a/dwm/patches/dwm-clientresizehints-6.5.diff b/dwm/patches/dwm-clientresizehints-6.5.diff
new file mode 100644
index 0000000..8c35e8b
--- /dev/null
+++ b/dwm/patches/dwm-clientresizehints-6.5.diff
@@ -0,0 +1,75 @@
+# From b2de13e11e7b4d67b4982ef51befa87ed9202080 Mon Sep 17 00:00:00 2001
+# From: Fred Frey <fred@fpf3.net>
+# Date: Sun, 22 Sep 2024 16:09:53 -0400
+# Subject: [PATCH] implement per-client resizehints
+#
+# ---
+# config.def.h | 6 +++---
+# dwm.c | 7 +++++--
+# 2 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..67e7a9c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -26,9 +26,9 @@ static const Rule rules[] = {
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+- /* class instance title tags mask isfloating monitor */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ /* class instance title tags mask isfloating monitor resizehints */
++ { "Gimp", NULL, NULL, 0, 1, -1, 1},
++ { "Firefox", NULL, NULL, 1 << 8, 0, -1, 1},
+ };
+
+ /* layout(s) */
+diff --git a/dwm.c b/dwm.c
+index 67c6b2b..f179b4c 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -92,7 +92,7 @@ struct Client {
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+ int bw, oldbw;
+ unsigned int tags;
+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, resizehints;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -139,6 +139,7 @@ typedef struct {
+ unsigned int tags;
+ int isfloating;
+ int monitor;
++ int resizehints;
+ } Rule;
+
+ /* function declarations */
+@@ -299,6 +300,7 @@ applyrules(Client *c)
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
++ c->resizehints = r->resizehints;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+@@ -343,7 +345,7 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
+ *h = bh;
+ if (*w < bh)
+ *w = bh;
+- if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
++ if (c->resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+ if (!c->hintsvalid)
+ updatesizehints(c);
+ /* see last two sentences in ICCCM 4.1.2.3 */
+@@ -1043,6 +1045,7 @@ manage(Window w, XWindowAttributes *wa)
+ c->w = c->oldw = wa->width;
+ c->h = c->oldh = wa->height;
+ c->oldbw = wa->border_width;
++ c->resizehints = resizehints;
+
+ updatetitle(c);
+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+--
+2.46.0
diff --git a/dwm/patches/dwm-colorbar-6.3.diff b/dwm/patches/dwm-colorbar-6.3.diff
new file mode 100644
index 0000000..976a2e5
--- /dev/null
+++ b/dwm/patches/dwm-colorbar-6.3.diff
@@ -0,0 +1,85 @@
+# From 647a2a56cf7cab6dea868f9800671770940ce3c3 Mon Sep 17 00:00:00 2001
+# From: Alessandro Sisto <alessandro.sisto@studioform.net>
+# Date: Sun, 5 Jun 2022 12:03:43 +0200
+# Subject: [PATCH] colorbar
+#
+# ---
+# config.def.h | 6 +++++-
+# dwm.c | 12 ++++++------
+# 2 files changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..56bc324 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -16,6 +16,11 @@ static const char *colors[][3] = {
+ /* fg bg border */
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
++ [SchemeStatus] = { col_gray3, col_gray1, "#000000" }, // Statusbar right {text,background,not used but cannot be empty}
++ [SchemeTagsSel] = { col_gray4, col_cyan, "#000000" }, // Tagbar left selected {text,background,not used but cannot be empty}
++ [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, // Tagbar left unselected {text,background,not used but cannot be empty}
++ [SchemeInfoSel] = { col_gray4, col_cyan, "#000000" }, // infobar middle selected {text,background,not used but cannot be empty}
++ [SchemeInfoNorm] = { col_gray3, col_gray1, "#000000" }, // infobar middle unselected {text,background,not used but cannot be empty}
+ };
+
+ /* tagging */
+@@ -113,4 +118,3 @@ static Button buttons[] = {
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ };
+-
+diff --git a/dwm.c b/dwm.c
+index a96f33c..0eaa4cd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -59,7 +59,7 @@
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+-enum { SchemeNorm, SchemeSel }; /* color schemes */
++enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+@@ -707,7 +707,7 @@ drawbar(Monitor *m)
+
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
+- drw_setscheme(drw, scheme[SchemeNorm]);
++ drw_setscheme(drw, scheme[SchemeStatus]);
+ tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+ }
+@@ -720,7 +720,7 @@ drawbar(Monitor *m)
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+ w = TEXTW(tags[i]);
+- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+@@ -729,17 +729,17 @@ drawbar(Monitor *m)
+ x += w;
+ }
+ w = blw = TEXTW(m->ltsymbol);
+- drw_setscheme(drw, scheme[SchemeNorm]);
++ drw_setscheme(drw, scheme[SchemeTagsNorm]);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel) {
+- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
++ drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+- drw_setscheme(drw, scheme[SchemeNorm]);
++ drw_setscheme(drw, scheme[SchemeInfoNorm]);
+ drw_rect(drw, x, 0, w, bh, 1, 1);
+ }
+ }
+--
+2.36.1
diff --git a/dwm/patches/dwm-exresize-r1606.diff b/dwm/patches/dwm-exresize-r1606.diff
new file mode 100644
index 0000000..dcc93c0
--- /dev/null
+++ b/dwm/patches/dwm-exresize-r1606.diff
@@ -0,0 +1,372 @@
+diff --git a/config.def.h b/config.def.h
+index 7fb4d82..959a119 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -88,6 +88,33 @@ static Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++
++ { MODKEY, XK_KP_7, explace, {.ui = EX_NW }},
++ { MODKEY, XK_KP_8, explace, {.ui = EX_N }},
++ { MODKEY, XK_KP_9, explace, {.ui = EX_NE }},
++ { MODKEY, XK_KP_4, explace, {.ui = EX_W }},
++ { MODKEY, XK_KP_5, explace, {.ui = EX_C }},
++ { MODKEY, XK_KP_6, explace, {.ui = EX_E }},
++ { MODKEY, XK_KP_1, explace, {.ui = EX_SW }},
++ { MODKEY, XK_KP_2, explace, {.ui = EX_S }},
++ { MODKEY, XK_KP_3, explace, {.ui = EX_SE }},
++
++ { MODKEY|ShiftMask, XK_KP_8, exresize, {.v = (int []){ 0, 25 }}},
++ { MODKEY|ShiftMask, XK_KP_2, exresize, {.v = (int []){ 0, -25 }}},
++ { MODKEY|ShiftMask, XK_KP_6, exresize, {.v = (int []){ 25, 0 }}},
++ { MODKEY|ShiftMask, XK_KP_4, exresize, {.v = (int []){ -25, 0 }}},
++ { MODKEY|ShiftMask, XK_KP_5, exresize, {.v = (int []){ 25, 25 }}},
++ { MODKEY|ShiftMask|ControlMask, XK_KP_5, exresize, {.v = (int []){ -25, -25 }}},
++
++ { MODKEY|ControlMask, XK_KP_6, togglehorizontalexpand, {.i = +1} },
++ { MODKEY|ControlMask, XK_KP_3, togglehorizontalexpand, {.i = 0} },
++ { MODKEY|ControlMask, XK_KP_4, togglehorizontalexpand, {.i = -1} },
++ { MODKEY|ControlMask, XK_KP_8, toggleverticalexpand, {.i = +1} },
++ { MODKEY|ControlMask, XK_KP_1, toggleverticalexpand, {.i = 0} },
++ { MODKEY|ControlMask, XK_KP_2, toggleverticalexpand, {.i = -1} },
++ { MODKEY|ControlMask, XK_KP_9, togglemaximize, {.i = -1} },
++ { MODKEY|ControlMask, XK_KP_7, togglemaximize, {.i = +1} },
++ { MODKEY|ControlMask, XK_KP_5, togglemaximize, {.i = 0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index 4986b07..8fc0c57 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -89,11 +89,14 @@ struct Client {
+ char name[256];
+ float mina, maxa;
+ int x, y, w, h;
++ int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
+ int oldx, oldy, oldw, oldh;
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh;
+ int bw, oldbw;
+ unsigned int tags;
+- Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ unsigned char expandmask;
++ int expandx1, expandy1, expandx2, expandy2;
++ Bool wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -1132,8 +1135,14 @@ manage(Window w, XWindowAttributes *wa) {
+ updatewindowtype(c);
+ updatesizehints(c);
+ updatewmhints(c);
++ c->sfx = c->x;
++ c->sfy = c->y;
++ c->sfw = c->w;
++ c->sfh = c->h;
+ XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ grabbuttons(c, False);
++ c->wasfloating = False;
++ c->expandmask = 0;
+ if(!c->isfloating)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if(c->isfloating)
+@@ -1234,8 +1243,9 @@ movemouse(const Arg *arg) {
+ case MotionNotify:
+ nx = ocx + (ev.xmotion.x - x);
+ ny = ocy + (ev.xmotion.y - y);
+- if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
+- && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
++ if ((m = recttomon(nx, ny, c->w, c->h))) {
++ if (m != selmon)
++ sendmon(c, m);
+ if(abs(selmon->wx - nx) < snap)
+ nx = selmon->wx;
+ else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
+@@ -1343,6 +1353,7 @@ resizeclient(Client *c, int x, int y, int w, int h) {
+ c->oldy = c->y; c->y = wc.y = y;
+ c->oldw = c->w; c->w = wc.width = w;
+ c->oldh = c->h; c->h = wc.height = h;
++ c->expandmask = 0;
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+@@ -1379,9 +1390,9 @@ resizemouse(const Arg *arg) {
+ case MotionNotify:
+ nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
+ nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
+- if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
+- && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
+- {
++ if ((m = recttomon(c->x, c->y, nw, nh))) {
++ if (m != selmon)
++ sendmon(c, m);
+ if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
+ && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
+@@ -1463,6 +1474,7 @@ scan(void) {
+
+ void
+ sendmon(Client *c, Monitor *m) {
++ Monitor *oldm = selmon;
+ if(c->mon == m)
+ return;
+ unfocus(c, True);
+@@ -1472,8 +1484,11 @@ sendmon(Client *c, Monitor *m) {
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ attach(c);
+ attachstack(c);
+- focus(NULL);
+- arrange(NULL);
++ if (oldm != m)
++ arrange(oldm);
++ arrange(m);
++ focus(c);
++ restack(m);
+ }
+
+ void
+@@ -1549,8 +1564,18 @@ setfullscreen(Client *c, Bool fullscreen) {
+
+ void
+ setlayout(const Arg *arg) {
+- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
+ selmon->sellt ^= 1;
++ if (!selmon->lt[selmon->sellt]->arrange) {
++ for (Client *c = selmon->clients ; c ; c = c->next) {
++ if(!c->isfloating) {
++ /*restore last known float dimensions*/
++ resize(c, selmon->mx + c->sfx, selmon->my + c->sfy,
++ c->sfw, c->sfh, False);
++ }
++ }
++ }
++ }
+ if(arg && arg->v)
+ selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
+@@ -1732,9 +1757,19 @@ togglefloating(const Arg *arg) {
+ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
+ selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
+- if(selmon->sel->isfloating)
+- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+- selmon->sel->w, selmon->sel->h, False);
++ if(selmon->sel->isfloating) {
++ /*restore last known float dimensions*/
++ resize(selmon->sel, selmon->mx + selmon->sel->sfx, selmon->my + selmon->sel->sfy,
++ selmon->sel->sfw, selmon->sel->sfh, False);
++ } else {
++ if (selmon->sel->isfullscreen)
++ setfullscreen(selmon->sel, False);
++ /*save last known float dimensions*/
++ selmon->sel->sfx = selmon->sel->x - selmon->mx;
++ selmon->sel->sfy = selmon->sel->y - selmon->my;
++ selmon->sel->sfw = selmon->sel->w;
++ selmon->sel->sfh = selmon->sel->h;
++ }
+ arrange(selmon);
+ }
+
+diff --git a/exresize.c b/exresize.c
+new file mode 100644
+index 0000000..2343ffe
+--- /dev/null
++++ b/exresize.c
+@@ -0,0 +1,195 @@
++#define EXPAND_LEFT (1 << 0)
++#define EXPAND_RIGHT (1 << 2)
++#define EXPAND_UP (1 << 4)
++#define EXPAND_DOWN (1 << 6)
++
++#define IS_SET(q, w) ((q & w) != 0)
++#define IS_FORCED(q, w) IS_SET((q << 1), w)
++
++#define EXPANDALL (EXPAND_LEFT | EXPAND_RIGHT | EXPAND_UP | EXPAND_DOWN)
++#define UNEXPAND (EXPANDALL << 1) // Force all directions to 0
++#define FORCE_EXPANDALL ~0 // Force expand in all directions
++
++enum { EX_NW, EX_N, EX_NE, EX_W, EX_C, EX_E, EX_SW, EX_S, EX_SE };
++
++void expand(unsigned char mask);
++
++void togglemaximize(const Arg *arg);
++void toggleverticalexpand(const Arg *arg);
++void togglehorizontalexpand(const Arg *arg);
++void exresize(const Arg *arg);
++void explace(const Arg *arg);
++
++void
++exresize(const Arg *arg) {
++ Client *c;
++ int x, y, nx, ny, nw, nh;
++ c = selmon->sel;
++
++ if (!c || !arg) return;
++ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
++ togglefloating(NULL);
++ if (c->expandmask != 0)
++ expand(UNEXPAND);
++
++ x = ((int *)arg->v)[0];
++ y = ((int *)arg->v)[1];
++
++ nw = MIN(selmon->ww - c->bw*2, c->w + x);
++ nh = MIN(selmon->wh - c->bw*2, c->h + y);
++ nx = c->x - x/2;
++ ny = c->y - y/2;
++
++ if (!((abs(c->x + c->w/2 - (selmon->wx + selmon->ww/2)) < snap))) {
++ if ((nw == selmon->ww) ||
++ (nx < selmon->wx) ||
++ (abs(selmon->wx - c->x) < snap))
++ nx = selmon->wx;
++ else if ((nx+nw > (selmon->wx + selmon->ww)) ||
++ (abs((selmon->wx + selmon->ww) - (c->x + c->w)) < snap))
++ nx = (selmon->wx + selmon->ww) - nw - c->bw*2;
++ } else
++ nx = selmon->wx + selmon->ww/2 - nw/2;
++
++ if (!((abs(c->y + c->h/2 - (selmon->wy + selmon->wh/2)) < snap))) {
++
++ if ((nh == selmon->wh) ||
++ (ny < selmon->wy) ||
++ (abs(selmon->wy - c->y) < snap))
++ ny = selmon->wy;
++ else if ((ny+nh > (selmon->wy + selmon->wh)) ||
++ (abs((selmon->wy + selmon->wh) - (c->y + c->h)) < snap))
++ ny = (selmon->wy + selmon->wh) - nh - c->bw*2;
++ } else
++ ny = selmon->wy + selmon->wh/2 - nh/2;
++
++
++ resizeclient(c, nx, ny, MAX(nw, 32), MAX(nh, 32));
++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
++}
++
++void
++explace(const Arg *arg) {
++ Client *c;
++ int nx, ny;
++
++ c = selmon->sel;
++ if (!c || (arg->ui >= 9)) return;
++ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
++ togglefloating(NULL);
++
++ nx = (arg->ui % 3) - 1;
++ ny = (arg->ui / 3) - 1;
++
++ if (nx < 0) nx = selmon->wx;
++ else if (nx > 0) nx = selmon->wx + selmon->ww - c->w - c->bw*2;
++ else nx = selmon->wx + selmon->ww/2 - c->w/2;
++
++ if (ny < 0) ny = selmon->wy;
++ else if (ny > 0) ny = selmon->wy + selmon->wh - c->h - c->bw*2;
++ else ny = selmon->wy + selmon->wh/2 - c->h/2;
++
++ resize(c, nx, ny, c->w, c->h, 0);
++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
++}
++
++int
++calculate_expand(unsigned char mask, unsigned char curmask,
++ unsigned char *newmask, unsigned char key,
++ int *reset_value, int new_reset_value,
++ int max_value, int old_value) {
++ if (IS_SET(key, mask) ||
++ (IS_SET(key, curmask) && (!IS_SET(key, mask) && IS_FORCED(key, mask))) ||
++ (!IS_SET(key, curmask) && (IS_SET(key, mask) && IS_FORCED(key, mask)))) {
++
++ if (IS_SET(key, mask) && (!IS_SET(key,curmask) || IS_FORCED(key,mask)))
++ {
++ if (!IS_SET(key, curmask))
++ *reset_value = new_reset_value;
++ *newmask |= key;
++ return max_value;
++ } else if ((IS_SET(key,curmask) && IS_SET(key, mask)) ||
++ (!IS_SET(key, mask) && IS_FORCED(key, mask))) {
++ *newmask &= ~key;
++ return *reset_value;
++ } else {
++ *newmask &= ~key;
++ return old_value;
++ }
++ } else
++ return new_reset_value;
++}
++
++void
++expand(unsigned char mask) {
++ XEvent ev;
++ int nx1, ny1, nx2, ny2;
++ unsigned char curmask;
++ unsigned char newmask;
++
++ if(!selmon->sel || selmon->sel->isfixed)
++ return;
++ XRaiseWindow(dpy, selmon->sel->win);
++ newmask = curmask = selmon->sel->expandmask;
++
++ if (curmask == 0) {
++ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating)
++ selmon->sel->wasfloating = 0;
++ else {
++ togglefloating(NULL);
++ selmon->sel->wasfloating = 0;
++ }
++ }
++
++ nx1 = calculate_expand(mask, curmask, &newmask,
++ EXPAND_LEFT, &selmon->sel->expandx1,
++ selmon->sel->x,
++ selmon->wx,
++ selmon->sel->oldx);
++ nx2 = calculate_expand(mask, curmask, &newmask,
++ EXPAND_RIGHT, &selmon->sel->expandx2,
++ selmon->sel->x + selmon->sel->w,
++ selmon->wx + selmon->ww - 2*borderpx,
++ selmon->sel->oldw + selmon->sel->x);
++ ny1 = calculate_expand(mask, curmask, &newmask,
++ EXPAND_UP, &selmon->sel->expandy1,
++ selmon->sel->y,
++ selmon->wy,
++ selmon->sel->oldy);
++ ny2 = calculate_expand(mask, curmask, &newmask,
++ EXPAND_DOWN, &selmon->sel->expandy2,
++ selmon->sel->y + selmon->sel->h,
++ selmon->wy + selmon->wh - 2*borderpx,
++ selmon->sel->oldh + selmon->sel->y);
++
++
++ resizeclient(selmon->sel, nx1, ny1, MAX(nx2-nx1, 32), MAX(ny2-ny1, 32));
++
++ if ((newmask == 0) && (!selmon->sel->wasfloating))
++ togglefloating(NULL);
++ selmon->sel->expandmask = newmask;
++ drawbar(selmon);
++ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
++}
++
++void
++togglemaximize(const Arg *arg) {
++ if (arg->i > 0) expand(FORCE_EXPANDALL);
++ else if (arg->i < 0) expand(UNEXPAND);
++ else expand(EXPANDALL);
++}
++
++void
++toggleverticalexpand(const Arg *arg) {
++ if (arg->i < 0) expand(EXPAND_DOWN);
++ else if (arg->i > 0) expand(EXPAND_UP);
++ else expand(EXPAND_DOWN | EXPAND_UP);
++}
++
++void
++togglehorizontalexpand(const Arg *arg) {
++ if (arg->i < 0) expand(EXPAND_LEFT);
++ else if (arg->i > 0) expand(EXPAND_RIGHT);
++ else expand(EXPAND_LEFT | EXPAND_RIGHT);
++}
++
diff --git a/dwm/patches/dwm-float-border-color-20231008-3a7ea45f.diff b/dwm/patches/dwm-float-border-color-20231008-3a7ea45f.diff
new file mode 100644
index 0000000..dc1106b
--- /dev/null
+++ b/dwm/patches/dwm-float-border-color-20231008-3a7ea45f.diff
@@ -0,0 +1,108 @@
+# From 5f6716fa3fb7e28e6592872ce3de32b7aa0965a7 Mon Sep 17 00:00:00 2001
+# From: glpzzz <glpz@daxslab.com>
+# Date: Sun, 8 Oct 2023 16:44:37 -0400
+# Subject: [PATCH] set the custom colored floating border on unfocus too.
+#
+# ---
+# config.def.h | 8 ++++----
+# dwm.c | 24 ++++++++++++++++++++----
+# 2 files changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..ce68d1e 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -12,10 +12,10 @@ static const char col_gray2[] = "#444444";
+ static const char col_gray3[] = "#bbbbbb";
+ static const char col_gray4[] = "#eeeeee";
+ static const char col_cyan[] = "#005577";
+-static const char *colors[][3] = {
+- /* fg bg border */
+- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
++static const char *colors[][4] = {
++ /* fg bg border float */
++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2, col_gray2 },
++ [SchemeSel] = { col_gray4, col_cyan, col_gray2, col_cyan },
+ };
+
+ /* tagging */
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..4182083 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -56,6 +56,7 @@
+ #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
+ #define TAGMASK ((1 << LENGTH(tags)) - 1)
+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
++#define ColFloat 3
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+@@ -801,7 +802,10 @@ focus(Client *c)
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, 1);
+- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
++ if(c->isfloating)
++ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
++ else
++ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ setfocus(c);
+ } else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+@@ -1063,7 +1067,10 @@ manage(Window w, XWindowAttributes *wa)
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+- XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
++ if(c->isfloating)
++ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
++ else
++ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatewindowtype(c);
+ updatesizehints(c);
+@@ -1074,6 +1081,8 @@ manage(Window w, XWindowAttributes *wa)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
++ if(c->isfloating)
++ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
+ attach(c);
+ attachstack(c);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+@@ -1586,7 +1595,7 @@ setup(void)
+ /* init appearance */
+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ for (i = 0; i < LENGTH(colors); i++)
+- scheme[i] = drw_scm_create(drw, colors[i], 3);
++ scheme[i] = drw_scm_create(drw, colors[i], 4);
+ /* init bars */
+ updatebars();
+ updatestatus();
+@@ -1730,6 +1739,10 @@ togglefloating(const Arg *arg)
+ return;
+ selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
+ if (selmon->sel->isfloating)
++ XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColFloat].pixel);
++ else
++ XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColBorder].pixel);
++ if(selmon->sel->isfloating)
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, 0);
+ arrange(selmon);
+@@ -1768,7 +1781,10 @@ unfocus(Client *c, int setfocus)
+ if (!c)
+ return;
+ grabbuttons(c, 0);
+- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
++ if (c->isfloating)
++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
++ else
++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+--
+2.39.2
diff --git a/dwm/patches/dwm-floatborderwidth-6.3.diff b/dwm/patches/dwm-floatborderwidth-6.3.diff
new file mode 100644
index 0000000..d41bed2
--- /dev/null
+++ b/dwm/patches/dwm-floatborderwidth-6.3.diff
@@ -0,0 +1,68 @@
+# From 54b88e6663364d561fc0feb3ea9d4c79c0f4e3b0 Mon Sep 17 00:00:00 2001
+# From: Dylan Cairns-Howarth <dairnarth@dylancairns.co.uk>
+# Date: Sun, 20 Feb 2022 07:48:59 +0000
+# Subject: [PATCH] Floating Windows have seperate border width
+#
+# This dwm patch adds the int fborderpx to config.def.h that assigns a
+# border width to floating windows.
+#
+# By default, this patch sets borderpx to 0 and fborderpx to 1 (no borders
+# for tiled windows and a 1px border for floating windows).
+# ---
+# config.def.h | 4 ++--
+# dwm.c | 13 +++++++++++--
+# 2 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..ce35589 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -1,7 +1,8 @@
+ /* See LICENSE file for copyright and license details. */
+
+ /* appearance */
+-static const unsigned int borderpx = 1; /* border pixel of windows */
++static const unsigned int borderpx = 0; /* border pixel of windows */
++static const unsigned int fborderpx = 1; /* border pixel of floating 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 */
+@@ -113,4 +114,3 @@ static Button buttons[] = {
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ };
+-
+diff --git a/dwm.c b/dwm.c
+index a96f33c..a63e9cd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1052,6 +1052,8 @@ manage(Window w, XWindowAttributes *wa)
+ c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
+ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+ c->bw = borderpx;
++ if (c->isfloating)
++ c->bw = fborderpx;
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+@@ -1719,9 +1721,16 @@ togglefloating(const Arg *arg)
+ if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
+ selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
+- if (selmon->sel->isfloating)
++ if (selmon->sel->isfloating) {
++ selmon->sel->bw = fborderpx;
++ configure(selmon->sel);
++ int borderdiff = (fborderpx - borderpx) * 2;
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+- selmon->sel->w, selmon->sel->h, 0);
++ selmon->sel->w - borderdiff, selmon->sel->h - borderdiff, 0);
++ } else {
++ selmon->sel->bw = borderpx;
++ configure(selmon->sel);
++ }
+ arrange(selmon);
+ }
+
+--
+2.35.1
diff --git a/dwm/patches/dwm-focusmaster-return-6.2.diff b/dwm/patches/dwm-focusmaster-return-6.2.diff
new file mode 100644
index 0000000..9a02054
--- /dev/null
+++ b/dwm/patches/dwm-focusmaster-return-6.2.diff
@@ -0,0 +1,89 @@
+# From 8f662e7a556f94bda83ec724fb036e15b2badaac Mon Sep 17 00:00:00 2001
+# From: Jack Bird <jack.bird@durham.ac.uk>
+# Date: Fri, 27 Aug 2021 01:14:44 +0100
+# Subject: [PATCH] 6.2 focusmaster return
+#
+# ---
+# dwm.c | 39 +++++++++++++++++++++++++++++++++++++++
+# 1 file changed, 39 insertions(+)
+
+diff --git a/dwm.c b/dwm.c
+index 4465af1..5219cbd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -127,6 +127,7 @@ struct Monitor {
+ Client *clients;
+ Client *sel;
+ Client *stack;
++ Client *tagmarked[32];
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
+@@ -167,6 +168,7 @@ static void enternotify(XEvent *e);
+ static void expose(XEvent *e);
+ static void focus(Client *c);
+ static void focusin(XEvent *e);
++static void focusmaster(const Arg *arg);
+ static void focusmon(const Arg *arg);
+ static void focusstack(const Arg *arg);
+ static int getrootptr(int *x, int *y);
+@@ -659,6 +661,10 @@ detach(Client *c)
+ {
+ Client **tc;
+
++ for (int i = 1; i < LENGTH(tags); i++)
++ if (c == c->mon->tagmarked[i])
++ c->mon->tagmarked[i] = NULL;
++
+ for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
+ *tc = c->next;
+ }
+@@ -815,6 +821,34 @@ focusin(XEvent *e)
+ setfocus(selmon->sel);
+ }
+
++void
++focusmaster(const Arg *arg)
++{
++ Client *master;
++
++ if (selmon->nmaster > 1)
++ return;
++ if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
++ return;
++
++ master = nexttiled(selmon->clients);
++
++ if (!master)
++ return;
++
++ int i;
++ for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
++ i++;
++
++ if (selmon->sel == master) {
++ if (selmon->tagmarked[i] && ISVISIBLE(selmon->tagmarked[i]))
++ focus(selmon->tagmarked[i]);
++ } else {
++ selmon->tagmarked[i] = selmon->sel;
++ focus(master);
++ }
++}
++
+ void
+ focusmon(const Arg *arg)
+ {
+@@ -1202,6 +1236,11 @@ nexttiled(Client *c)
+ void
+ pop(Client *c)
+ {
++ int i;
++ for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
++ i++;
++
++ c->mon->tagmarked[i] = nexttiled(c->mon->clients);
+ detach(c);
+ attach(c);
+ focus(c);
+--
+2.33.0
diff --git a/dwm/patches/dwm-gestures-6.4.diff b/dwm/patches/dwm-gestures-6.4.diff
new file mode 100644
index 0000000..d3ed528
--- /dev/null
+++ b/dwm/patches/dwm-gestures-6.4.diff
@@ -0,0 +1,126 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2023-01-13 15:14:16.536118429 +0100
++++ b/config.def.h 2023-01-13 15:21:25.946360539 +0100
+@@ -78,6 +78,7 @@ static const Key keys[] = {
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
++ { MODKEY, XK_g, gesture, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+@@ -107,9 +108,21 @@ static const Button buttons[] = {
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
++ { ClkClientWin, MODKEY|ShiftMask,Button3, gesture, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ };
+
++/* gestures
++ * u means up
++ * d means down
++ * l means left
++ * r means right
++ * ud means up and down
++ */
++static Gesture gestures[] = {
++ { "u", spawn, {.v = termcmd } },
++ { "d", spawn, {.v = dmenucmd } },
++};
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2023-01-13 15:14:16.536118429 +0100
++++ b/dwm.c 2023-01-13 15:14:41.094075080 +0100
+@@ -75,6 +75,12 @@ typedef union {
+ } Arg;
+
+ typedef struct {
++ char *gname;
++ void (*func)(const Arg *arg);
++ const Arg arg;
++} Gesture;
++
++typedef struct {
+ unsigned int click;
+ unsigned int mask;
+ unsigned int button;
+@@ -183,6 +189,7 @@ static void mappingnotify(XEvent *e);
+ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
++static void gesture(const Arg *arg);
+ static void movemouse(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *c);
+@@ -1134,6 +1141,68 @@ motionnotify(XEvent *e)
+ }
+
+ void
++gesture(const Arg *arg) {
++ int x, y, dx, dy, q;
++ int valid=0, listpos=0, gestpos=0, count=0;
++ char move, currGest[10];
++ XEvent ev;
++
++ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
++ return;
++ if(!getrootptr(&x, &y))
++ return;
++ do {
++ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
++ switch (ev.type) {
++ case ConfigureRequest:
++ case Expose:
++ case MapRequest:
++ handler[ev.type](&ev);
++ break;
++ case MotionNotify:
++ if(count++ < 10)
++ break;
++ count = 0;
++ dx = ev.xmotion.x - x;
++ dy = ev.xmotion.y - y;
++ x = ev.xmotion.x;
++ y = ev.xmotion.y;
++
++ if( abs(dx)/(abs(dy)+1) == 0 )
++ move = dy<0?'u':'d';
++ else
++ move = dx<0?'l':'r';
++
++ if(move!=currGest[gestpos-1])
++ {
++ if(gestpos>9)
++ { ev.type++;
++ break;
++ }
++
++ currGest[gestpos] = move;
++ currGest[++gestpos] = '\0';
++
++ valid = 0;
++ for(q = 0; q<LENGTH(gestures); q++)
++ { if(!strcmp(currGest, gestures[q].gname))
++ { valid++;
++ listpos = q;
++ }
++ }
++ }
++
++ }
++ } while(ev.type != ButtonRelease);
++
++ if(valid)
++ gestures[listpos].func(&(gestures[listpos].arg));
++
++ XUngrabPointer(dpy, CurrentTime);
++}
++
++void
+ movemouse(const Arg *arg)
+ {
+ int x, y, ocx, ocy, nx, ny;
diff --git a/dwm/patches/dwm-hide_vacant_tags-6.4.diff b/dwm/patches/dwm-hide_vacant_tags-6.4.diff
new file mode 100644
index 0000000..42d9c05
--- /dev/null
+++ b/dwm/patches/dwm-hide_vacant_tags-6.4.diff
@@ -0,0 +1,48 @@
+:100644 100644 f1d86b2 0000000 M dwm.c
+
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..d41cc14 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -433,9 +433,15 @@ buttonpress(XEvent *e)
+ }
+ if (ev->window == selmon->barwin) {
+ i = x = 0;
+- do
++ unsigned int occ = 0;
++ for(c = m->clients; c; c=c->next)
++ occ |= c->tags == TAGMASK ? 0 : c->tags;
++ do {
++ /* Do not reserve space for vacant tags */
++ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
++ continue;
+ x += TEXTW(tags[i]);
+- while (ev->x >= x && ++i < LENGTH(tags));
++ } while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+ arg.ui = 1 << i;
+@@ -715,19 +721,18 @@ drawbar(Monitor *m)
+ }
+
+ for (c = m->clients; c; c = c->next) {
+- occ |= c->tags;
++ occ |= c->tags == TAGMASK ? 0 : c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
++ /* Do not draw vacant tags */
++ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
++ continue;
+ w = TEXTW(tags[i]);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+- if (occ & 1 << i)
+- drw_rect(drw, x + boxs, boxs, boxw, boxw,
+- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+- urg & 1 << i);
+ x += w;
+ }
+ w = TEXTW(m->ltsymbol);
diff --git a/dwm/patches/dwm-keychord-6.4.diff b/dwm/patches/dwm-keychord-6.4.diff
new file mode 100644
index 0000000..cd22e03
--- /dev/null
+++ b/dwm/patches/dwm-keychord-6.4.diff
@@ -0,0 +1,234 @@
+# From cb7ea178ac8e60cf123b333af64df8228762f669 Mon Sep 17 00:00:00 2001
+# From: =?UTF-8?q?Aaron=20Z=C3=BCger?= <contact@azureorange.xyz>
+# Date: Wed, 19 Jul 2023 14:17:39 +0200
+# Subject: [PATCH] Update dwm-keychord patch to comply with the changes in dwm
+# from version 6.2 to version 6.4. Namely changes in the grabkey function to
+# match the newer implementation of said function.
+#
+# ---
+# config.def.h | 81 ++++++++++++++++++++++++++--------------------------
+# dwm.c | 72 +++++++++++++++++++++++++++++++++++++---------
+# 2 files changed, 99 insertions(+), 54 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..49f0558 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -46,11 +46,11 @@ static const Layout layouts[] = {
+
+ /* key definitions */
+ #define MODKEY 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} },
++#define TAGKEYS(KEY,TAG) \
++ &((Keychord){1, {{MODKEY, KEY}}, view, {.ui = 1 << TAG} }), \
++ &((Keychord){1, {{MODKEY|ControlMask, KEY}}, toggleview, {.ui = 1 << TAG} }), \
++ &((Keychord){1, {{MODKEY|ShiftMask, KEY}}, tag, {.ui = 1 << TAG} }), \
++ &((Keychord){1, {{MODKEY|ControlMask|ShiftMask, KEY}}, toggletag, {.ui = 1 << TAG} }),
+
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+@@ -60,41 +60,42 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
+-static const Key keys[] = {
+- /* modifier key function argument */
+- { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+- { MODKEY, XK_b, togglebar, {0} },
+- { MODKEY, XK_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, XK_Return, zoom, {0} },
+- { MODKEY, XK_Tab, view, {0} },
+- { MODKEY|ShiftMask, XK_c, killclient, {0} },
+- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+- { MODKEY, XK_space, setlayout, {0} },
+- { MODKEY|ShiftMask, XK_space, togglefloating, {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 } },
+- 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|ShiftMask, XK_q, quit, {0} },
++static Keychord *keychords[] = {
++ /* Keys function argument */
++ &((Keychord){1, {{MODKEY, XK_p}}, spawn, {.v = dmenucmd } }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_Return}}, spawn, {.v = termcmd } }),
++ &((Keychord){2, {{MODKEY, XK_e}, {MODKEY, XK_e}}, spawn, {.v = termcmd } }),
++ &((Keychord){1, {{MODKEY, XK_b}}, togglebar, {0} }),
++ &((Keychord){1, {{MODKEY, XK_j}}, focusstack, {.i = +1 } }),
++ &((Keychord){1, {{MODKEY, XK_k}}, focusstack, {.i = -1 } }),
++ &((Keychord){1, {{MODKEY, XK_i}}, incnmaster, {.i = +1 } }),
++ &((Keychord){1, {{MODKEY, XK_d}}, incnmaster, {.i = -1 } }),
++ &((Keychord){1, {{MODKEY, XK_h}}, setmfact, {.f = -0.05} }),
++ &((Keychord){1, {{MODKEY, XK_l}}, setmfact, {.f = +0.05} }),
++ &((Keychord){1, {{MODKEY, XK_Return}}, zoom, {0} }),
++ &((Keychord){1, {{MODKEY, XK_Tab}}, view, {0} }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_c}}, killclient, {0} }),
++ &((Keychord){1, {{MODKEY, XK_t}}, setlayout, {.v = &layouts[0]} }),
++ &((Keychord){1, {{MODKEY, XK_f}}, setlayout, {.v = &layouts[1]} }),
++ &((Keychord){1, {{MODKEY, XK_m}}, setlayout, {.v = &layouts[2]} }),
++ &((Keychord){1, {{MODKEY, XK_space}}, setlayout, {0} }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_space}}, togglefloating, {0} }),
++ &((Keychord){1, {{MODKEY, XK_0}}, view, {.ui = ~0 } }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_0}}, tag, {.ui = ~0 } }),
++ &((Keychord){1, {{MODKEY, XK_comma}}, focusmon, {.i = -1 } }),
++ &((Keychord){1, {{MODKEY, XK_period}}, focusmon, {.i = +1 } }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_comma}}, tagmon, {.i = -1 } }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_period}}, tagmon, {.i = +1 } }),
++ &((Keychord){1, {{MODKEY|ShiftMask, XK_q}}, quit, {0} }),
++ 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)
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..e4885a4 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -102,9 +102,14 @@ struct Client {
+ typedef struct {
+ unsigned int mod;
+ KeySym keysym;
++} Key;
++
++typedef struct {
++ unsigned int n;
++ const Key keys[5];
+ void (*func)(const Arg *);
+ const Arg arg;
+-} Key;
++} Keychord;
+
+ typedef struct {
+ const char *symbol;
+@@ -267,6 +272,7 @@ static Display *dpy;
+ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
++unsigned int currentkey = 0;
+
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+@@ -954,7 +960,8 @@ grabkeys(void)
+ {
+ updatenumlockmask();
+ {
+- unsigned int i, j, k;
++ /* unsigned int i, j, k; */
++ unsigned int i, c, k;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+ int start, end, skip;
+ KeySym *syms;
+@@ -964,15 +971,18 @@ grabkeys(void)
+ syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+ if (!syms)
+ return;
++
+ for (k = start; k <= end; k++)
+- for (i = 0; i < LENGTH(keys); i++)
++ for (i = 0; i < LENGTH(keychords); i++)
+ /* skip modifier codes, we do that ourselves */
+- if (keys[i].keysym == syms[(k - start) * skip])
+- for (j = 0; j < LENGTH(modifiers); j++)
++ if (keychords[i]->keys[currentkey].keysym == syms[(k - start) * skip])
++ for (c = 0; c < LENGTH(modifiers); c++)
+ XGrabKey(dpy, k,
+- keys[i].mod | modifiers[j],
++ keychords[i]->keys[currentkey].mod | modifiers[c],
+ root, True,
+ GrabModeAsync, GrabModeAsync);
++ if(currentkey > 0)
++ XGrabKey(dpy, XKeysymToKeycode(dpy, XK_Escape), AnyModifier, root, True, GrabModeAsync, GrabModeAsync);
+ XFree(syms);
+ }
+ }
+@@ -999,17 +1009,51 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
+ void
+ keypress(XEvent *e)
+ {
+- unsigned int i;
++ /* unsigned int i; */
++ XEvent event = *e;
++ unsigned int ran = 0;
+ KeySym keysym;
+ XKeyEvent *ev;
+
+- ev = &e->xkey;
+- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+- for (i = 0; i < LENGTH(keys); i++)
+- if (keysym == keys[i].keysym
+- && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+- && keys[i].func)
+- keys[i].func(&(keys[i].arg));
++ Keychord *arr1[sizeof(keychords) / sizeof(Keychord*)];
++ Keychord *arr2[sizeof(keychords) / sizeof(Keychord*)];
++ memcpy(arr1, keychords, sizeof(keychords));
++ Keychord **rpointer = arr1;
++ Keychord **wpointer = arr2;
++
++ size_t r = sizeof(keychords)/ sizeof(Keychord*);
++
++ while(1){
++ ev = &event.xkey;
++ keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
++ size_t w = 0;
++ for (int i = 0; i < r; i++){
++ if(keysym == (*(rpointer + i))->keys[currentkey].keysym
++ && CLEANMASK((*(rpointer + i))->keys[currentkey].mod) == CLEANMASK(ev->state)
++ && (*(rpointer + i))->func){
++ if((*(rpointer + i))->n == currentkey +1){
++ (*(rpointer + i))->func(&((*(rpointer + i))->arg));
++ ran = 1;
++ }else{
++ *(wpointer + w) = *(rpointer + i);
++ w++;
++ }
++ }
++ }
++ currentkey++;
++ if(w == 0 || ran == 1)
++ break;
++ grabkeys();
++ while (running && !XNextEvent(dpy, &event) && !ran)
++ if(event.type == KeyPress)
++ break;
++ r = w;
++ Keychord **holder = rpointer;
++ rpointer = wpointer;
++ wpointer = holder;
++ }
++ currentkey = 0;
++ grabkeys();
+ }
+
+ void
+--
+2.41.0
diff --git a/dwm/patches/dwm-layoutmenu-6.2.diff b/dwm/patches/dwm-layoutmenu-6.2.diff
new file mode 100644
index 0000000..9a2417e
--- /dev/null
+++ b/dwm/patches/dwm-layoutmenu-6.2.diff
@@ -0,0 +1,88 @@
+# From e45e286b3d639b90ef202996d87054cced1fd80e Mon Sep 17 00:00:00 2001
+# From: tdu <tdukv@protonmail.com>
+# Date: Mon, 31 Aug 2020 00:07:32 +0300
+# Subject: [PATCH] Right clicking the layout symbol opens an xmenu prompt to
+# select layout.
+#
+# Xmenu need to be installed for this to work.
+# Edit layoutmenu with the correct layout table, and place in PATH.
+# ---
+# config.def.h | 3 ++-
+# dwm.c | 19 +++++++++++++++++++
+# layoutmenu | 7 +++++++
+# 3 files changed, 28 insertions(+), 1 deletion(-)
+# create mode 100755 layoutmenu
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..c9e0833 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -58,6 +58,7 @@ static const Layout layouts[] = {
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
++static const char *layoutmenu_cmd = "layoutmenu";
+
+ static Key keys[] = {
+ /* modifier key function argument */
+@@ -101,7 +102,7 @@ static Key keys[] = {
+ static Button buttons[] = {
+ /* click event mask button function argument */
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+- { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
++ { ClkLtSymbol, 0, Button3, layoutmenu, {0} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..2508a0a 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -177,6 +177,7 @@ static void grabkeys(void);
+ static void incnmaster(const Arg *arg);
+ static void keypress(XEvent *e);
+ static void killclient(const Arg *arg);
++static void layoutmenu(const Arg *arg);
+ static void manage(Window w, XWindowAttributes *wa);
+ static void mappingnotify(XEvent *e);
+ static void maprequest(XEvent *e);
+@@ -1014,6 +1015,24 @@ killclient(const Arg *arg)
+ }
+ }
+
++void
++layoutmenu(const Arg *arg) {
++ FILE *p;
++ char c[3], *s;
++ int i;
++
++ if (!(p = popen(layoutmenu_cmd, "r")))
++ return;
++ s = fgets(c, sizeof(c), p);
++ pclose(p);
++
++ if (!s || *s == '\0' || c[0] == '\0')
++ return;
++
++ i = atoi(c);
++ setlayout(&((Arg) { .v = &layouts[i] }));
++}
++
+ void
+ manage(Window w, XWindowAttributes *wa)
+ {
+diff --git a/layoutmenu b/layoutmenu
+new file mode 100755
+index 0000000..1bf95f2
+--- /dev/null
++++ b/layoutmenu
+@@ -0,0 +1,7 @@
++#!/bin/sh
++
++cat <<EOF | xmenu
++[]= Tiled Layout 0
++><> Floating Layout 1
++[M] Monocle Layout 2
++EOF
+--
+2.28.0
diff --git a/dwm/patches/dwm-layoutscroll-6.2.diff b/dwm/patches/dwm-layoutscroll-6.2.diff
new file mode 100644
index 0000000..95e621d
--- /dev/null
+++ b/dwm/patches/dwm-layoutscroll-6.2.diff
@@ -0,0 +1,67 @@
+diff --git a/config.def.h b/config.def.h
+index 4c56466..11ee7b5 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -90,6 +90,8 @@ static Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY|ShiftMask, XK_h, layoutscroll, {.i = -1 } },
++ { MODKEY|ShiftMask, XK_l, layoutscroll, {.i = +1 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+diff --git a/dwm.c b/dwm.c
+index 1e37fcf..24effbc 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -148,6 +148,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ int ltcur; /* current layout */
+ };
+
+ typedef struct {
+@@ -227,6 +228,7 @@ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
++static void layoutscroll(const Arg *arg);
+ static void setlayout(const Arg *arg);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+@@ -725,6 +727,7 @@ createmon(void)
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
++ m->ltcur = 0;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+@@ -1667,6 +1670,25 @@ setfullscreen(Client *c, int fullscreen)
+ }
+ }
+
++void
++layoutscroll(const Arg *arg)
++{
++ if (!arg || !arg->i)
++ return;
++ int switchto = selmon->ltcur + arg->i;
++ int l = LENGTH(layouts);
++
++ if (switchto == l)
++ switchto = 0;
++ else if(switchto < 0)
++ switchto = l - 1;
++
++ selmon->ltcur = switchto;
++ Arg arg2 = {.v= &layouts[switchto] };
++ setlayout(&arg2);
++
++}
++
+ void
+ setlayout(const Arg *arg)
+ {
diff --git a/dwm/patches/dwm-mark-new-6.2.diff b/dwm/patches/dwm-mark-new-6.2.diff
new file mode 100644
index 0000000..711c3fd
--- /dev/null
+++ b/dwm/patches/dwm-mark-new-6.2.diff
@@ -0,0 +1,247 @@
+# From 753860d3435e2968358f2bf8daf70bf625fe75fe Mon Sep 17 00:00:00 2001
+# From: Kajetan Puchalski <kajetan.puchalski@tuta.io>
+# Date: Mon, 5 Oct 2020 11:04:31 +0100
+# Subject: [PATCH] Updated Mark patch to work with 6.2
+#
+# ---
+# config.def.h | 14 +++++--
+# drw.h | 2 +-
+# dwm.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
+# 3 files changed, 118 insertions(+), 9 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 3858d75..a416c97 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -12,10 +12,13 @@ static const char col_gray2[] = "#444444";
+ static const char col_gray3[] = "#bbbbbb";
+ static const char col_gray4[] = "#eeeeee";
+ static const char col_cyan[] = "#005577";
+-static const char *colors[][3] = {
+- /* fg bg border */
+- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
++static const char normmarkcolor[] = "#775500"; /*border color for marked client*/
++static const char selmarkcolor[] = "#775577"; /*border color for marked client on focus*/
++
++static const char *colors[][4] = {
++ /* fg bg border mark */
++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2, normmarkcolor },
++ [SchemeSel] = { col_gray4, col_cyan, col_cyan, selmarkcolor },
+ };
+
+ /* tagging */
+@@ -94,6 +97,9 @@ static Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_semicolon, togglemark, {0} },
++ { MODKEY, XK_o, swapfocus, {0} },
++ { MODKEY, XK_u, swapclient, {0} },
+ };
+
+ /* button definitions */
+diff --git a/drw.h b/drw.h
+index 4bcd5ad..97aae99 100644
+--- a/drw.h
++++ b/drw.h
+@@ -12,7 +12,7 @@ typedef struct Fnt {
+ struct Fnt *next;
+ } Fnt;
+
+-enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */
++enum { ColFg, ColBg, ColBorder, ColMark }; /* Clr scheme index */
+ typedef XftColor Clr;
+
+ typedef struct {
+diff --git a/dwm.c b/dwm.c
+index 664c527..195b8eb 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -201,17 +201,21 @@ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
+ static void setlayout(const Arg *arg);
++static void setmark(Client *c);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static void swapclient(const Arg *arg);
++static void swapfocus(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglemark(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -268,6 +272,7 @@ static Display *dpy;
+ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
++static Client *mark;
+
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+@@ -796,7 +801,10 @@ focus(Client *c)
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, 1);
+- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
++ if (c == mark)
++ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColMark].pixel);
++ else
++ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ setfocus(c);
+ } else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+@@ -1052,7 +1060,10 @@ manage(Window w, XWindowAttributes *wa)
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+- XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
++ if (c == mark)
++ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColMark].pixel);
++ else
++ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatewindowtype(c);
+ updatesizehints(c);
+@@ -1512,6 +1523,23 @@ setlayout(const Arg *arg)
+ drawbar(selmon);
+ }
+
++void
++setmark(Client *c)
++{
++ if (c == mark)
++ return;
++ if (mark) {
++ XSetWindowBorder(dpy, mark->win, scheme[mark == selmon->sel
++ ? SchemeSel : SchemeNorm][ColBorder].pixel);
++ mark = 0;
++ }
++ if (c) {
++ XSetWindowBorder(dpy, c->win, scheme[c == selmon->sel
++ ? SchemeSel : SchemeNorm][ColMark].pixel);
++ mark = c;
++ }
++}
++
+ /* arg > 1.0 will set mfact absolutely */
+ void
+ setmfact(const Arg *arg)
+@@ -1570,7 +1598,7 @@ setup(void)
+ /* init appearance */
+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ for (i = 0; i < LENGTH(colors); i++)
+- scheme[i] = drw_scm_create(drw, colors[i], 3);
++ scheme[i] = drw_scm_create(drw, colors[i], 4);
+ /* init bars */
+ updatebars();
+ updatestatus();
+@@ -1653,6 +1681,75 @@ spawn(const Arg *arg)
+ }
+ }
+
++void
++swapclient(const Arg *arg)
++{
++ Client *s, *m, t;
++
++ if (!mark || !selmon->sel || mark == selmon->sel
++ || !selmon->lt[selmon->sellt]->arrange)
++ return;
++ s = selmon->sel;
++ m = mark;
++ t = *s;
++ strcpy(s->name, m->name);
++ s->win = m->win;
++ s->x = m->x;
++ s->y = m->y;
++ s->w = m->w;
++ s->h = m->h;
++
++ m->win = t.win;
++ strcpy(m->name, t.name);
++ m->x = t.x;
++ m->y = t.y;
++ m->w = t.w;
++ m->h = t.h;
++
++ selmon->sel = m;
++ mark = s;
++ focus(s);
++ setmark(m);
++
++ arrange(s->mon);
++ if (s->mon != m->mon) {
++ arrange(m->mon);
++ }
++}
++
++void
++swapfocus(const Arg *arg)
++{
++ Client *t;
++
++ if (!selmon->sel || !mark || selmon->sel == mark)
++ return;
++ t = selmon->sel;
++ if (mark->mon != selmon) {
++ unfocus(selmon->sel, 0);
++ selmon = mark->mon;
++ }
++ if (ISVISIBLE(mark)) {
++ focus(mark);
++ restack(selmon);
++ } else {
++ selmon->seltags ^= 1;
++ selmon->tagset[selmon->seltags] = mark->tags;
++ focus(mark);
++ arrange(selmon);
++ }
++ setmark(t);
++}
++
++void
++togglemark(const Arg *arg)
++{
++ if (!selmon->sel)
++ return;
++ setmark(selmon->sel == mark ? 0 : selmon->sel);
++}
++
++
+ void
+ tag(const Arg *arg)
+ {
+@@ -1755,7 +1852,10 @@ unfocus(Client *c, int setfocus)
+ if (!c)
+ return;
+ grabbuttons(c, 0);
+- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
++ if (c == mark)
++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColMark].pixel);
++ else
++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+@@ -1768,6 +1868,9 @@ unmanage(Client *c, int destroyed)
+ Monitor *m = c->mon;
+ XWindowChanges wc;
+
++ if (c == mark)
++ setmark(0);
++
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+--
+2.28.0
diff --git a/dwm/patches/dwm-movecenter-6.5.diff b/dwm/patches/dwm-movecenter-6.5.diff
new file mode 100644
index 0000000..b24977a
--- /dev/null
+++ b/dwm/patches/dwm-movecenter-6.5.diff
@@ -0,0 +1,41 @@
+diff --git a/config.def.h b/config.def.h
+index 9efa774..89a958a 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -85,6 +85,7 @@ static const Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY, XK_x, movecenter, {0} },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..ad534ad 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -184,6 +184,7 @@ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
++static void movecenter(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *c);
+ static void propertynotify(XEvent *e);
+@@ -1202,6 +1203,16 @@ movemouse(const Arg *arg)
+ }
+ }
+
++void
++movecenter(const Arg *arg)
++{
++ if (selmon->sel) {
++ selmon->sel->x = selmon->sel->mon->mx + (selmon->sel->mon->mw - WIDTH(selmon->sel)) / 2;
++ selmon->sel->y = selmon->sel->mon->my + (selmon->sel->mon->mh - HEIGHT(selmon->sel)) / 2;
++ arrange(selmon);
++ }
++}
++
+ Client *
+ nexttiled(Client *c)
+ {
diff --git a/dwm/patches/dwm-multimon-1-monitor_marker-6.4.diff b/dwm/patches/dwm-multimon-1-monitor_marker-6.4.diff
new file mode 100644
index 0000000..ea4b851
--- /dev/null
+++ b/dwm/patches/dwm-multimon-1-monitor_marker-6.4.diff
@@ -0,0 +1,194 @@
+# From c13f9b5a379422525ec7f714d83a1cbb0e3251c2 Mon Sep 17 00:00:00 2001
+# From: "Gary B. Genett" <me@garybgenett.net>
+# Date: Sun, 19 Feb 2023 08:56:42 -0800
+# Subject: added monitor marker to bar
+# MIME-Version: 1.0
+# Content-Type: multipart/mixed; boundary="------------2.37.4"
+#
+# This is a multi-part message in MIME format.
+# --------------2.37.4
+# Content-Type: text/plain; charset=UTF-8; format=fixed
+# Content-Transfer-Encoding: 8bit
+#
+# ---
+# config.def.h | 2 ++
+# dwm.c | 12 +++++++++++-
+# 2 files changed, 13 insertions(+), 1 deletion(-)
+#
+#
+# --------------2.37.4
+# Content-Type: text/x-patch; name="0001-added-monitor-marker-to-bar.patch"
+# Content-Transfer-Encoding: 8bit
+# Content-Disposition: attachment; filename="0001-added-monitor-marker-to-bar.patch"
+
+diff --git a/config.def.h b/config.def.h
+index 9efa7744b39c8b0ff0cf09a504a2539910c2881c..9d549ce8628e1a7769ee2a3d5c0a4c6d56ce6931 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -96,20 +96,22 @@ static const Key keys[] = {
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
+ };
+
+ /* button definitions */
+ /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+ static const Button buttons[] = {
+ /* click event mask button function argument */
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
++ { ClkMonNum, 0, Button1, focusmon, {.i = +1} },
++ { ClkMonNum, 0, Button3, focusmon, {.i = -1} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ };
+diff --git a/dwm.c b/dwm.c
+index c2bd8710544eb4b4e7eaa4a1307e1f1dfd8d16ba..bc5160a7d46ab07da82f0595abb7700debb2b891 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -57,21 +57,21 @@
+ #define TAGMASK ((1 << LENGTH(tags)) - 1)
+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
++enum { ClkTagBar, ClkLtSymbol, ClkMonNum, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+
+ typedef union {
+ int i;
+ unsigned int ui;
+ float f;
+ const void *v;
+ } Arg;
+
+ typedef struct {
+@@ -106,20 +106,21 @@ typedef struct {
+ const Arg arg;
+ } Key;
+
+ typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
+ } Layout;
+
+ struct Monitor {
+ char ltsymbol[16];
++ char monmark[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 */
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+ int showbar;
+@@ -434,20 +435,22 @@ buttonpress(XEvent *e)
+ if (ev->window == selmon->barwin) {
+ i = x = 0;
+ do
+ 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 + TEXTW(selmon->ltsymbol))
+ click = ClkLtSymbol;
++ else if (ev->x < x + TEXTW(selmon->ltsymbol) + TEXTW(selmon->monmark))
++ click = ClkMonNum;
+ else if (ev->x > selmon->ww - (int)TEXTW(stext))
+ click = ClkStatusText;
+ else
+ click = ClkWinTitle;
+ } else if ((c = wintoclient(ev->window))) {
+ focus(c);
+ restack(selmon);
+ XAllowEvents(dpy, ReplayPointer, CurrentTime);
+ click = ClkClientWin;
+ }
+@@ -637,20 +640,22 @@ createmon(void)
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
++ /* this is actually set in updategeom, to avoid a race condition */
++// snprintf(m->monmark, sizeof(m->monmark), "(%d)", m->num);
+ return m;
+ }
+
+ void
+ destroynotify(XEvent *e)
+ {
+ Client *c;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+ if ((c = wintoclient(ev->window)))
+@@ -726,20 +731,23 @@ drawbar(Monitor *m)
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+ urg & 1 << i);
+ x += w;
+ }
+ w = TEXTW(m->ltsymbol);
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
++ w = TEXTW(m->monmark);
++ drw_setscheme(drw, scheme[SchemeNorm]);
++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->monmark, 0);
+
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, x, 0, w, bh, 1, 1);
+@@ -1886,20 +1894,22 @@ updategeom(void)
+ else
+ mons = createmon();
+ }
+ for (i = 0, m = mons; i < nn && m; m = m->next, i++)
+ if (i >= n
+ || unique[i].x_org != m->mx || unique[i].y_org != m->my
+ || unique[i].width != m->mw || unique[i].height != m->mh)
+ {
+ dirty = 1;
+ m->num = i;
++ /* this is ugly, but it is a race condition otherwise */
++ snprintf(m->monmark, sizeof(m->monmark), "(%d)", m->num);
+ m->mx = m->wx = unique[i].x_org;
+ m->my = m->wy = unique[i].y_org;
+ m->mw = m->ww = unique[i].width;
+ m->mh = m->wh = unique[i].height;
+ updatebarpos(m);
+ }
+ /* removed monitors if n > nn */
+ for (i = nn; i < n; i++) {
+ for (m = mons; m && m->next; m = m->next);
+ while ((c = m->clients)) {
+
+--------------2.37.4--
diff --git a/dwm/patches/dwm-multimon-2-unified_view-6.4.diff b/dwm/patches/dwm-multimon-2-unified_view-6.4.diff
new file mode 100644
index 0000000..9815e92
--- /dev/null
+++ b/dwm/patches/dwm-multimon-2-unified_view-6.4.diff
@@ -0,0 +1,181 @@
+# From 96ebf3ddfad143aec93a7d2aa212389121ccae41 Mon Sep 17 00:00:00 2001
+# From: "Gary B. Genett" <me@garybgenett.net>
+# Date: Sun, 19 Feb 2023 08:57:30 -0800
+# Subject: added n*view wrappers, for unified multi-monitor
+# MIME-Version: 1.0
+# Content-Type: multipart/mixed; boundary="------------2.37.4"
+#
+# This is a multi-part message in MIME format.
+# --------------2.37.4
+# Content-Type: text/plain; charset=UTF-8; format=fixed
+# Content-Transfer-Encoding: 8bit
+#
+# ---
+# config.def.h | 5 +++++
+# dwm.c | 26 ++++++++++++++++++++++++++
+# 2 files changed, 31 insertions(+)
+#
+#
+# --------------2.37.4
+# Content-Type: text/x-patch; name="0002-added-n-view-wrappers-for-unified-multi-monitor.patch"
+# Content-Transfer-Encoding: 8bit
+# Content-Disposition: attachment; filename="0002-added-n-view-wrappers-for-unified-multi-monitor.patch"
+
+diff --git a/config.def.h b/config.def.h
+index 9d549ce8628e1a7769ee2a3d5c0a4c6d56ce6931..c59d27597a62ddf884baacded2830a318db1b45c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -38,24 +38,27 @@ static const int resizehints = 1; /* 1 means respect size hints in tiled resi
+ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+
+ static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile }, /* first entry is default */
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
+ };
+
+ /* key definitions */
++#define WINKEY Mod4Mask
+ #define MODKEY Mod1Mask
+ #define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
++ { MODKEY|WINKEY, KEY, nview, {.ui = 1 << TAG} }, \
++ { MODKEY|WINKEY|ControlMask, KEY, ntoggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << 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", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
+@@ -105,14 +108,16 @@ static const Button buttons[] = {
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkMonNum, 0, Button1, focusmon, {.i = +1} },
+ { ClkMonNum, 0, Button3, focusmon, {.i = -1} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
++ { ClkTagBar, MODKEY|WINKEY, Button1, nview, {0} },
++ { ClkTagBar, MODKEY|WINKEY, Button3, ntoggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ };
+
+diff --git a/dwm.c b/dwm.c
+index bc5160a7d46ab07da82f0595abb7700debb2b891..2cf8d78c22c64ff26eda6195b6bd503f213a4d5f 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -206,34 +206,36 @@ static void setmfact(const Arg *arg);
+ static void setup(void);
+ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void spawn(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
++static void ntoggleview(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 int updategeom(void);
+ static void updatenumlockmask(void);
+ static void updatesizehints(Client *c);
+ static void updatestatus(void);
+ static void updatetitle(Client *c);
+ static void updatewindowtype(Client *c);
+ static void updatewmhints(Client *c);
++static void nview(const Arg *arg);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -1743,20 +1745,32 @@ toggletag(const Arg *arg)
+ if (!selmon->sel)
+ return;
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ selmon->sel->tags = newtags;
+ focus(NULL);
+ arrange(selmon);
+ }
+ }
+
++void
++ntoggleview(const Arg *arg)
++{
++ const Arg n = {.i = +1};
++ const int mon = selmon->num;
++ do {
++ focusmon(&n);
++ toggleview(arg);
++ }
++ while (selmon->num != mon);
++}
++
+ void
+ toggleview(const Arg *arg)
+ {
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -2045,20 +2059,32 @@ updatewmhints(Client *c)
+ } else
+ c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
+ if (wmh->flags & InputHint)
+ c->neverfocus = !wmh->input;
+ else
+ c->neverfocus = 0;
+ XFree(wmh);
+ }
+ }
+
++void
++nview(const Arg *arg)
++{
++ const Arg n = {.i = +1};
++ const int mon = selmon->num;
++ do {
++ focusmon(&n);
++ view(arg);
++ }
++ while (selmon->num != mon);
++}
++
+ void
+ view(const Arg *arg)
+ {
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ focus(NULL);
+ arrange(selmon);
+
+--------------2.37.4--
diff --git a/dwm/patches/dwm-multimon-4-status_all-6.4.diff b/dwm/patches/dwm-multimon-4-status_all-6.4.diff
new file mode 100644
index 0000000..5059958
--- /dev/null
+++ b/dwm/patches/dwm-multimon-4-status_all-6.4.diff
@@ -0,0 +1,102 @@
+# From 34d7ca93ff7fff443f9cf0ce6ba6da6acbcfe06c Mon Sep 17 00:00:00 2001
+# From: "Gary B. Genett" <me@garybgenett.net>
+# Date: Sun, 19 Feb 2023 08:59:36 -0800
+# Subject: added statusall toggle
+# MIME-Version: 1.0
+# Content-Type: multipart/mixed; boundary="------------2.37.4"
+#
+# This is a multi-part message in MIME format.
+# --------------2.37.4
+# Content-Type: text/plain; charset=UTF-8; format=fixed
+# Content-Transfer-Encoding: 8bit
+#
+# ---
+# config.def.h | 1 +
+# dwm.c | 4 ++--
+# 2 files changed, 3 insertions(+), 2 deletions(-)
+#
+#
+# --------------2.37.4
+# Content-Type: text/x-patch; name="0004-added-statusall-toggle.patch"
+# Content-Transfer-Encoding: 8bit
+# Content-Disposition: attachment; filename="0004-added-statusall-toggle.patch"
+
+diff --git a/config.def.h b/config.def.h
+index a664c793845c4c7c0ebe8ac69c96885c76193819..fcfe8245a438686f276ffc9a4df17695382ed58b 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -29,20 +29,21 @@ static const Rule rules[] = {
+ /* class instance title tags mask isfloating monitor */
+ { "Gimp", NULL, NULL, 0, 1, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ };
+
+ /* layout(s) */
+ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+ static const int nmaster = 1; /* number of clients in master area */
+ static const int nviews = 3; /* mask of tags highlighted by default (tags 1-4) */
+ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
++static const int statusall = 1; /* 1 means status is shown in all bars, not just active monitor */
+ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+
+ static const float facts[1]; //static const float facts[] = { 0, 0.5 }; // = mfact // 50%
+ static const int masters[1]; //static const int masters[] = { 0, -1 }; // = nmaster // vertical stacking (for rotated monitor)
+ static const int views[1]; //static const int views[] = { 0, ~0 }; // = nviews // all tags
+ /* invert tags after nviews */ /* array dimentions can both be as big as needed */ // final highlighted tags
+ static const int toggles[1][1]; //static const int toggles[2][2] = { {0,8}, {~0,~0} }; // 2-4+9 // all (leave as views above)
+ static const int toggles[1][1] = {{~0}};
+
+ static const Layout layouts[] = {
+ /* symbol arrange function */
+diff --git a/dwm.c b/dwm.c
+index 93da0f4565d7a17ef96a1b167cfcb2c9f0ac6ad3..77ff310e03edbf42ac2dd55471962ce259b63071 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -709,21 +709,21 @@ drawbar(Monitor *m)
+ int x, w, tw = 0;
+ int boxs = drw->fonts->h / 9;
+ int boxw = drw->fonts->h / 6 + 2;
+ unsigned int i, occ = 0, urg = 0;
+ Client *c;
+
+ if (!m->showbar)
+ return;
+
+ /* draw status first so it can be overdrawn by tags later */
+- if (m == selmon) { /* status is only drawn on selected monitor */
++ if (m == selmon || statusall) { /* status is only drawn on selected monitor */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+ }
+
+ for (c = m->clients; c; c = c->next) {
+ occ |= c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
+ }
+@@ -2017,21 +2017,21 @@ updatesizehints(Client *c)
+ c->maxa = c->mina = 0.0;
+ c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+ c->hintsvalid = 1;
+ }
+
+ void
+ updatestatus(void)
+ {
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+ strcpy(stext, "dwm-"VERSION);
+- drawbar(selmon);
++ statusall ? drawbars() : drawbar(selmon);
+ }
+
+ void
+ updatetitle(Client *c)
+ {
+ if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
+ gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
+ if (c->name[0] == '\0') /* hack to mark broken clients */
+ strcpy(c->name, broken);
+ }
+
+--------------2.37.4--
diff --git a/dwm/patches/dwm-multimon-6-swap_focus-6.4.diff b/dwm/patches/dwm-multimon-6-swap_focus-6.4.diff
new file mode 100644
index 0000000..9bd091a
--- /dev/null
+++ b/dwm/patches/dwm-multimon-6-swap_focus-6.4.diff
@@ -0,0 +1,185 @@
+# From de73c72af0250f56f9ac30a5c3f4520da250282a Mon Sep 17 00:00:00 2001
+# From: "Gary B. Genett" <me@garybgenett.net>
+# Date: Sun, 19 Feb 2023 09:40:00 -0800
+# Subject: patches/swapfocus: dwm-swapfocus-20160731-56a31dc.diff
+# MIME-Version: 1.0
+# Content-Type: multipart/mixed; boundary="------------2.37.4"
+#
+# This is a multi-part message in MIME format.
+# --------------2.37.4
+# Content-Type: text/plain; charset=UTF-8; format=fixed
+# Content-Transfer-Encoding: 8bit
+#
+#
+# modified from sites: 38b351cf3689ff3fa4845d35ce9894fd9253dbb8
+# ---
+# config.def.h | 1 +
+# dwm.c | 19 ++++++++++++++++++-
+# 2 files changed, 19 insertions(+), 1 deletion(-)
+#
+#
+# --------------2.37.4
+# Content-Type: text/x-patch; name="0006-patches-swapfocus-dwm-swapfocus-20160731-56a31dc.dif.patch"
+# Content-Transfer-Encoding: 8bit
+# Content-Disposition: attachment; filename="0006-patches-swapfocus-dwm-swapfocus-20160731-56a31dc.dif.patch"
+
+diff --git a/config.def.h b/config.def.h
+index fd00f7080db9271912d0e4352434739d3c08e1b3..9a1118791c3a2f875b58bf3979db5074416b8634 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -79,20 +79,21 @@ static const Key keys[] = {
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_j, pushdown, {0} },
+ { MODKEY|ShiftMask, XK_k, pushup, {0} },
+ { 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, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
++ { MODKEY|ShiftMask, XK_Tab, swapfocus, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {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 } },
+diff --git a/dwm.c b/dwm.c
+index 5aa229611a27b8aa943308314b494c10e2364137..ac52b8c25991a073db15b55fae774e9c47a05708 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -203,20 +203,21 @@ static int sendevent(Client *c, Atom proto);
+ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
+ static void setlayout(const Arg *arg);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void spawn(const Arg *arg);
++static void swapfocus(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void ntoggleview(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+ static void unmanage(Client *c, int destroyed);
+@@ -235,20 +236,21 @@ static void nview(const Arg *arg);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
+ static void reset_view(const Arg *arg);
+
+ /* variables */
++static Client *prevclient = NULL;
+ static const char broken[] = "broken";
+ static char stext[256];
+ static int screen;
+ static int sw, sh; /* X display screen geometry width, height */
+ static int bh; /* bar height */
+ 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,
+@@ -1721,20 +1723,32 @@ spawn(const Arg *arg)
+ dmenumon[0] = '0' + selmon->num;
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
+ }
+ }
+
++void
++swapfocus(const Arg *arg)
++{
++ Client *c;
++
++ for(c = selmon->clients; c && c != prevclient; c = c->next) ;
++ if(c == prevclient) {
++ focus(prevclient);
++ restack(prevclient->mon);
++ }
++}
++
+ void
+ tag(const Arg *arg)
+ {
+ if (selmon->sel && arg->ui & TAGMASK) {
+ selmon->sel->tags = arg->ui & TAGMASK;
+ focus(NULL);
+ arrange(selmon);
+ }
+ }
+
+@@ -1834,20 +1848,21 @@ toggleview(const Arg *arg)
+ focus(NULL);
+ arrange(selmon);
+ }
+ }
+
+ void
+ unfocus(Client *c, int setfocus)
+ {
+ if (!c)
+ return;
++ prevclient = c;
+ grabbuttons(c, 0);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+ }
+
+ void
+ unmanage(Client *c, int destroyed)
+@@ -2213,25 +2228,27 @@ int
+ xerrorstart(Display *dpy, XErrorEvent *ee)
+ {
+ die("dwm: another window manager is already running");
+ return -1;
+ }
+
+ void
+ zoom(const Arg *arg)
+ {
+ Client *c = selmon->sel;
++ prevclient = nexttiled(selmon->clients);
+
+ if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
+ return;
+ if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
+- return;
++ if (!c || !(c = prevclient = nexttiled(c->next)))
++ return;
+ pop(c);
+ }
+
+ void
+ reset_view(const Arg *arg) {
+ const int mon = selmon->num;
+ Arg n = {.i = +1}; // focusmon(next monitor)
+ Arg m = {.f = 0}; // mfact -> facts[]
+ Arg i = {.i = 0}; // nmaster -> masters[]
+ Arg v = {.ui = 0}; // nviews -> views[]
+
+--------------2.37.4--
diff --git a/dwm/patches/dwm-multimon-7-focus_on_active-6.4.diff b/dwm/patches/dwm-multimon-7-focus_on_active-6.4.diff
new file mode 100644
index 0000000..958ae04
--- /dev/null
+++ b/dwm/patches/dwm-multimon-7-focus_on_active-6.4.diff
@@ -0,0 +1,59 @@
+# From ef123521987ec72df95a05542f6558999b673863 Mon Sep 17 00:00:00 2001
+# From: "Gary B. Genett" <me@garybgenett.net>
+# Date: Sun, 19 Feb 2023 09:09:23 -0800
+# Subject: patches/focusonnetactive: dwm-focusonnetactive-6.2.diff
+# MIME-Version: 1.0
+# Content-Type: multipart/mixed; boundary="------------2.37.4"
+#
+# This is a multi-part message in MIME format.
+# --------------2.37.4
+# Content-Type: text/plain; charset=UTF-8; format=fixed
+# Content-Transfer-Encoding: 8bit
+#
+#
+# modified from sites: 38b351cf3689ff3fa4845d35ce9894fd9253dbb8
+# used old dwm code instead: bb3bd6fec37174e8d4bb9457ca815c00609e5157
+# ---
+# dwm.c | 7 +++++--
+# 1 file changed, 5 insertions(+), 2 deletions(-)
+#
+#
+# --------------2.37.4
+# Content-Type: text/x-patch; name="0007-patches-focusonnetactive-dwm-focusonnetactive-6.2.di.patch"
+# Content-Transfer-Encoding: 8bit
+# Content-Disposition: attachment; filename="0007-patches-focusonnetactive-dwm-focusonnetactive-6.2.di.patch"
+
+diff --git a/dwm.c b/dwm.c
+index ac52b8c25991a073db15b55fae774e9c47a05708..3294c2fe53785473397b6e978c79a704cb7e8f25 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -530,22 +530,25 @@ clientmessage(XEvent *e)
+ Client *c = wintoclient(cme->window);
+
+ if (!c)
+ return;
+ if (cme->message_type == netatom[NetWMState]) {
+ if (cme->data.l[1] == netatom[NetWMFullscreen]
+ || cme->data.l[2] == netatom[NetWMFullscreen])
+ setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ } else if (cme->message_type == netatom[NetActiveWindow]) {
+- if (c != selmon->sel && !c->isurgent)
+- seturgent(c, 1);
++ if (!ISVISIBLE(c)) {
++ c->mon->seltags ^= 1;
++ c->mon->tagset[c->mon->seltags] = c->tags;
++ }
++ pop(c);
+ }
+ }
+
+ void
+ configure(Client *c)
+ {
+ XConfigureEvent ce;
+
+ ce.type = ConfigureNotify;
+ ce.display = dpy;
+
+--------------2.37.4--
diff --git a/dwm/patches/dwm-multiple-dynamic-scratchpads.diff b/dwm/patches/dwm-multiple-dynamic-scratchpads.diff
new file mode 100644
index 0000000..22d0000
--- /dev/null
+++ b/dwm/patches/dwm-multiple-dynamic-scratchpads.diff
@@ -0,0 +1,207 @@
+diff --git a/config.def.h b/config.def.h
+index a2ac963..1c82453 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -95,6 +95,13 @@ static Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_s, scratchpad_show, {.i = 1} },
++ { MODKEY, XK_y, scratchpad_show, {.i = 2} },
++ { MODKEY, XK_u, scratchpad_show, {.i = 3} },
++ { MODKEY|ShiftMask, XK_s, scratchpad_hide, {.i = 1} },
++ { MODKEY|ShiftMask, XK_y, scratchpad_hide, {.i = 2} },
++ { MODKEY|ShiftMask, XK_u, scratchpad_hide, {.i = 3} },
++ { MODKEY|ShiftMask, XK_r, scratchpad_remove, {0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index 5f16260..202038f 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -195,6 +195,11 @@ static void resizemouse(const Arg *arg);
+ static void restack(Monitor *m);
+ static void run(void);
+ static void scan(void);
++static void scratchpad_hide();
++static void scratchpad_remove();
++static void scratchpad_show();
++static void scratchpad_show_client(Client *c);
++static void scratchpad_show_first(int scratchNum);
+ static int sendevent(Client *c, Atom proto);
+ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+@@ -269,11 +274,19 @@ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
+
++/* scratchpad */
++#define SCRATCHPAD_MASK_1 (1u << sizeof tags / sizeof * tags)
++#define SCRATCHPAD_MASK_2 (1u << (sizeof tags / sizeof * tags + 1))
++#define SCRATCHPAD_MASK_3 (1u << (sizeof tags / sizeof * tags + 2))
++static int scratchpad_hide_flag = 0;
++static Client *scratchpad_last_showed_1 = NULL;
++static Client *scratchpad_last_showed_2 = NULL;
++static Client *scratchpad_last_showed_3 = NULL;
+ /* 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]; };
++struct NumTags { char limitexceeded[LENGTH(tags) > 28 ? -1 : 1]; };
+
+ /* function implementations */
+ void
+@@ -309,7 +322,9 @@ applyrules(Client *c)
+ XFree(ch.res_class);
+ if (ch.res_name)
+ XFree(ch.res_name);
++ if(c->tags != SCRATCHPAD_MASK_1 && c->tags != SCRATCHPAD_MASK_2 && c->tags != SCRATCHPAD_MASK_3) {
+ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
++ }
+ }
+
+ int
+@@ -1412,6 +1427,124 @@ scan(void)
+ }
+ }
+
++static void scratchpad_hide(const Arg *arg) {
++ if(scratchpad_hide_flag < 4) {
++ if(arg->i == 1) {
++ if(selmon->sel) {
++ selmon->sel->tags = SCRATCHPAD_MASK_1;
++ selmon->sel->isfloating = 1;
++ focus(NULL);
++ arrange(selmon);
++ scratchpad_hide_flag++;
++ }
++ }
++ else if(arg->i == 2) {
++ if(selmon->sel) {
++ selmon->sel->tags = SCRATCHPAD_MASK_2;
++ selmon->sel->isfloating = 1;
++ focus(NULL);
++ arrange(selmon);
++ scratchpad_hide_flag++;
++ }
++ }
++ else if(arg->i == 3) {
++ if(selmon->sel) {
++ selmon->sel->tags = SCRATCHPAD_MASK_3;
++ selmon->sel->isfloating = 1;
++ focus(NULL);
++ arrange(selmon);
++ scratchpad_hide_flag++;
++ }
++ }
++ }
++}
++
++static void scratchpad_remove() {
++ if(selmon->sel && (scratchpad_last_showed_1 != NULL || scratchpad_last_showed_2 != NULL ||scratchpad_last_showed_3 != NULL) && (selmon->sel == scratchpad_last_showed_1 || selmon->sel == scratchpad_last_showed_2 || selmon->sel == scratchpad_last_showed_3)) {
++ if(scratchpad_last_showed_1 == selmon->sel) {
++ scratchpad_last_showed_1 = NULL;
++ scratchpad_hide_flag--;
++ }
++ else if(scratchpad_last_showed_2 == selmon->sel) {
++ scratchpad_last_showed_2 = NULL;
++ scratchpad_hide_flag--;
++ }
++ else if(scratchpad_last_showed_3 == selmon->sel) {
++ scratchpad_last_showed_3 = NULL;
++ scratchpad_hide_flag--;
++ }
++ }
++}
++
++static void scratchpad_show(const Arg *arg) {
++ if(arg->i == 1) {
++ if(scratchpad_last_showed_1 == NULL) {
++ scratchpad_show_first(arg->i);
++ }
++ else {
++ if(scratchpad_last_showed_1->tags != SCRATCHPAD_MASK_1) {
++ scratchpad_last_showed_1->tags = SCRATCHPAD_MASK_1;
++ focus(NULL);
++ arrange(selmon);
++ }
++ else {
++ scratchpad_show_first(arg->i);
++ }
++ }
++ }
++ else if(arg->i == 2) {
++ if(scratchpad_last_showed_2 == NULL) {
++ scratchpad_show_first(arg->i);
++ }
++ else {
++ if(scratchpad_last_showed_2->tags != SCRATCHPAD_MASK_2) {
++ scratchpad_last_showed_2->tags = SCRATCHPAD_MASK_2;
++ focus(NULL);
++ arrange(selmon);
++ }
++ else {
++ scratchpad_show_first(arg->i);
++ }
++ }
++ }
++ else if(arg->i == 3) {
++ if(scratchpad_last_showed_3 == NULL) {
++ scratchpad_show_first(arg->i);
++ }
++ else {
++ if(scratchpad_last_showed_3->tags != SCRATCHPAD_MASK_3) {
++ scratchpad_last_showed_3->tags = SCRATCHPAD_MASK_3;
++ focus(NULL);
++ arrange(selmon);
++ }
++ else {
++ scratchpad_show_first(arg->i);
++ }
++ }
++ }
++}
++
++static void scratchpad_show_client(Client *c) {
++ c->tags = selmon->tagset[selmon->seltags];
++ focus(c);
++ arrange(selmon);
++}
++
++static void scratchpad_show_first(int scratchNum) {
++ for(Client *c = selmon->clients; c !=NULL; c = c->next) {
++ if(c->tags == SCRATCHPAD_MASK_1 && scratchNum == 1) {
++ scratchpad_last_showed_1 = c;
++ scratchpad_show_client(c);
++ } else if(c->tags == SCRATCHPAD_MASK_2 && scratchNum == 2) {
++ scratchpad_last_showed_2 = c;
++ scratchpad_show_client(c);
++ } else if(c->tags == SCRATCHPAD_MASK_3 && scratchNum == 3) {
++ scratchpad_last_showed_3 = c;
++ scratchpad_show_client(c);
++ }
++ }
++}
++
+ void
+ sendmon(Client *c, Monitor *m)
+ {
+@@ -1785,6 +1918,16 @@ unmanage(Client *c, int destroyed)
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
++ if(scratchpad_last_showed_1 == c) {
++ scratchpad_last_showed_1 = NULL;
++ }
++ if(scratchpad_last_showed_2 == c) {
++ scratchpad_last_showed_2 = NULL;
++ }
++ if(scratchpad_last_showed_3 == c) {
++ scratchpad_last_showed_3 = NULL;
++ }
++
+ free(c);
+ focus(NULL);
+ updateclientlist();
diff --git a/dwm/patches/dwm-pertag_with_sel-20231003-9f88553.diff b/dwm/patches/dwm-pertag_with_sel-20231003-9f88553.diff
new file mode 100644
index 0000000..70e3b5d
--- /dev/null
+++ b/dwm/patches/dwm-pertag_with_sel-20231003-9f88553.diff
@@ -0,0 +1,214 @@
+# From b47a32da69a1bb6f60b9c81619f3e504278cc780 Mon Sep 17 00:00:00 2001
+# From: Leonardo-Boss <70913810+Leonardo-Boss@users.noreply.github.com>
+# Date: Tue, 3 Oct 2023 12:33:58 -0300
+# Subject: [PATCH] pertag with last selection
+#
+# ---
+# dwm.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
+# 1 file changed, 90 insertions(+), 7 deletions(-)
+
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..0e4d444 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -111,6 +111,7 @@ typedef struct {
+ void (*arrange)(Monitor *);
+ } Layout;
+
++typedef struct Pertag Pertag;
+ struct Monitor {
+ char ltsymbol[16];
+ float mfact;
+@@ -130,6 +131,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ Pertag *pertag;
+ };
+
+ typedef struct {
+@@ -271,6 +273,16 @@ static Window root, wmcheckwin;
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
++struct Pertag {
++ unsigned int curtag, prevtag; /* current and previous tag */
++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
++ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
++ Client *sel[LENGTH(tags) + 1]; /* selected client */
++};
++
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+@@ -634,6 +646,7 @@ Monitor *
+ createmon(void)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+@@ -644,6 +657,20 @@ createmon(void)
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
++ m->pertag = ecalloc(1, sizeof(Pertag));
++ m->pertag->curtag = m->pertag->prevtag = 1;
++
++ for (i = 0; i <= LENGTH(tags); i++) {
++ m->pertag->nmasters[i] = m->nmaster;
++ m->pertag->mfacts[i] = m->mfact;
++
++ m->pertag->ltidxs[i][0] = m->lt[0];
++ m->pertag->ltidxs[i][1] = m->lt[1];
++ m->pertag->sellts[i] = m->sellt;
++
++ m->pertag->showbars[i] = m->showbar;
++ }
++
+ return m;
+ }
+
+@@ -808,6 +835,7 @@ focus(Client *c)
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+ selmon->sel = c;
++ selmon->pertag->sel[selmon->pertag->curtag] = c;
+ drawbars();
+ }
+
+@@ -980,7 +1008,7 @@ grabkeys(void)
+ void
+ incnmaster(const Arg *arg)
+ {
+- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
+ }
+
+@@ -1511,9 +1539,9 @@ void
+ setlayout(const Arg *arg)
+ {
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+- selmon->sellt ^= 1;
++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
+ if (arg && arg->v)
+- selmon->lt[selmon->sellt] = (Layout *)arg->v;
++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
+ if (selmon->sel)
+ arrange(selmon);
+@@ -1532,7 +1560,7 @@ setmfact(const Arg *arg)
+ f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+ if (f < 0.05 || f > 0.95)
+ return;
+- selmon->mfact = f;
++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
+ arrange(selmon);
+ }
+
+@@ -1715,7 +1743,7 @@ tile(Monitor *m)
+ void
+ togglebar(const Arg *arg)
+ {
+- selmon->showbar = !selmon->showbar;
++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
+ updatebarpos(selmon);
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+ arrange(selmon);
+@@ -1754,9 +1782,33 @@ void
+ toggleview(const Arg *arg)
+ {
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
++ int i;
+
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
++
++ if (newtagset == ~0) {
++ selmon->pertag->prevtag = selmon->pertag->curtag;
++ selmon->pertag->curtag = 0;
++ }
++
++ /* test if the user did not select the same tag */
++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
++ selmon->pertag->prevtag = selmon->pertag->curtag;
++ for (i = 0; !(newtagset & 1 << i); i++) ;
++ selmon->pertag->curtag = i + 1;
++ }
++
++ /* apply settings for this view */
++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
++
++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
++ togglebar(NULL);
++
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -1778,9 +1830,14 @@ unfocus(Client *c, int setfocus)
+ void
+ unmanage(Client *c, int destroyed)
+ {
++ int i;
+ Monitor *m = c->mon;
+ XWindowChanges wc;
+
++ for (i = 0; i < LENGTH(tags) + 1; i++)
++ if (c->mon->pertag->sel[i] == c)
++ c->mon->pertag->sel[i] = NULL;
++
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+@@ -2053,12 +2110,38 @@ updatewmhints(Client *c)
+ void
+ view(const Arg *arg)
+ {
++ int i;
++ unsigned int tmptag;
++
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+- if (arg->ui & TAGMASK)
++ if (arg->ui & TAGMASK) {
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+- focus(NULL);
++ selmon->pertag->prevtag = selmon->pertag->curtag;
++
++ if (arg->ui == ~0)
++ selmon->pertag->curtag = 0;
++ else {
++ for (i = 0; !(arg->ui & 1 << i); i++) ;
++ selmon->pertag->curtag = i + 1;
++ }
++ } else {
++ tmptag = selmon->pertag->prevtag;
++ selmon->pertag->prevtag = selmon->pertag->curtag;
++ selmon->pertag->curtag = tmptag;
++ }
++
++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
++
++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
++ togglebar(NULL);
++
++ focus(selmon->pertag->sel[selmon->pertag->curtag]);
+ arrange(selmon);
+ }
+
+--
+2.41.0
diff --git a/dwm/patches/dwm-preserveonrestart-6.3.diff b/dwm/patches/dwm-preserveonrestart-6.3.diff
new file mode 100644
index 0000000..9fed4d8
--- /dev/null
+++ b/dwm/patches/dwm-preserveonrestart-6.3.diff
@@ -0,0 +1,118 @@
+# From 713fa8650f5a20006451ebcccf57a4512e83bae8 Mon Sep 17 00:00:00 2001
+# From: Arda Atci <arda@phytech.io>
+# Date: Wed, 18 May 2022 17:23:16 +0300
+# Subject: [PATCH] preserve clients on old tags when renewing dwm
+#
+# By default, when dwm is recompiled-restarted all clients will
+# lose it's current tag and collapse to first tag. This patch preserves
+# clients on old tags, however note that layout order is not preserved.
+#
+# ---
+# dwm.c | 38 +++++++++++++++++++++++++++++++++++++-
+# 1 file changed, 37 insertions(+), 1 deletion(-)
+
+diff --git a/dwm.c b/dwm.c
+index a96f33c..a12e0bd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -62,7 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++ NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+@@ -198,6 +198,7 @@ static void scan(void);
+ static int sendevent(Client *c, Atom proto);
+ 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 setlayout(const Arg *arg);
+@@ -1060,6 +1061,26 @@ manage(Window w, XWindowAttributes *wa)
+ updatewindowtype(c);
+ updatesizehints(c);
+ updatewmhints(c);
++ {
++ int format;
++ unsigned long *data, n, extra;
++ Monitor *m;
++ Atom atom;
++ if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL,
++ &atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2) {
++ c->tags = *data;
++ for (m = mons; m; m = m->next) {
++ if (m->num == *(data+1)) {
++ c->mon = m;
++ break;
++ }
++ }
++ }
++ if (n > 0)
++ XFree(data);
++ }
++ setclienttagprop(c);
++
+ XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ grabbuttons(c, 0);
+ if (!c->isfloating)
+@@ -1423,6 +1444,7 @@ sendmon(Client *c, Monitor *m)
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ attach(c);
+ attachstack(c);
++ setclienttagprop(c);
+ focus(NULL);
+ arrange(NULL);
+ }
+@@ -1566,6 +1588,7 @@ setup(void)
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
++ netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
+ /* init cursors */
+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+@@ -1589,6 +1612,7 @@ setup(void)
+ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) netatom, NetLast);
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
++ XDeleteProperty(dpy, root, netatom[NetClientInfo]);
+ /* select events */
+ wa.cursor = cursor[CurNormal]->cursor;
+ wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
+@@ -1656,11 +1680,22 @@ spawn(const Arg *arg)
+ }
+ }
+
++void
++setclienttagprop(Client *c)
++{
++ long data[] = { (long) c->tags, (long) c->mon->num };
++ XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
++ PropModeReplace, (unsigned char *) data, 2);
++}
++
+ void
+ tag(const Arg *arg)
+ {
++ Client *c;
+ if (selmon->sel && arg->ui & TAGMASK) {
++ c = selmon->sel;
+ selmon->sel->tags = arg->ui & TAGMASK;
++ setclienttagprop(c);
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -1735,6 +1770,7 @@ toggletag(const Arg *arg)
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ selmon->sel->tags = newtags;
++ setclienttagprop(selmon->sel);
+ focus(NULL);
+ arrange(selmon);
+ }
+--
+2.36.1
diff --git a/dwm/patches/dwm-preventfocusshift-20240831-6.5.diff b/dwm/patches/dwm-preventfocusshift-20240831-6.5.diff
new file mode 100644
index 0000000..a779208
--- /dev/null
+++ b/dwm/patches/dwm-preventfocusshift-20240831-6.5.diff
@@ -0,0 +1,24 @@
+# From 554f5a8a2205a7c52280babf5685462d8991b038 Mon Sep 17 00:00:00 2001
+# From: Suleyman Farajli <suleyman@farajli.net>
+# Date: Sat, 31 Aug 2024 13:34:58 +0400
+# Subject: [PATCH] prevent focus shifting when a window is spawned in fullscreen
+#
+# ---
+# dwm.c | 2 ++
+# 1 file changed, 2 insertions(+)
+
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..31b5d07 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1080,6 +1080,8 @@ manage(Window w, XWindowAttributes *wa)
+ (unsigned char *) &(c->win), 1);
+ XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
+ setclientstate(c, NormalState);
++ if(selmon->sel && selmon->sel->isfullscreen && !c->isfloating)
++ setfullscreen(selmon->sel, 0);
+ if (c->mon == selmon)
+ unfocus(selmon->sel, 0);
+ c->mon->sel = c;
+--
+2.44.2
diff --git a/dwm/patches/dwm-refreshrate-20230826-9554a10.diff b/dwm/patches/dwm-refreshrate-20230826-9554a10.diff
new file mode 100644
index 0000000..aa93b19
--- /dev/null
+++ b/dwm/patches/dwm-refreshrate-20230826-9554a10.diff
@@ -0,0 +1,55 @@
+# From 9554a109e240789f76f0ece3e62f9014ceb8a4bc Mon Sep 17 00:00:00 2001
+# From: sewn <sewn@disroot.org>
+# Date: Sat, 26 Aug 2023 22:57:51 +0300
+# Subject: [PATCH] dwm: remove resize/move limitation
+#
+# we have modern machines, and we have high refresh rate monitors;
+# this makes resizing and moving windows have no limit when refreshing.
+# ---
+# dwm.c | 10 ----------
+# 1 file changed, 10 deletions(-)
+
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..4c00cbe 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1149,7 +1149,6 @@ movemouse(const Arg *arg)
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+- Time lasttime = 0;
+
+ if (!(c = selmon->sel))
+ return;
+@@ -1172,10 +1171,6 @@ movemouse(const Arg *arg)
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+- if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+- continue;
+- lasttime = ev.xmotion.time;
+-
+ nx = ocx + (ev.xmotion.x - x);
+ ny = ocy + (ev.xmotion.y - y);
+ if (abs(selmon->wx - nx) < snap)
+@@ -1304,7 +1299,6 @@ resizemouse(const Arg *arg)
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+- Time lasttime = 0;
+
+ if (!(c = selmon->sel))
+ return;
+@@ -1326,10 +1320,6 @@ resizemouse(const Arg *arg)
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+- if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+- continue;
+- lasttime = ev.xmotion.time;
+-
+ nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
+ nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
+ if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
+--
+2.42.0
diff --git a/dwm/patches/dwm-resetlayout-6.2.diff b/dwm/patches/dwm-resetlayout-6.2.diff
new file mode 100644
index 0000000..e3cd587
--- /dev/null
+++ b/dwm/patches/dwm-resetlayout-6.2.diff
@@ -0,0 +1,64 @@
+# From 4df827a2ec7820f41bdb8576cc39b55fbf35be44 Mon Sep 17 00:00:00 2001
+# From: Jack Bird <jack.bird@durham.ac.uk>
+# Date: Mon, 16 Aug 2021 23:25:16 +0100
+# Subject: [PATCH] Patch applies cleanly
+#
+# ---
+# config.def.h | 1 +
+# dwm.c | 15 +++++++++++++++
+# 2 files changed, 16 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..5d118cf 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -70,6 +70,7 @@ static Key keys[] = {
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
++ { MODKEY, XK_r, resetlayout, {0} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..77727ea 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -188,6 +188,7 @@ static void pop(Client *);
+ static void propertynotify(XEvent *e);
+ static void quit(const Arg *arg);
+ static Monitor *recttomon(int x, int y, int w, int h);
++static void resetlayout(const Arg *arg);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
+ static void resizeclient(Client *c, int x, int y, int w, int h);
+ static void resizemouse(const Arg *arg);
+@@ -1265,6 +1266,16 @@ recttomon(int x, int y, int w, int h)
+ return r;
+ }
+
++void
++resetlayout(const Arg *arg)
++{
++ Arg default_layout = {.v = &layouts[0]};
++ Arg default_mfact = {.f = mfact + 1};
++
++ setlayout(&default_layout);
++ setmfact(&default_mfact);
++}
++
+ void
+ resize(Client *c, int x, int y, int w, int h, int interact)
+ {
+@@ -1282,6 +1293,10 @@ resizeclient(Client *c, int x, int y, int w, int h)
+ c->oldw = c->w; c->w = wc.width = w;
+ c->oldh = c->h; c->h = wc.height = h;
+ wc.border_width = c->bw;
++
++ if ((nexttiled(c->mon->clients) == c) && !(nexttiled(c->next)))
++ resetlayout(NULL);
++
+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+ XSync(dpy, False);
+--
+2.32.0
diff --git a/dwm/patches/dwm-resetnmaster-pertag-6.3.diff b/dwm/patches/dwm-resetnmaster-pertag-6.3.diff
new file mode 100644
index 0000000..a3d12c0
--- /dev/null
+++ b/dwm/patches/dwm-resetnmaster-pertag-6.3.diff
@@ -0,0 +1,36 @@
+diff -r -u a/config.def.h b/config.def.h
+--- a/config.def.h 2022-01-07 06:42:18.000000000 -0500
++++ b/config.def.h 2022-01-23 16:03:42.521951418 -0500
+@@ -69,6 +69,7 @@
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
++ { MODKEY, XK_o, resetnmaster, {0} },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
+diff -r -u a/dwm.c b/dwm.c
+--- a/dwm.c 2022-01-23 16:06:01.221948285 -0500
++++ b/dwm.c 2022-01-23 16:05:35.949948855 -0500
+@@ -191,6 +191,7 @@
+ static void propertynotify(XEvent *e);
+ static void quit(const Arg *arg);
+ static Monitor *recttomon(int x, int y, int w, int h);
++static void resetnmaster(const Arg *arg);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
+ static void resizeclient(Client *c, int x, int y, int w, int h);
+ static void resizemouse(const Arg *arg);
+@@ -1296,6 +1297,13 @@
+ }
+
+ void
++resetnmaster(const Arg *arg)
++{
++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = 1;
++ arrange(selmon);
++}
++
++void
+ resize(Client *c, int x, int y, int w, int h, int interact)
+ {
+ if (applysizehints(c, &x, &y, &w, &h, interact))
diff --git a/dwm/patches/dwm-resizehere-20230824-e81f17d.diff b/dwm/patches/dwm-resizehere-20230824-e81f17d.diff
new file mode 100644
index 0000000..2e353f1
--- /dev/null
+++ b/dwm/patches/dwm-resizehere-20230824-e81f17d.diff
@@ -0,0 +1,60 @@
+# From d2824944615917697c18555a397bf84f2249a722 Mon Sep 17 00:00:00 2001
+# From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= <gutyina.gergo.2@gmail.com>
+# Date: Thu, 24 Aug 2023 15:06:56 +0200
+# Subject: [PATCH] Resize clients without wrapping the pointer
+#
+# ---
+# dwm.c | 14 +++++++-------
+# 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/dwm.c b/dwm.c
+index f1d86b2..8c661a2 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1300,7 +1300,7 @@ resizeclient(Client *c, int x, int y, int w, int h)
+ void
+ resizemouse(const Arg *arg)
+ {
+- int ocx, ocy, nw, nh;
++ int x, y, ocw, och, nw, nh;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+@@ -1311,12 +1311,13 @@ resizemouse(const Arg *arg)
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+- ocx = c->x;
+- ocy = c->y;
++ ocw = c->w;
++ och = c->h;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ return;
+- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
++ if(!getrootptr(&x, &y))
++ return;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+@@ -1330,8 +1331,8 @@ resizemouse(const Arg *arg)
+ continue;
+ lasttime = ev.xmotion.time;
+
+- nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
+- nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
++ nw = MAX(ocw + (ev.xmotion.x - x), 1);
++ nh = MAX(och + (ev.xmotion.y - y), 1);
+ if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
+ && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
+ {
+@@ -1344,7 +1345,6 @@ resizemouse(const Arg *arg)
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+--
+2.41.0
diff --git a/dwm/patches/dwm-restartsig-20180523-6.2.diff b/dwm/patches/dwm-restartsig-20180523-6.2.diff
new file mode 100644
index 0000000..5aa979b
--- /dev/null
+++ b/dwm/patches/dwm-restartsig-20180523-6.2.diff
@@ -0,0 +1,138 @@
+# From 2991f37f0aaf44b9f9b11e7893ff0af8eb88f649 Mon Sep 17 00:00:00 2001
+# From: Christopher Drelich <cd@cdrakka.com>
+# Date: Wed, 23 May 2018 22:50:38 -0400
+# Subject: [PATCH] Modifies quit to handle restarts and adds SIGHUP and SIGTERM
+# handlers.
+#
+# Modified quit() to restart if it receives arg .i = 1
+# MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that.
+#
+# Signal handlers were handled for SIGHUP and SIGTERM.
+# If dwm receives these signals it calls quit() with
+# arg .i = to 1 or 0, respectively.
+#
+# To restart dwm:
+# MOD+CTRL+SHIFT+Q
+# or
+# kill -HUP dwmpid
+#
+# To quit dwm cleanly:
+# MOD+SHIFT+Q
+# or
+# kill -TERM dwmpid
+# ---
+# config.def.h | 1 +
+# dwm.1 | 10 ++++++++++
+# dwm.c | 22 ++++++++++++++++++++++
+# 3 files changed, 33 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index a9ac303..e559429 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -94,6 +94,7 @@ static Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.1 b/dwm.1
+index 13b3729..36a331c 100644
+--- a/dwm.1
++++ b/dwm.1
+@@ -142,6 +142,9 @@ Add/remove all windows with nth tag to/from the view.
+ .TP
+ .B Mod1\-Shift\-q
+ Quit dwm.
++.TP
++.B Mod1\-Control\-Shift\-q
++Restart dwm.
+ .SS Mouse commands
+ .TP
+ .B Mod1\-Button1
+@@ -155,6 +158,13 @@ Resize focused window while dragging. Tiled windows will be toggled to the float
+ .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)
+diff --git a/dwm.c b/dwm.c
+index bb95e26..286eecd 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -205,6 +205,8 @@ static void setup(void);
+ static void seturgent(Client *c, int urg);
+ 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 void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+@@ -260,6 +262,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
+ [UnmapNotify] = unmapnotify
+ };
+ static Atom wmatom[WMLast], netatom[NetLast];
++static int restart = 0;
+ static int running = 1;
+ static Cur *cursor[CurLast];
+ static Clr **scheme;
+@@ -1248,6 +1251,7 @@ propertynotify(XEvent *e)
+ void
+ quit(const Arg *arg)
+ {
++ if(arg->i) restart = 1;
+ running = 0;
+ }
+
+@@ -1536,6 +1540,9 @@ setup(void)
+ /* clean up any zombies immediately */
+ sigchld(0);
+
++ signal(SIGHUP, sighup);
++ signal(SIGTERM, sigterm);
++
+ /* init screen */
+ screen = DefaultScreen(dpy);
+ sw = DisplayWidth(dpy, screen);
+@@ -1637,6 +1644,20 @@ sigchld(int unused)
+ }
+
+ void
++sighup(int unused)
++{
++ Arg a = {.i = 1};
++ quit(&a);
++}
++
++void
++sigterm(int unused)
++{
++ Arg a = {.i = 0};
++ quit(&a);
++}
++
++void
+ spawn(const Arg *arg)
+ {
+ if (arg->v == dmenucmd)
+@@ -2139,6 +2160,7 @@ main(int argc, char *argv[])
+ setup();
+ scan();
+ run();
++ if(restart) execvp(argv[0], argv);
+ cleanup();
+ XCloseDisplay(dpy);
+ return EXIT_SUCCESS;
+--
+2.7.4
diff --git a/dwm/patches/dwm-scratchpads-20200414-728d397b.diff b/dwm/patches/dwm-scratchpads-20200414-728d397b.diff
new file mode 100644
index 0000000..050e367
--- /dev/null
+++ b/dwm/patches/dwm-scratchpads-20200414-728d397b.diff
@@ -0,0 +1,198 @@
+# From 728d397b21982af88737277fd9d6939a7b558786 Mon Sep 17 00:00:00 2001
+# From: Christian Tenllado <ctenllado@gmail.com>
+# Date: Tue, 14 Apr 2020 23:31:15 +0200
+# Subject: [PATCH] Multiple scratchpads
+#
+# This patch enables multiple scratchpads, each with one asigned window.
+# This enables the same scratchpad workflow that you have in i3.
+#
+# Scratchpads are implemented as special tags, whose mask does not
+# apply to new spawned windows. To assign a window to a scratchpad you
+# have to set up a rule, as you do with regular tags.
+#
+# Windows tagged with scratchpad tags can be set floating or not in the
+# rules array. Most users would probably want them floating (i3 style),
+# but having them tiled does also perfectly work and might fit better the
+# DWM approach. In case they are set floating, the patch moves them to the
+# center of the screen whenever they are shown. The patch can easily be
+# modified to make this last feature configurable in the rules array (see
+# the center patch).
+#
+# The togglescratch function, borrowed from the previous scratchpad patch
+# and slightly modified, can be used to spawn a registered scratchpad
+# process or toggle its view. This function looks for a window tagged with
+# the selected scratchpad tag. If it is found its view is toggled. If it is
+# not found the corresponding registered command is spawned. The
+# config.def.h shows three examples of its use to spawn a terminal in the
+# first scratchpad tag, a second terminal running ranger on the second
+# scratchpad tag and the keepassxc application to manage passwords on a
+# third scratchpad tag.
+#
+# If you prefer to spawn your scratchpad applications from the startup
+# script, you might opt for binding keys to toggleview instead, as
+# scratchpads are just special tags (you may even extend the TAGKEYS macro
+# to generalize the key bindings).
+# ---
+# config.def.h | 28 ++++++++++++++++++++++++----
+# dwm.c | 43 +++++++++++++++++++++++++++++++++++++++++--
+# 2 files changed, 65 insertions(+), 6 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..06265e1 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -18,17 +18,33 @@ static const char *colors[][3] = {
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ };
+
++typedef struct {
++ const char *name;
++ const void *cmd;
++} Sp;
++const char *spcmd1[] = {"st", "-n", "spterm", "-g", "120x34", NULL };
++const char *spcmd2[] = {"st", "-n", "spfm", "-g", "144x41", "-e", "ranger", NULL };
++const char *spcmd3[] = {"keepassxc", NULL };
++static Sp scratchpads[] = {
++ /* name cmd */
++ {"spterm", spcmd1},
++ {"spranger", spcmd2},
++ {"keepassxc", spcmd3},
++};
++
+ /* tagging */
+ 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 */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ { "Gimp", NULL, NULL, 0, 1, -1 },
++ { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ { NULL, "spterm", NULL, SPTAG(0), 1, -1 },
++ { NULL, "spfm", NULL, SPTAG(1), 1, -1 },
++ { NULL, "keepassxc", NULL, SPTAG(2), 0, -1 },
+ };
+
+ /* layout(s) */
+@@ -59,6 +75,7 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
++
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+@@ -84,6 +101,9 @@ static Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY, XK_y, togglescratch, {.ui = 0 } },
++ { MODKEY, XK_u, togglescratch, {.ui = 1 } },
++ { MODKEY, XK_x, togglescratch, {.ui = 2 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+@@ -106,7 +126,7 @@ static Button buttons[] = {
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+- { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
++ { ClkClientWin, MODKEY, Button1, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..646aa1a 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -54,7 +54,10 @@
+ #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 NUMTAGS (LENGTH(tags) + LENGTH(scratchpads))
++#define TAGMASK ((1 << NUMTAGS) - 1)
++#define SPTAG(i) ((1 << LENGTH(tags)) << (i))
++#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+
+ /* enums */
+@@ -211,6 +214,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglescratch(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -299,6 +303,11 @@ applyrules(Client *c)
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
++ if ((r->tags & SPTAGMASK) && r->isfloating) {
++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
++ }
++
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+@@ -308,7 +317,7 @@ applyrules(Client *c)
+ 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];
++ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK);
+ }
+
+ int
+@@ -1616,6 +1625,10 @@ showhide(Client *c)
+ if (!c)
+ return;
+ if (ISVISIBLE(c)) {
++ if ((c->tags & SPTAGMASK) && c->isfloating) {
++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
++ }
+ /* show clients top down */
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
+@@ -1719,6 +1732,32 @@ togglefloating(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++togglescratch(const Arg *arg)
++{
++ Client *c;
++ unsigned int found = 0;
++ unsigned int scratchtag = SPTAG(arg->ui);
++ Arg sparg = {.v = scratchpads[arg->ui].cmd};
++
++ for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next);
++ if (found) {
++ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
++ if (newtagset) {
++ selmon->tagset[selmon->seltags] = newtagset;
++ focus(NULL);
++ arrange(selmon);
++ }
++ if (ISVISIBLE(c)) {
++ focus(c);
++ restack(selmon);
++ }
++ } else {
++ selmon->tagset[selmon->seltags] |= scratchtag;
++ spawn(&sparg);
++ }
++}
++
+ void
+ toggletag(const Arg *arg)
+ {
+--
+2.20.1
diff --git a/dwm/patches/dwm-sendmoncenter-20210805-138b405f.diff b/dwm/patches/dwm-sendmoncenter-20210805-138b405f.diff
new file mode 100644
index 0000000..3efdca4
--- /dev/null
+++ b/dwm/patches/dwm-sendmoncenter-20210805-138b405f.diff
@@ -0,0 +1,27 @@
+# From 449324adbe53240a734cb5f8f72763bb3419829a Mon Sep 17 00:00:00 2001
+# From: Rizqi Nur Assyaufi <bandithijo@gmail.com>
+# Date: Sat, 5 Aug 2021 00:04:32 +0800
+# Subject: [PATCH] [sendmoncenter] Send floating window to another monitor will
+# centered
+#
+# This patch will allows you to send floating window client to another monitor
+# will be centered position.
+# ---
+# dwm.c | 2 ++
+# 1 file changed, 2 insertions(+)
+
+diff --git a/dwm.c b/dwm.c
+index 5e4d494..c20023e 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1418,6 +1418,8 @@ sendmon(Client *c, Monitor *m)
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
++ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
++ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
+ attach(c);
+ attachstack(c);
+ focus(NULL);
+--
+2.31.1
diff --git a/dwm/patches/dwm-setborderpx-6.2.diff b/dwm/patches/dwm-setborderpx-6.2.diff
new file mode 100644
index 0000000..6a82087
--- /dev/null
+++ b/dwm/patches/dwm-setborderpx-6.2.diff
@@ -0,0 +1,90 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2020-05-12 02:17:20.070933833 +0200
++++ b/config.def.h 2020-05-13 03:27:51.018695798 +0200
+@@ -84,6 +84,9 @@ static Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY|ShiftMask, XK_minus, setborderpx, {.i = -1 } },
++ { MODKEY|ShiftMask, XK_plus, setborderpx, {.i = +1 } },
++ { MODKEY|ShiftMask, XK_numbersign, setborderpx, {.i = 0 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2020-05-12 02:17:20.070933833 +0200
++++ b/dwm.c 2020-05-14 00:17:35.047919771 +0200
+@@ -119,6 +119,7 @@ struct Monitor {
+ int by; /* bar geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
++ unsigned int borderpx;
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+@@ -196,6 +197,7 @@ static void run(void);
+ static void scan(void);
+ static int sendevent(Client *c, Atom proto);
+ static void sendmon(Client *c, Monitor *m);
++static void setborderpx(const Arg *arg);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
+@@ -638,6 +640,7 @@ createmon(void)
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
++ m->borderpx = borderpx;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+@@ -1047,7 +1050,7 @@ manage(Window w, XWindowAttributes *wa)
+ /* only fix client y-offset, if the client center might cover the bar */
+ c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
+ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+- c->bw = borderpx;
++ c->bw = c->mon->borderpx;
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+@@ -1424,6 +1427,40 @@ sendmon(Client *c, Monitor *m)
+ }
+
+ void
++setborderpx(const Arg *arg)
++{
++ Client *c;
++ int prev_borderpx = selmon->borderpx;
++
++ if (arg->i == 0)
++ selmon->borderpx = borderpx;
++ else if (selmon->borderpx + arg->i < 0)
++ selmon->borderpx = 0;
++ else
++ selmon->borderpx += arg->i;
++
++ for (c = selmon->clients; c; c = c->next)
++ {
++ if (c->bw + arg->i < 0)
++ c->bw = selmon->borderpx = 0;
++ else
++ c->bw = selmon->borderpx;
++ if (c->isfloating || !selmon->lt[selmon->sellt]->arrange)
++ {
++ if (arg->i != 0 && prev_borderpx + arg->i >= 0)
++ resize(c, c->x, c->y, c->w-(arg->i*2), c->h-(arg->i*2), 0);
++ else if (arg->i != 0)
++ resizeclient(c, c->x, c->y, c->w, c->h);
++ else if (prev_borderpx > borderpx)
++ resize(c, c->x, c->y, c->w + 2*(prev_borderpx - borderpx), c->h + 2*(prev_borderpx - borderpx), 0);
++ else if (prev_borderpx < borderpx)
++ resize(c, c->x, c->y, c->w-2*(borderpx - prev_borderpx), c->h-2*(borderpx - prev_borderpx), 0);
++ }
++ }
++ arrange(selmon);
++}
++
++void
+ setclientstate(Client *c, long state)
+ {
+ long data[] = { state, None };
diff --git a/dwm/patches/dwm-shift-tools-6.2.diff b/dwm/patches/dwm-shift-tools-6.2.diff
new file mode 100644
index 0000000..e9b9803
--- /dev/null
+++ b/dwm/patches/dwm-shift-tools-6.2.diff
@@ -0,0 +1,55 @@
+# From d57c8508c9f26be40667d402a2daaa2b27ae759f Mon Sep 17 00:00:00 2001
+# From: explosion-mental <explosion0mental@gmail.com>
+# Date: Wed, 11 Aug 2021 21:05:44 -0500
+# Subject: [PATCH] shift-tools-scratchpads - shifttag, moves the current selected client to
+# the adjacent tag - shifttagclients, moves the current selected client to the
+# adjacent tag that has at least one client else acts as shifttag -
+# shiftview, view adjacent tag - shiftviewclients, view the closes tag that has
+# a client. If none acts as shiftview - shiftboth, shifttag and shiftview.
+# Basically moves the window to the next/prev tag and follows it. -
+# shiftswaptags, its a shift implementation on the swaptags function (see
+# https://github.com/moizifty/DWM-Build/blob/65379c62640788881486401a0d8c79333751b02f/config.h#L48
+# for more details), which in short 'swaps tags' (swaps all clients with
+# the clients on the adjacent tag). A pretty useful example of this is
+# chosing a tag empty and sending all your clients to that tag. - swapfunction
+# is the 'helper' function for the shiftswaptags. remember that these functions
+# **shift**, which means you can go from tag 1 to 9 or 9 to 1. Also remember
+# that the default argument is 1 and you can change it.
+#
+# ---
+# config.def.h | 9 ++++
+# shift-tools-scratchpads.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++
+# 2 files changed, 144 insertions(+)
+# create mode 100644 shift-tools-scratchpads.c
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..1390d17 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -58,9 +58,14 @@ static const Layout layouts[] = {
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
++#include "shift-tools-scratchpads.c"
+
+ static Key keys[] = {
+ /* modifier key function argument */
++ { MODKEY, XK_o, shiftviewclients, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_o, shiftview, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_i, shiftview, { .i = -1 } },
++ { MODKEY, XK_i, shiftviewclients, { .i = -1 } },
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
+@@ -69,6 +74,10 @@ static Key keys[] = {
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
++ { MODKEY|ShiftMask, XK_h, shiftboth, { .i = -1 } },
++ { MODKEY|ControlMask, XK_h, shiftswaptags, { .i = -1 } },
++ { MODKEY|ControlMask, XK_l, shiftswaptags, { .i = +1 } },
++ { MODKEY|ShiftMask, XK_l, shiftboth, { .i = +1 } },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+2.32.0
diff --git a/dwm/patches/dwm-showselmon-6.2.diff b/dwm/patches/dwm-showselmon-6.2.diff
new file mode 100644
index 0000000..bbf837e
--- /dev/null
+++ b/dwm/patches/dwm-showselmon-6.2.diff
@@ -0,0 +1,46 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2020-07-04 13:56:23.316739958 +0200
++++ b/config.def.h 2020-07-04 13:57:58.020554340 +0200
+@@ -15,6 +15,7 @@ static const char col_cyan[] = "#
+ static const char *colors[][3] = {
+ /* fg bg border */
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
++ [SchemeInv] = { col_gray1, col_gray3, col_gray2 },
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ };
+
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2020-07-04 13:56:23.316739958 +0200
++++ b/dwm.c 2020-07-04 14:14:54.124590755 +0200
+@@ -59,7 +59,7 @@
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+-enum { SchemeNorm, SchemeSel }; /* color schemes */
++enum { SchemeNorm, SchemeInv, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+@@ -716,7 +716,12 @@ drawbar(Monitor *m)
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+ w = TEXTW(tags[i]);
+- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
++ if (m == selmon) {
++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
++ }
++ else {
++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeInv : SchemeNorm]);
++ }
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+@@ -730,7 +735,7 @@ drawbar(Monitor *m)
+
+ if ((w = m->ww - sw - x) > bh) {
+ if (m->sel) {
+- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
++ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeInv]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
diff --git a/dwm/patches/dwm-spawntag-6.2.diff b/dwm/patches/dwm-spawntag-6.2.diff
new file mode 100644
index 0000000..9dba2da
--- /dev/null
+++ b/dwm/patches/dwm-spawntag-6.2.diff
@@ -0,0 +1,84 @@
+# From abace8a090f579a9bd2513e78e0ebe9d9fa1e0bb Mon Sep 17 00:00:00 2001
+# From: Piyush Pangtey <gokuvsvegita@gmail.com>
+# Date: Wed, 19 May 2021 19:27:34 +0530
+# Subject: [PATCH] [Feature] spawntag
+#
+# spawn application whenever a tag is middle clicked
+# ---
+# config.def.h | 16 ++++++++++++++++
+# dwm.c | 14 ++++++++++++++
+# 2 files changed, 30 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..442b556 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -54,11 +54,26 @@ static const Layout layouts[] = {
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
++/* helper for launching gtk application */
++#define GTKCMD(cmd) { .v = (const char*[]){ "/usr/bin/gtk-launch", cmd, NULL } }
++
+ /* commands */
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
++static const Arg tagexec[] = {
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd },
++ { .v = termcmd }
++};
++
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+@@ -108,6 +123,7 @@ static Button buttons[] = {
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
++ { ClkTagBar, 0, Button2, spawntag, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+diff --git a/dwm.c b/dwm.c
+index 4465af1..89b3220 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -207,6 +207,7 @@ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
+ static void tag(const Arg *arg);
++static void spawntag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+@@ -1662,6 +1663,19 @@ tag(const Arg *arg)
+ }
+ }
+
++void
++spawntag(const Arg *arg)
++{
++ if (arg->ui & TAGMASK) {
++ for (int i = LENGTH(tags); i >= 0; i--) {
++ if (arg->ui & 1<<i) {
++ spawn(&tagexec[i]);
++ return;
++ }
++ }
++ }
++}
++
+ void
+ tagmon(const Arg *arg)
+ {
+--
+2.31.1
diff --git a/dwm/patches/dwm-stacker-6.2.diff b/dwm/patches/dwm-stacker-6.2.diff
new file mode 100644
index 0000000..91837f0
--- /dev/null
+++ b/dwm/patches/dwm-stacker-6.2.diff
@@ -0,0 +1,196 @@
+# From d04f2d00688c8b0969d4f10f460c980dd91dac37 Mon Sep 17 00:00:00 2001
+# From: MLquest8 <miskuzius@gmail.com>
+# Date: Fri, 12 Jun 2020 16:04:18 +0400
+# Subject: [PATCH] stacker updated for version 6.2
+#
+# ---
+# config.def.h | 14 +++++++--
+# dwm.c | 88 ++++++++++++++++++++++++++++++++++++++++------------
+# 2 files changed, 80 insertions(+), 22 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..d28f8fc 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -50,6 +50,14 @@ static const Layout layouts[] = {
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
++#define STACKKEYS(MOD,ACTION) \
++ { MOD, XK_j, ACTION##stack, {.i = INC(+1) } }, \
++ { MOD, XK_k, ACTION##stack, {.i = INC(-1) } }, \
++ { MOD, XK_grave, ACTION##stack, {.i = PREVSEL } }, \
++ { MOD, XK_q, ACTION##stack, {.i = 0 } }, \
++ { MOD, XK_a, ACTION##stack, {.i = 1 } }, \
++ { MOD, XK_z, ACTION##stack, {.i = 2 } }, \
++ { MOD, XK_x, ACTION##stack, {.i = -1 } },
+
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+@@ -64,8 +72,8 @@ static Key keys[] = {
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
+- { MODKEY, XK_j, focusstack, {.i = +1 } },
+- { MODKEY, XK_k, focusstack, {.i = -1 } },
++ STACKKEYS(MODKEY, focus)
++ STACKKEYS(MODKEY|ShiftMask, push)
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+@@ -93,7 +101,7 @@ static Key keys[] = {
+ TAGKEYS( XK_7, 6)
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+- { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY|ShiftMask, XK_BackSpace, quit, {0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index 9fd0286..6c302c3 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -47,15 +47,21 @@
+ /* macros */
+ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
++#define GETINC(X) ((X) - 2000)
++#define INC(X) ((X) + 2000)
+ #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 ISINC(X) ((X) > 1000 && (X) < 3000)
+ #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
++#define PREVSEL 3000
+ #define LENGTH(X) (sizeof X / sizeof X[0])
++#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M))
+ #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 TRUNC(X,A,B) (MAX((A), MIN((X), (B))))
+
+ /* enums */
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+@@ -187,6 +193,7 @@ static void movemouse(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *);
+ static void propertynotify(XEvent *e);
++static void pushstack(const Arg *arg);
+ static void quit(const Arg *arg);
+ static Monitor *recttomon(int x, int y, int w, int h);
+ static void resize(Client *c, int x, int y, int w, int h, int interact);
+@@ -207,6 +214,7 @@ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static int stackpos(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+@@ -833,27 +841,16 @@ focusmon(const Arg *arg)
+ void
+ focusstack(const Arg *arg)
+ {
+- Client *c = NULL, *i;
++ int i = stackpos(arg);
++ Client *c, *p;
+
+- if (!selmon->sel)
++ if(i < 0)
+ return;
+- if (arg->i > 0) {
+- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
+- if (!c)
+- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+- } else {
+- for (i = selmon->clients; i != selmon->sel; i = i->next)
+- if (ISVISIBLE(i))
+- c = i;
+- if (!c)
+- for (; i; i = i->next)
+- if (ISVISIBLE(i))
+- c = i;
+- }
+- if (c) {
+- focus(c);
+- restack(selmon);
+- }
++
++ for(p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c));
++ i -= ISVISIBLE(c) ? 1 : 0, p = c, c = c->next);
++ focus(c ? c : p);
++ restack(selmon);
+ }
+
+ Atom
+@@ -1246,6 +1243,29 @@ propertynotify(XEvent *e)
+ }
+ }
+
++void
++pushstack(const Arg *arg) {
++ int i = stackpos(arg);
++ Client *sel = selmon->sel, *c, *p;
++
++ if(i < 0)
++ return;
++ else if(i == 0) {
++ detach(sel);
++ attach(sel);
++ }
++ else {
++ for(p = NULL, c = selmon->clients; c; p = c, c = c->next)
++ if(!(i -= (ISVISIBLE(c) && c != sel)))
++ break;
++ c = c ? c : p;
++ detach(sel);
++ sel->next = c->next;
++ c->next = sel;
++ }
++ arrange(selmon);
++}
++
+ void
+ quit(const Arg *arg)
+ {
+@@ -1653,6 +1673,36 @@ spawn(const Arg *arg)
+ }
+ }
+
++int
++stackpos(const Arg *arg) {
++ int n, i;
++ Client *c, *l;
++
++ if(!selmon->clients)
++ return -1;
++
++ if(arg->i == PREVSEL) {
++ for(l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext);
++ if(!l)
++ return -1;
++ for(i = 0, c = selmon->clients; c != l; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
++ return i;
++ }
++ else if(ISINC(arg->i)) {
++ if(!selmon->sel)
++ return -1;
++ for(i = 0, c = selmon->clients; c != selmon->sel; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
++ for(n = i; c; n += ISVISIBLE(c) ? 1 : 0, c = c->next);
++ return MOD(i + GETINC(arg->i), n);
++ }
++ else if(arg->i < 0) {
++ for(i = 0, c = selmon->clients; c; i += ISVISIBLE(c) ? 1 : 0, c = c->next);
++ return MAX(i + arg->i, 0);
++ }
++ else
++ return arg->i;
++}
++
+ void
+ tag(const Arg *arg)
+ {
+--
+2.26.2
diff --git a/dwm/patches/dwm-stairs-fullgaps-20220430-8b48e30.diff b/dwm/patches/dwm-stairs-fullgaps-20220430-8b48e30.diff
new file mode 100644
index 0000000..75b47fd
--- /dev/null
+++ b/dwm/patches/dwm-stairs-fullgaps-20220430-8b48e30.diff
@@ -0,0 +1,98 @@
+# From 2004db267a9478918699961ab2f3579c2c8113fb Mon Sep 17 00:00:00 2001
+# From: Ehsan Ghorbannezhad <ehsan@disroot.org>
+# Date: Sat, 30 Apr 2022 02:48:58 +0430
+# Subject: [PATCH] add the stairs layout with fullgaps support
+#
+# ---
+# config.def.h | 5 +++++
+# dwm.c | 38 ++++++++++++++++++++++++++++++++++++++
+# 2 files changed, 43 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 5b0d4de..c0f24f4 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -6,6 +6,9 @@ static const unsigned int gappx = 5; /* 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 unsigned int stairpx = 20; /* depth of the stairs layout */
++static const int stairdirection = 1; /* 0: left-aligned, 1: right-aligned */
++static const int stairsamesize = 1; /* 1 means shrink all the staired windows to the same size */
+ static const char *fonts[] = { "monospace:size=10" };
+ static const char dmenufont[] = "monospace:size=10";
+ static const char col_gray1[] = "#222222";
+@@ -43,6 +46,7 @@ static const Layout layouts[] = {
+ { "[]=", tile }, /* first entry is default */
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
++ { "[S]", stairs },
+ };
+
+ /* key definitions */
+@@ -78,6 +82,7 @@ static Key keys[] = {
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
++ { MODKEY, XK_s, setlayout, {.v = &layouts[3]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+diff --git a/dwm.c b/dwm.c
+index 5b7348c..2c5380f 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -209,6 +209,7 @@ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static void stairs(Monitor *m);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+@@ -1672,6 +1673,43 @@ spawn(const Arg *arg)
+ }
+ }
+
++void
++stairs(Monitor *m)
++{
++ unsigned int i, n, h, mw, my;
++ unsigned int ox, oy, ow, oh; /* stair offset values */
++ Client *c;
++
++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
++ if (n == 0)
++ return;
++
++ if (n > m->nmaster)
++ mw = m->nmaster ? m->ww * m->mfact : 0;
++ else
++ mw = m->ww - m->gappx;
++
++ for (i = 0, my = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
++ if (i < m->nmaster) {
++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx;
++ resize(c, m->wx + m->gappx, m->wy + my, mw - (2 * c->bw) - m->gappx, h - (2 * c->bw), 0);
++ if (my + HEIGHT(c) + m->gappx < m->wh)
++ my += HEIGHT(c) + m->gappx;
++ } else {
++ oy = i - m->nmaster;
++ ox = stairdirection ? n - i - 1 : (stairsamesize ? i - m->nmaster : 0);
++ ow = stairsamesize ? n - m->nmaster - 1 : n - i - 1;
++ oh = stairsamesize ? ow : i - m->nmaster;
++ resize(c,
++ m->wx + mw + (ox * stairpx) + m->gappx,
++ m->wy + (oy * stairpx) + m->gappx,
++ m->ww - mw - (2 * c->bw) - (ow * stairpx) - (2 * m->gappx),
++ m->wh - (2 * c->bw) - (oh * stairpx) - (2 * m->gappx),
++ 0);
++ }
++ }
++}
++
+ void
+ tag(const Arg *arg)
+ {
+--
+2.36.0
diff --git a/dwm/patches/dwm-statuscmd-20241009-8933ebc.diff b/dwm/patches/dwm-statuscmd-20241009-8933ebc.diff
new file mode 100644
index 0000000..4e68a8a
--- /dev/null
+++ b/dwm/patches/dwm-statuscmd-20241009-8933ebc.diff
@@ -0,0 +1,219 @@
+# From ca2a2e6386a746ebfc3480787e5d99da11e7abee Mon Sep 17 00:00:00 2001
+# From: Justinas Grigas <dev@jstnas.com>
+# Date: Wed, 9 Oct 2024 01:00:20 +0100
+# Subject: [PATCH] [dwm][statuscmd] better click regions
+#
+# The main improvement of this patch over the previous version 20210405 is that
+# the click region now ends on a matching signal raw byte.
+#
+# The matching byte is optional, and without it dwm will behave as before.
+#
+# To take advantage of this feature, scripts need to be modified to print the raw
+# byte at the end as well.
+#
+# In addition, this patch cleanly applies onto master branch.
+# ---
+# config.def.h | 6 ++-
+# dwm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++---
+# 2 files changed, 104 insertions(+), 6 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..d008275 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -55,6 +55,8 @@ static const Layout layouts[] = {
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
++#define STATUSBAR "dwmblocks"
++
+ /* commands */
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+@@ -104,7 +106,9 @@ static const Button buttons[] = {
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
++ { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} },
++ { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} },
++ { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+diff --git a/dwm.c b/dwm.c
+index 1443802..94ee0c7 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -171,6 +171,7 @@ static void focusstack(const Arg *arg);
+ static Atom getatomprop(Client *c, Atom prop);
+ static int getrootptr(int *x, int *y);
+ static long getstate(Window w);
++static pid_t getstatusbarpid();
+ static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
+ static void grabbuttons(Client *c, int focused);
+ static void grabkeys(void);
+@@ -204,6 +205,7 @@ static void setmfact(const Arg *arg);
+ static void setup(void);
+ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
++static void sigstatusbar(const Arg *arg);
+ static void spawn(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+@@ -236,6 +238,9 @@ static void zoom(const Arg *arg);
+ /* variables */
+ static const char broken[] = "broken";
+ static char stext[256];
++static int statusw;
++static int statussig;
++static pid_t statuspid = -1;
+ static int screen;
+ static int sw, sh; /* X display screen geometry width, height */
+ static int bh; /* bar height */
+@@ -422,6 +427,7 @@ buttonpress(XEvent *e)
+ Client *c;
+ Monitor *m;
+ XButtonPressedEvent *ev = &e->xbutton;
++ char *text, *s, ch;
+
+ click = ClkRootWin;
+ /* focus monitor if necessary */
+@@ -440,9 +446,27 @@ buttonpress(XEvent *e)
+ arg.ui = 1 << i;
+ } else if (ev->x < x + TEXTW(selmon->ltsymbol))
+ click = ClkLtSymbol;
+- else if (ev->x > selmon->ww - (int)TEXTW(stext))
++ else if (ev->x > selmon->ww - statusw) {
++ x = selmon->ww - statusw;
+ click = ClkStatusText;
+- else
++ statussig = 0;
++ for (text = s = stext; *s && x <= ev->x; s++) {
++ if ((unsigned char)(*s) < ' ') {
++ ch = *s;
++ *s = '\0';
++ x += TEXTW(text) - lrpad;
++ *s = ch;
++ text = s + 1;
++ if (x >= ev->x)
++ break;
++ /* reset on matching signal raw byte */
++ if (ch == statussig)
++ statussig = 0;
++ else
++ statussig = ch;
++ }
++ }
++ } else
+ click = ClkWinTitle;
+ } else if ((c = wintoclient(ev->window))) {
+ focus(c);
+@@ -708,9 +732,24 @@ drawbar(Monitor *m)
+
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
++ char *text, *s, ch;
+ drw_setscheme(drw, scheme[SchemeNorm]);
+- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
++
++ x = 0;
++ for (text = s = stext; *s; s++) {
++ if ((unsigned char)(*s) < ' ') {
++ ch = *s;
++ *s = '\0';
++ tw = TEXTW(text) - lrpad;
++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
++ x += tw;
++ *s = ch;
++ text = s + 1;
++ }
++ }
++ tw = TEXTW(text) - lrpad + 2;
++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
++ tw = statusw;
+ }
+
+ for (c = m->clients; c; c = c->next) {
+@@ -876,6 +915,30 @@ getatomprop(Client *c, Atom prop)
+ return atom;
+ }
+
++pid_t
++getstatusbarpid()
++{
++ char buf[32], *str = buf, *c;
++ FILE *fp;
++
++ if (statuspid > 0) {
++ snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid);
++ if ((fp = fopen(buf, "r"))) {
++ fgets(buf, sizeof(buf), fp);
++ while ((c = strchr(str, '/')))
++ str = c + 1;
++ fclose(fp);
++ if (!strcmp(str, STATUSBAR))
++ return statuspid;
++ }
++ }
++ if (!(fp = popen("pidof -s "STATUSBAR, "r")))
++ return -1;
++ fgets(buf, sizeof(buf), fp);
++ pclose(fp);
++ return strtol(buf, NULL, 10);
++}
++
+ int
+ getrootptr(int *x, int *y)
+ {
+@@ -1643,6 +1706,20 @@ showhide(Client *c)
+ }
+ }
+
++void
++sigstatusbar(const Arg *arg)
++{
++ union sigval sv;
++
++ if (!statussig)
++ return;
++ sv.sival_int = arg->i;
++ if ((statuspid = getstatusbarpid()) <= 0)
++ return;
++
++ sigqueue(statuspid, SIGRTMIN+statussig, sv);
++}
++
+ void
+ spawn(const Arg *arg)
+ {
+@@ -2004,8 +2081,25 @@ updatesizehints(Client *c)
+ void
+ updatestatus(void)
+ {
+- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
+ strcpy(stext, "dwm-"VERSION);
++ statusw = TEXTW(stext) - lrpad + 2;
++ } else {
++ char *text, *s, ch;
++
++ statusw = 0;
++ for (text = s = stext; *s; s++) {
++ if ((unsigned char)(*s) < ' ') {
++ ch = *s;
++ *s = '\0';
++ statusw += TEXTW(text) - lrpad;
++ *s = ch;
++ text = s + 1;
++ }
++ }
++ statusw += TEXTW(text) - lrpad + 2;
++
++ }
+ drawbar(selmon);
+ }
+
+--
+2.46.2
diff --git a/dwm/patches/dwm-sticky-6.5.diff b/dwm/patches/dwm-sticky-6.5.diff
new file mode 100644
index 0000000..50a4066
--- /dev/null
+++ b/dwm/patches/dwm-sticky-6.5.diff
@@ -0,0 +1,145 @@
+# From 60f7034ca1573e10cf9e005e2ef5a44e6b76ea9b Mon Sep 17 00:00:00 2001
+# From: elbachir-one <bachiralfa@gmail.com>
+# Date: Fri, 27 Sep 2024 12:35:36 +0100
+# Subject: [PATCH] Added the missing keybinding
+#
+# ---
+# config.def.h | 1 +
+# dwm.c | 43 ++++++++++++++++++++++++++++++++++++++++---
+# 2 files changed, 41 insertions(+), 3 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9efa774..55c0a6c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -95,6 +95,7 @@ static const Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_s, togglesticky, {0} },
+ };
+
+ /* button definitions */
+diff --git a/dwm.c b/dwm.c
+index 67c6b2b..e8ed755 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -49,7 +49,7 @@
+ #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 ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
++#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)
+@@ -61,7 +61,7 @@
+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+ enum { SchemeNorm, SchemeSel }; /* color schemes */
+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
++ NetWMFullscreen, NetWMSticky, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+@@ -92,7 +92,7 @@ struct Client {
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+ int bw, oldbw;
+ unsigned int tags;
+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, issticky;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -200,6 +200,7 @@ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+ static void setfocus(Client *c);
+ static void setfullscreen(Client *c, int fullscreen);
++static void setsticky(Client *c, int sticky);
+ static void setlayout(const Arg *arg);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+@@ -211,6 +212,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglesticky(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -525,6 +527,10 @@ clientmessage(XEvent *e)
+ || cme->data.l[2] == netatom[NetWMFullscreen])
+ setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
++
++ if (cme->data.l[1] == netatom[NetWMSticky]
++ || cme->data.l[2] == netatom[NetWMSticky])
++ setsticky(c, (cme->data.l[0] == 1 || (cme->data.l[0] == 2 && !c->issticky)));
+ } else if (cme->message_type == netatom[NetActiveWindow]) {
+ if (c != selmon->sel && !c->isurgent)
+ seturgent(c, 1);
+@@ -1507,6 +1513,23 @@ setfullscreen(Client *c, int fullscreen)
+ }
+ }
+
++void
++ setsticky(Client *c, int sticky)
++ {
++
++ if(sticky && !c->issticky) {
++ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
++ PropModeReplace, (unsigned char *) &netatom[NetWMSticky], 1);
++ c->issticky = 1;
++ } else if(!sticky && c->issticky){
++ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
++ PropModeReplace, (unsigned char *)0, 0);
++ c->issticky = 0;
++ arrange(c->mon);
++ }
++ }
++
++
+ void
+ setlayout(const Arg *arg)
+ {
+@@ -1576,6 +1599,7 @@ setup(void)
+ netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
++ netatom[NetWMSticky] = XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+@@ -1735,6 +1759,15 @@ togglefloating(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++togglesticky(const Arg *arg)
++{
++ if (!selmon->sel)
++ return;
++ setsticky(selmon->sel, !selmon->sel->issticky);
++ arrange(selmon);
++}
++
+ void
+ toggletag(const Arg *arg)
+ {
+@@ -2027,6 +2060,9 @@ updatewindowtype(Client *c)
+
+ if (state == netatom[NetWMFullscreen])
+ setfullscreen(c, 1);
++ if (state == netatom[NetWMSticky]) {
++ setsticky(c, 1);
++ }
+ if (wtype == netatom[NetWMWindowTypeDialog])
+ c->isfloating = 1;
+ }
+@@ -2163,3 +2199,4 @@ main(int argc, char *argv[])
+ XCloseDisplay(dpy);
+ return EXIT_SUCCESS;
+ }
++
+--
+2.46.0
diff --git a/dwm/patches/dwm-stickyindicator-6.2.diff b/dwm/patches/dwm-stickyindicator-6.2.diff
new file mode 100644
index 0000000..8b6ec41
--- /dev/null
+++ b/dwm/patches/dwm-stickyindicator-6.2.diff
@@ -0,0 +1,65 @@
+diff -pu dwm.stickypatch/config.def.h dwm.stickyindicator/config.def.h
+--- dwm.stickypatch/config.def.h 2021-02-28 23:51:25.118904642 -0600
++++ dwm.stickyindicator/config.def.h 2021-03-15 20:19:53.533323727 -0500
+@@ -17,6 +17,8 @@ static const char *colors[][3] = {
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ };
++static const XPoint stickyicon[] = { {0,0}, {4,0}, {4,8}, {2,6}, {0,8}, {0,0} }; /* represents the icon as an array of vertices */
++static const XPoint stickyiconbb = {4,8}; /* defines the bottom right corner of the polygon's bounding box (speeds up scaling) */
+
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+diff -pu dwm.stickypatch/drw.c dwm.stickyindicator/drw.c
+--- dwm.stickypatch/drw.c 2021-02-28 23:51:06.992237482 -0600
++++ dwm.stickyindicator/drw.c 2021-03-15 20:19:19.499990633 -0500
+@@ -248,6 +248,26 @@ drw_rect(Drw *drw, int x, int y, unsigne
+ XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
+ }
+
++void
++drw_polygon(Drw *drw, int x, int y, int ow, int oh, int sw, int sh, const XPoint *points, int npoints, int shape, int filled) /* wrapper function to scale and draw a polygon with X11 */
++{
++ if (!drw || !drw->scheme)
++ return;
++ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
++ if (!filled) { /* reduces the scaled width and height by 1 when drawing the outline to compensate for X11 drawing the line 1 pixel over */
++ sw -= 1;
++ sh -= 1;
++ }
++ XPoint scaledpoints[npoints];
++ memcpy(scaledpoints, points, npoints);
++ for (int v = 0; v < npoints; v++)
++ scaledpoints[v] = (XPoint){ .x = points[v].x * sw / ow + x, .y = points[v].y * sh / oh + y };
++ if (filled)
++ XFillPolygon(drw->dpy, drw->drawable, drw->gc, scaledpoints, npoints, shape, CoordModeOrigin); /* Change shape to 'Convex' or 'Complex' in dwm.c if the shape is not 'Nonconvex' */
++ else
++ XDrawLines(drw->dpy, drw->drawable, drw->gc, scaledpoints, npoints, CoordModeOrigin);
++}
++
+ int
+ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
+ {
+diff -pu dwm.stickypatch/drw.h dwm.stickyindicator/drw.h
+--- dwm.stickypatch/drw.h 2021-02-28 23:51:06.992237482 -0600
++++ dwm.stickyindicator/drw.h 2021-03-01 01:34:02.739074730 -0600
+@@ -51,6 +51,7 @@ 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);
++void drw_polygon(Drw *drw, int x, int y, int ow, int oh, int sw, int sh, const XPoint *points, int npoints, int shape, int filled);
+ 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 */
+diff -pu dwm.stickypatch/dwm.c dwm.stickyindicator/dwm.c
+--- dwm.stickypatch/dwm.c 2021-02-28 23:51:25.118904642 -0600
++++ dwm.stickyindicator/dwm.c 2021-03-15 20:12:32.063326766 -0500
+@@ -736,6 +736,8 @@ drawbar(Monitor *m)
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
++ if (m->sel->issticky)
++ drw_polygon(drw, x + boxs, m->sel->isfloating ? boxs * 2 + boxw : boxs, stickyiconbb.x, stickyiconbb.y, boxw, boxw * stickyiconbb.y / stickyiconbb.x, stickyicon, LENGTH(stickyicon), Nonconvex, m->sel->tags & m->tagset[m->seltags]);
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, x, 0, w, bh, 1, 1);
diff --git a/dwm/patches/dwm-swallow-6.3.diff b/dwm/patches/dwm-swallow-6.3.diff
new file mode 100644
index 0000000..d2d3835
--- /dev/null
+++ b/dwm/patches/dwm-swallow-6.3.diff
@@ -0,0 +1,410 @@
+# From 0cf9a007511f7dfd7dd94171b172562ebac9b6d5 Mon Sep 17 00:00:00 2001
+# From: Tom Schwindl <schwindl@posteo.de>
+# Date: Sat, 10 Sep 2022 12:51:09 +0200
+# Subject: [PATCH] 6.3 swallow patch
+#
+# ---
+# config.def.h | 9 +-
+# config.mk | 3 +-
+# dwm.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++--
+# 3 files changed, 237 insertions(+), 10 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 061ad662f82a..0b2b8ffd30d5 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -3,6 +3,7 @@
+ /* appearance */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
+ static const int showbar = 1; /* 0 means no bar */
+ static const int topbar = 1; /* 0 means bottom bar */
+ static const char *fonts[] = { "monospace:size=10" };
+@@ -26,9 +27,11 @@ static const Rule rules[] = {
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+- /* class instance title tags mask isfloating monitor */
+- { "Gimp", NULL, NULL, 0, 1, -1 },
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
++ /* class instance title tags mask isfloating isterminal noswallow monitor */
++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
++ { "St", NULL, NULL, 0, 0, 1, 0, -1 },
++ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
+ };
+
+ /* layout(s) */
+diff --git a/config.mk b/config.mk
+index 81c493ef4aff..52d1ebf30bec 100644
+--- a/config.mk
++++ b/config.mk
+@@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2
+ # OpenBSD (uncomment)
+ #FREETYPEINC = ${X11INC}/freetype2
+ #MANPREFIX = ${PREFIX}/man
++#KVMLIB = -lkvm
+
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/dwm.c b/dwm.c
+index e5efb6a22806..e68294b6b679 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -40,6 +40,12 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <X11/Xlib-xcb.h>
++#include <xcb/res.h>
++#ifdef __OpenBSD__
++#include <sys/sysctl.h>
++#include <kvm.h>
++#endif /* __OpenBSD */
+
+ #include "drw.h"
+ #include "util.h"
+@@ -92,9 +98,11 @@ struct Client {
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+ int bw, oldbw;
+ unsigned int tags;
+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
++ pid_t pid;
+ Client *next;
+ Client *snext;
++ Client *swallowing;
+ Monitor *mon;
+ Window win;
+ };
+@@ -138,6 +146,8 @@ typedef struct {
+ const char *title;
+ unsigned int tags;
+ int isfloating;
++ int isterminal;
++ int noswallow;
+ int monitor;
+ } Rule;
+
+@@ -235,6 +245,12 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
+
++static pid_t getparentprocess(pid_t p);
++static int isdescprocess(pid_t p, pid_t c);
++static Client *swallowingclient(Window w);
++static Client *termforwin(const Client *c);
++static pid_t winpid(Window w);
++
+ /* variables */
+ static const char broken[] = "broken";
+ static char stext[256];
+@@ -269,6 +285,8 @@ static Drw *drw;
+ static Monitor *mons, *selmon;
+ static Window root, wmcheckwin;
+
++static xcb_connection_t *xcon;
++
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
+@@ -298,6 +316,8 @@ applyrules(Client *c)
+ && (!r->class || strstr(class, r->class))
+ && (!r->instance || strstr(instance, r->instance)))
+ {
++ c->isterminal = r->isterminal;
++ c->noswallow = r->noswallow;
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+@@ -416,6 +436,53 @@ attachstack(Client *c)
+ c->mon->stack = c;
+ }
+
++void
++swallow(Client *p, Client *c)
++{
++
++ if (c->noswallow || c->isterminal)
++ return;
++ if (c->noswallow && !swallowfloating && c->isfloating)
++ return;
++
++ detach(c);
++ detachstack(c);
++
++ setclientstate(c, WithdrawnState);
++ XUnmapWindow(dpy, p->win);
++
++ p->swallowing = c;
++ c->mon = p->mon;
++
++ Window w = p->win;
++ p->win = c->win;
++ c->win = w;
++ updatetitle(p);
++ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
++ arrange(p->mon);
++ configure(p);
++ updateclientlist();
++}
++
++void
++unswallow(Client *c)
++{
++ c->win = c->swallowing->win;
++
++ free(c->swallowing);
++ c->swallowing = NULL;
++
++ /* unfullscreen the client */
++ setfullscreen(c, 0);
++ updatetitle(c);
++ arrange(c->mon);
++ XMapWindow(dpy, c->win);
++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
++ setclientstate(c, NormalState);
++ focus(NULL);
++ arrange(c->mon);
++}
++
+ void
+ buttonpress(XEvent *e)
+ {
+@@ -656,6 +723,9 @@ destroynotify(XEvent *e)
+
+ if ((c = wintoclient(ev->window)))
+ unmanage(c, 1);
++
++ else if ((c = swallowingclient(ev->window)))
++ unmanage(c->swallowing, 1);
+ }
+
+ void
+@@ -1022,12 +1092,13 @@ killclient(const Arg *arg)
+ void
+ manage(Window w, XWindowAttributes *wa)
+ {
+- Client *c, *t = NULL;
++ Client *c, *t = NULL, *term = NULL;
+ Window trans = None;
+ XWindowChanges wc;
+
+ c = ecalloc(1, sizeof(Client));
+ c->win = w;
++ c->pid = winpid(w);
+ /* geometry */
+ c->x = c->oldx = wa->x;
+ c->y = c->oldy = wa->y;
+@@ -1042,6 +1113,7 @@ manage(Window w, XWindowAttributes *wa)
+ } else {
+ c->mon = selmon;
+ applyrules(c);
++ term = termforwin(c);
+ }
+
+ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+@@ -1076,6 +1148,8 @@ manage(Window w, XWindowAttributes *wa)
+ c->mon->sel = c;
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
++ if (term)
++ swallow(term, c);
+ focus(NULL);
+ }
+
+@@ -1763,6 +1837,20 @@ unmanage(Client *c, int destroyed)
+ Monitor *m = c->mon;
+ XWindowChanges wc;
+
++ if (c->swallowing) {
++ unswallow(c);
++ return;
++ }
++
++ Client *s = swallowingclient(c->win);
++ if (s) {
++ free(s->swallowing);
++ s->swallowing = NULL;
++ arrange(m);
++ focus(NULL);
++ return;
++ }
++
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+@@ -1778,9 +1866,12 @@ unmanage(Client *c, int destroyed)
+ XUngrabServer(dpy);
+ }
+ free(c);
+- focus(NULL);
+- updateclientlist();
+- arrange(m);
++
++ if (!s) {
++ arrange(m);
++ focus(NULL);
++ updateclientlist();
++ }
+ }
+
+ void
+@@ -2044,6 +2135,136 @@ view(const Arg *arg)
+ arrange(selmon);
+ }
+
++pid_t
++winpid(Window w)
++{
++
++ pid_t result = 0;
++
++#ifdef __linux__
++ xcb_res_client_id_spec_t spec = {0};
++ spec.client = w;
++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
++
++ xcb_generic_error_t *e = NULL;
++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
++
++ if (!r)
++ return (pid_t)0;
++
++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
++ for (; i.rem; xcb_res_client_id_value_next(&i)) {
++ spec = i.data->spec;
++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
++ uint32_t *t = xcb_res_client_id_value_value(i.data);
++ result = *t;
++ break;
++ }
++ }
++
++ free(r);
++
++ if (result == (pid_t)-1)
++ result = 0;
++
++#endif /* __linux__ */
++
++#ifdef __OpenBSD__
++ Atom type;
++ int format;
++ unsigned long len, bytes;
++ unsigned char *prop;
++ pid_t ret;
++
++ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
++ return 0;
++
++ ret = *(pid_t*)prop;
++ XFree(prop);
++ result = ret;
++#endif /* __OpenBSD__ */
++ return result;
++}
++
++pid_t
++getparentprocess(pid_t p)
++{
++ unsigned int v = 0;
++
++#ifdef __linux__
++ FILE *f;
++ char buf[256];
++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
++
++ if (!(f = fopen(buf, "r")))
++ return 0;
++
++ fscanf(f, "%*u %*s %*c %u", &v);
++ fclose(f);
++#endif /* __linux__*/
++
++#ifdef __OpenBSD__
++ int n;
++ kvm_t *kd;
++ struct kinfo_proc *kp;
++
++ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
++ if (!kd)
++ return 0;
++
++ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
++ v = kp->p_ppid;
++#endif /* __OpenBSD__ */
++
++ return (pid_t)v;
++}
++
++int
++isdescprocess(pid_t p, pid_t c)
++{
++ while (p != c && c != 0)
++ c = getparentprocess(c);
++
++ return (int)c;
++}
++
++Client *
++termforwin(const Client *w)
++{
++ Client *c;
++ Monitor *m;
++
++ if (!w->pid || w->isterminal)
++ return NULL;
++
++ for (m = mons; m; m = m->next) {
++ for (c = m->clients; c; c = c->next) {
++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
++ return c;
++ }
++ }
++
++ return NULL;
++}
++
++Client *
++swallowingclient(Window w)
++{
++ Client *c;
++ Monitor *m;
++
++ for (m = mons; m; m = m->next) {
++ for (c = m->clients; c; c = c->next) {
++ if (c->swallowing && c->swallowing->win == w)
++ return c;
++ }
++ }
++
++ return NULL;
++}
++
+ Client *
+ wintoclient(Window w)
+ {
+@@ -2133,10 +2354,12 @@ main(int argc, char *argv[])
+ fputs("warning: no locale support\n", stderr);
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("dwm: cannot open display");
++ if (!(xcon = XGetXCBConnection(dpy)))
++ die("dwm: cannot get xcb connection\n");
+ checkotherwm();
+ setup();
+ #ifdef __OpenBSD__
+- if (pledge("stdio rpath proc exec", NULL) == -1)
++ if (pledge("stdio rpath proc exec ps", NULL) == -1)
+ die("pledge");
+ #endif /* __OpenBSD__ */
+ scan();
+--
+2.37.2
diff --git a/dwm/patches/dwm-switchallmonitortags-6.3.diff b/dwm/patches/dwm-switchallmonitortags-6.3.diff
new file mode 100644
index 0000000..44b751f
--- /dev/null
+++ b/dwm/patches/dwm-switchallmonitortags-6.3.diff
@@ -0,0 +1,62 @@
+# From 31b89fe119b4a0298da98891aa37b134facb6311 Mon Sep 17 00:00:00 2001
+# From: yasumori <ysmr@protonmail.com>
+# Date: Fri, 27 May 2022 00:21:27 -0400
+# Subject: [PATCH] This patch allows the user to switch the selected tag of all
+# monitors.
+#
+# For example, if monitor A is currently on tag 1, and monitor B is on tag 2,
+# and the user presses MODKEY+SUPERKEY+3, both monitor A and B will switch to
+# tag 3 (without changing the currently selected monitor).
+# ---
+# config.def.h | 2 ++
+# dwm.c | 13 +++++++++++++
+# 2 files changed, 15 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..3f504ab 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -46,8 +46,10 @@ static const Layout layouts[] = {
+
+ /* key definitions */
+ #define MODKEY Mod1Mask
++#define SUPERKEY Mod4Mask
+ #define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
++ { MODKEY|SUPERKEY, KEY, viewall, {.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} },
+diff --git a/dwm.c b/dwm.c
+index 5646a5c..28736ee 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -228,6 +228,7 @@ static void updatetitle(Client *c);
+ static void updatewindowtype(Client *c);
+ static void updatewmhints(Client *c);
+ static void view(const Arg *arg);
++static void viewall(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+@@ -2054,6 +2055,18 @@ view(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++viewall(const Arg *arg)
++{
++ Monitor *m;
++
++ for (m = mons; m; m = m->next) {
++ m->tagset[m->seltags] = arg->ui;
++ arrange(m);
++ }
++ focus(NULL);
++}
++
+ Client *
+ wintoclient(Window w)
+ {
+--
+2.36.1
diff --git a/dwm/patches/dwm-taglabels-hide_vacant_tags_funcionality-6.2.diff b/dwm/patches/dwm-taglabels-hide_vacant_tags_funcionality-6.2.diff
new file mode 100644
index 0000000..d27b0d8
--- /dev/null
+++ b/dwm/patches/dwm-taglabels-hide_vacant_tags_funcionality-6.2.diff
@@ -0,0 +1,91 @@
+diff -pu dwm.hide_vacant_tags/config.def.h dwm.programtags+hidewithvacanttags/config.def.h
+--- dwm.hide_vacant_tags/config.def.h 2021-03-15 16:37:24.586622415 -0500
++++ dwm.programtags+hidewithvacanttags/config.def.h 2021-03-15 16:32:37.586956549 -0500
+@@ -21,6 +21,10 @@ static const char *colors[][3] = {
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
++static const char ptagf[] = "[%s %s]"; /* format of a tag label */
++static const char etagf[] = "[%s]"; /* format of an empty tag */
++static const int lcaselbl = 0; /* 1 means make tag label lowercase */
++
+ static const Rule rules[] = {
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+diff -pu dwm.hide_vacant_tags/dwm.c dwm.programtags+hidewithvacanttags/dwm.c
+--- dwm.hide_vacant_tags/dwm.c 2021-03-15 16:37:38.189939908 -0500
++++ dwm.programtags+hidewithvacanttags/dwm.c 2021-03-15 16:32:23.693639390 -0500
+@@ -20,6 +20,7 @@
+ *
+ * To understand everything else, start reading main().
+ */
++#include <ctype.h> /* for making tab label lowercase, very tiny standard library */
+ #include <errno.h>
+ #include <locale.h>
+ #include <signal.h>
+@@ -272,6 +273,8 @@ static Window root, wmcheckwin;
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
++unsigned int tagw[LENGTH(tags)];
++
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+@@ -438,7 +441,7 @@ buttonpress(XEvent *e)
+ /* do not reserve space for vacant tags */
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+- x += TEXTW(tags[i]);
++ x += tagw[i];
+ } while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+@@ -706,6 +709,8 @@ drawbar(Monitor *m)
+ int boxw = drw->fonts->h / 6 + 2;
+ unsigned int i, occ = 0, urg = 0;
+ Client *c;
++ char tagdisp[64];
++ char *masterclientontag[LENGTH(tags)];
+
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
+@@ -714,10 +719,21 @@ drawbar(Monitor *m)
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+ }
+
++ for (i = 0; i < LENGTH(tags); i++)
++ masterclientontag[i] = NULL;
++
+ for (c = m->clients; c; c = c->next) {
+ occ |= c->tags == 255 ? 0 : c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
++ for (i = 0; i < LENGTH(tags); i++)
++ if (!masterclientontag[i] && c->tags & (1<<i)) {
++ XClassHint ch = { NULL, NULL };
++ XGetClassHint(dpy, c->win, &ch);
++ masterclientontag[i] = ch.res_class;
++ if (lcaselbl)
++ masterclientontag[i][0] = tolower(masterclientontag[i][0]);
++ }
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+@@ -725,9 +741,14 @@ drawbar(Monitor *m)
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+
+- w = TEXTW(tags[i]);
++ if (masterclientontag[i])
++ snprintf(tagdisp, 64, ptagf, tags[i], masterclientontag[i]);
++ else
++ snprintf(tagdisp, 64, etagf, tags[i]);
++ masterclientontag[i] = tagdisp;
++ tagw[i] = w = TEXTW(masterclientontag[i]);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, masterclientontag[i], urg & 1 << i);
+ x += w;
+ }
+ w = blw = TEXTW(m->ltsymbol);
diff --git a/dwm/patches/dwm-tiledmove-20231210-b731.diff b/dwm/patches/dwm-tiledmove-20231210-b731.diff
new file mode 100644
index 0000000..8ede0c6
--- /dev/null
+++ b/dwm/patches/dwm-tiledmove-20231210-b731.diff
@@ -0,0 +1,82 @@
+# From 427c5fef13676179621949f0a8a4036e49d4b74e Mon Sep 17 00:00:00 2001
+# From: Niki <>
+# Date: Sun, 10 Dec 2023 00:29:59 +0000
+# Subject: [PATCH] The function `movemouse` now doesn't force clients to be
+# floating.
+#
+# Tiling clients when moved will swap with any existing clients that
+# overlap with the cursor, and snap to other monitors.
+# ---
+# dwm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
+# 1 file changed, 53 insertions(+), 3 deletions(-)
+
+diff --git a/dwm.c b/dwm.c
+index d12be2d..b1023e0 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1189,11 +1189,60 @@ movemouse(const Arg *arg)
+ ny = selmon->wy;
+ else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
+ ny = selmon->wy + selmon->wh - HEIGHT(c);
+- if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+- && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
+- togglefloating(NULL);
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+ resize(c, nx, ny, c->w, c->h, 1);
++ else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
++ if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
++ sendmon(c, m);
++ selmon = m;
++ focus(NULL);
++ }
++
++ Client *cc = c->mon->clients;
++ while (1) {
++ if (cc == 0) break;
++ if(
++ cc != c && !cc->isfloating && ISVISIBLE(cc) &&
++ ev.xmotion.x_root > cc->x &&
++ ev.xmotion.x_root < cc->x + cc->w &&
++ ev.xmotion.y_root > cc->y &&
++ ev.xmotion.y_root < cc->y + cc->h ) {
++ break;
++ }
++
++ cc = cc->next;
++ }
++
++ if (cc) {
++ Client *cl1, *cl2, ocl1;
++
++ if (!selmon->lt[selmon->sellt]->arrange) return;
++
++ cl1 = c;
++ cl2 = cc;
++ ocl1 = *cl1;
++ strcpy(cl1->name, cl2->name);
++ cl1->win = cl2->win;
++ cl1->x = cl2->x;
++ cl1->y = cl2->y;
++ cl1->w = cl2->w;
++ cl1->h = cl2->h;
++
++ cl2->win = ocl1.win;
++ strcpy(cl2->name, ocl1.name);
++ cl2->x = ocl1.x;
++ cl2->y = ocl1.y;
++ cl2->w = ocl1.w;
++ cl2->h = ocl1.h;
++
++ selmon->sel = cl2;
++
++ c = cc;
++ focus(c);
++
++ arrange(cl1->mon);
++ }
++ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+--
+2.43.0
diff --git a/dwm/patches/dwm-toggleallmonspertag-6.4.diff b/dwm/patches/dwm-toggleallmonspertag-6.4.diff
new file mode 100644
index 0000000..32527f6
--- /dev/null
+++ b/dwm/patches/dwm-toggleallmonspertag-6.4.diff
@@ -0,0 +1,74 @@
+diff --git a/config.def.h b/config.def.h
+index 061ad66..67afc6d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -71,6 +71,7 @@ static const Key keys[] = {
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
++ { MODKEY|ShiftMask, XK_Tab, toggleall, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+diff --git a/dwm.c b/dwm.c
+index e5efb6a..62f711b 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -210,6 +210,7 @@ static void spawn(const Arg *arg);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
++static void toggleall(const Arg *arg);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+@@ -1694,6 +1695,49 @@ tile(Monitor *m)
+ }
+ }
+
++
++void
++toggleall(const Arg *arg)
++{
++ int i;
++ unsigned int tmptag;
++
++ Monitor* m;
++ for(m = mons; m; m = m->next){
++
++ if ((arg->ui & TAGMASK) == m->tagset[m->seltags])
++ return;
++ m->seltags ^= 1; /* toggle sel tagset */
++ if (arg->ui & TAGMASK) {
++ m->tagset[m->seltags] = arg->ui & TAGMASK;
++ m->pertag->prevtag = m->pertag->curtag;
++
++ if (arg->ui == ~0)
++ m->pertag->curtag = 0;
++ else {
++ for (i = 0; !(arg->ui & 1 << i); i++) ;
++ m->pertag->curtag = i + 1;
++ }
++ } else {
++ tmptag = m->pertag->prevtag;
++ m->pertag->prevtag = m->pertag->curtag;
++ m->pertag->curtag = tmptag;
++ }
++
++ m->nmaster = m->pertag->nmasters[m->pertag->curtag];
++ m->mfact = m->pertag->mfacts[m->pertag->curtag];
++ m->sellt = m->pertag->sellts[m->pertag->curtag];
++ m->lt[m->sellt] = m->pertag->ltidxs[m->pertag->curtag][m->sellt];
++ m->lt[m->sellt^1] = m->pertag->ltidxs[m->pertag->curtag][m->sellt^1];
++
++ if (m->showbar != m->pertag->showbars[m->pertag->curtag])
++ togglebar(NULL);
++
++ focus(NULL);
++ arrange(m);
++ }
++}
++
+ void
+ togglebar(const Arg *arg)
+ {
diff --git a/dwm/patches/dwm-toggleborder-6.3.diff b/dwm/patches/dwm-toggleborder-6.3.diff
new file mode 100644
index 0000000..adc6bd0
--- /dev/null
+++ b/dwm/patches/dwm-toggleborder-6.3.diff
@@ -0,0 +1,52 @@
+# From ef85b0473590615fda4ba4b20a717e42c99e3f99 Mon Sep 17 00:00:00 2001
+# From: Stanisław Bitner <sbitner420@tutanota.com>
+# Date: Tue, 9 Aug 2022 23:17:47 +0200
+# Subject: [PATCH] toggleborder
+#
+# This patch allows you to toggle client border. It works by setting the
+# border of the client to 0 or to borderpx defined in configuration file.
+# ---
+# config.def.h | 1 +
+# dwm.c | 8 ++++++++
+# 2 files changed, 9 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..60b811f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -65,6 +65,7 @@ static Key keys[] = {
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
++ { MODKEY|ShiftMask, XK_b, toggleborder, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+diff --git a/dwm.c b/dwm.c
+index 967c9e8..91d00f6 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -211,6 +211,7 @@ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
++static void toggleborder(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+@@ -1707,6 +1708,13 @@ togglebar(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++toggleborder(const Arg *arg)
++{
++ selmon->sel->bw = (selmon->sel->bw == borderpx ? 0 : borderpx);
++ arrange(selmon);
++}
++
+ void
+ togglefloating(const Arg *arg)
+ {
+--
+2.37.1
diff --git a/dwm/patches/dwm-togglefloatingcenter-20210806-138b405f.diff b/dwm/patches/dwm-togglefloatingcenter-20210806-138b405f.diff
new file mode 100644
index 0000000..6e3c3d0
--- /dev/null
+++ b/dwm/patches/dwm-togglefloatingcenter-20210806-138b405f.diff
@@ -0,0 +1,30 @@
+# From efa326b2c71f0df1d097fd52a17684f5ccc5df6c Mon Sep 17 00:00:00 2001
+# From: Rizqi Nur Assyaufi <bandithijo@gmail.com>
+# Date: Sat, 7 Aug 2021 00:24:01 +0800
+# Subject: [PATCH] [dwm][patch][togglefloatingcenter] centered togglefloating
+# window
+#
+# Default behaviour when togglefloating() is floating from top-left corner.
+# This patch will allows you to toggle floating window client will be centered
+# position.
+# ---
+# dwm.c | 4 ++++
+# 1 file changed, 4 insertions(+)
+
+diff --git a/dwm.c b/dwm.c
+index 5e4d494..cbedb09 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -1719,6 +1719,10 @@ togglefloating(const Arg *arg)
+ if (selmon->sel->isfloating)
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, 0);
++
++ selmon->sel->x = selmon->sel->mon->mx + (selmon->sel->mon->mw - WIDTH(selmon->sel)) / 2;
++ selmon->sel->y = selmon->sel->mon->my + (selmon->sel->mon->mh - HEIGHT(selmon->sel)) / 2;
++
+ arrange(selmon);
+ }
+
+--
+2.31.1
diff --git a/dwm/patches/dwm-toggletopbar-barpadding-6.4.diff b/dwm/patches/dwm-toggletopbar-barpadding-6.4.diff
new file mode 100644
index 0000000..982fa3d
--- /dev/null
+++ b/dwm/patches/dwm-toggletopbar-barpadding-6.4.diff
@@ -0,0 +1,43 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2022-10-28 22:20:44.531059708 +0200
++++ b/config.def.h 2022-10-28 22:21:12.621059000 +0200
+@@ -67,6 +67,7 @@ static const Key keys[] = {
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
++ { MODKEY, XK_t, toggletopbar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+diff -up a/b.c b/b.c
+--- a/b.c 2022-10-28 22:20:44.532059708 +0200
++++ b/b.c 2022-10-28 22:23:27.019055613 +0200
+@@ -211,6 +211,7 @@ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglebar(const Arg *arg);
++static void toggletopbar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+@@ -1710,6 +1711,20 @@ togglebar(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++toggletopbar(const Arg *arg)
++{
++ selmon->topbar = !selmon->topbar;
++ updatebarpos(selmon);
++
++ if (selmon->topbar)
++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
++ else
++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by - vp, selmon->ww - 2 * sp, bh);
++
++ arrange(selmon);
++}
++
+ void
+ togglefloating(const Arg *arg)
+ {
diff --git a/dwm/patches/dwm-unicode_ellipsis-20222909-d3f93c7.diff b/dwm/patches/dwm-unicode_ellipsis-20222909-d3f93c7.diff
new file mode 100644
index 0000000..a03f88f
--- /dev/null
+++ b/dwm/patches/dwm-unicode_ellipsis-20222909-d3f93c7.diff
@@ -0,0 +1,22 @@
+diff --git a/drw.c b/drw.c
+index ced7d37..95da860 100644
+--- a/drw.c
++++ b/drw.c
+@@ -285,7 +285,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
+
+ usedfont = drw->fonts;
+ if (!ellipsis_width && render)
+- ellipsis_width = drw_fontset_getwidth(drw, "...");
++ ellipsis_width = drw_fontset_getwidth(drw, "…");
+ while (1) {
+ ew = ellipsis_len = utf8strlen = 0;
+ utf8str = text;
+@@ -339,7 +339,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
+ w -= ew;
+ }
+ if (render && overflow)
+- drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
++ drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "…", invert);
+
+ if (!*text || overflow) {
+ break;
diff --git a/dwm/patches/dwm-xresources-20210827-138b405.diff b/dwm/patches/dwm-xresources-20210827-138b405.diff
new file mode 100644
index 0000000..2a3a594
--- /dev/null
+++ b/dwm/patches/dwm-xresources-20210827-138b405.diff
@@ -0,0 +1,239 @@
+# From f30583c6e2ab5e7de6ef4ebf156076ac0f6e69fc Mon Sep 17 00:00:00 2001
+# From: Jack Bird <jack.bird@durham.ac.uk>
+# Date: Fri, 27 Aug 2021 00:53:14 +0100
+# Subject: [PATCH] xresources updated for 138b405
+#
+# ---
+# config.def.h | 61 ++++++++++++++++++++++++++++++--------------
+# drw.c | 2 +-
+# drw.h | 2 +-
+# dwm.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+# 4 files changed, 116 insertions(+), 21 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..87ac198 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -1,21 +1,23 @@
+ /* See LICENSE file for copyright and license details. */
+
+ /* appearance */
+-static const unsigned int borderpx = 1; /* border pixel of windows */
+-static const unsigned int snap = 32; /* snap pixel */
+-static const int showbar = 1; /* 0 means no bar */
+-static const int topbar = 1; /* 0 means bottom bar */
+-static const char *fonts[] = { "monospace:size=10" };
+-static const char dmenufont[] = "monospace:size=10";
+-static const char col_gray1[] = "#222222";
+-static const char col_gray2[] = "#444444";
+-static const char col_gray3[] = "#bbbbbb";
+-static const char col_gray4[] = "#eeeeee";
+-static const char col_cyan[] = "#005577";
+-static const char *colors[][3] = {
+- /* fg bg border */
+- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
++static unsigned int borderpx = 1; /* border pixel of windows */
++static unsigned int snap = 32; /* snap pixel */
++static int showbar = 1; /* 0 means no bar */
++static int topbar = 1; /* 0 means bottom bar */
++static char font[] = "monospace:size=10";
++static char dmenufont[] = "monospace:size=10";
++static const char *fonts[] = { font };
++static char normbgcolor[] = "#222222";
++static char normbordercolor[] = "#444444";
++static char normfgcolor[] = "#bbbbbb";
++static char selfgcolor[] = "#eeeeee";
++static char selbordercolor[] = "#005577";
++static char selbgcolor[] = "#005577";
++static char *colors[][3] = {
++ /* fg bg border */
++ [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor },
++ [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor },
+ };
+
+ /* tagging */
+@@ -32,9 +34,9 @@ static const Rule rules[] = {
+ };
+
+ /* layout(s) */
+-static const float mfact = 0.55; /* 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 float mfact = 0.55; /* factor of master area size [0.05..0.95] */
++static int nmaster = 1; /* number of clients in master area */
++static 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 const Layout layouts[] = {
+@@ -57,9 +59,30 @@ static const Layout layouts[] = {
+
+ /* commands */
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+-static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
++static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbordercolor, "-sf", selfgcolor, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
++/*
++ * Xresources preferences to load at startup
++ */
++ResourcePref resources[] = {
++ { "font", STRING, &font },
++ { "dmenufont", STRING, &dmenufont },
++ { "normbgcolor", STRING, &normbgcolor },
++ { "normbordercolor", STRING, &normbordercolor },
++ { "normfgcolor", STRING, &normfgcolor },
++ { "selbgcolor", STRING, &selbgcolor },
++ { "selbordercolor", STRING, &selbordercolor },
++ { "selfgcolor", STRING, &selfgcolor },
++ { "borderpx", INTEGER, &borderpx },
++ { "snap", INTEGER, &snap },
++ { "showbar", INTEGER, &showbar },
++ { "topbar", INTEGER, &topbar },
++ { "nmaster", INTEGER, &nmaster },
++ { "resizehints", INTEGER, &resizehints },
++ { "mfact", FLOAT, &mfact },
++};
++
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+diff --git a/drw.c b/drw.c
+index 4cdbcbe..8f1059e 100644
+--- a/drw.c
++++ b/drw.c
+@@ -208,7 +208,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *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)
++drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount)
+ {
+ size_t i;
+ Clr *ret;
+diff --git a/drw.h b/drw.h
+index 4bcd5ad..42b04ce 100644
+--- a/drw.h
++++ b/drw.h
+@@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
+
+ /* 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/dwm.c b/dwm.c
+index 5e4d494..2214b19 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -36,6 +36,7 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xproto.h>
+ #include <X11/Xutil.h>
++#include <X11/Xresource.h>
+ #ifdef XINERAMA
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+@@ -141,6 +142,19 @@ typedef struct {
+ int monitor;
+ } Rule;
+
++/* 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 void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+@@ -234,6 +248,8 @@ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
++static void load_xresources(void);
++static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -2127,6 +2143,60 @@ zoom(const Arg *arg)
+ pop(c);
+ }
+
++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", "dwm", 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);
++}
++
+ int
+ main(int argc, char *argv[])
+ {
+@@ -2139,6 +2209,8 @@ main(int argc, char *argv[])
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("dwm: cannot open display");
+ checkotherwm();
++ XrmInitialize();
++ load_xresources();
+ setup();
+ #ifdef __OpenBSD__
+ if (pledge("stdio rpath proc exec", NULL) == -1)
+--
+2.33.0
diff --git a/dwm/patches/dwmblocks-statuscmd-20210402-96cbb45.diff b/dwm/patches/dwmblocks-statuscmd-20210402-96cbb45.diff
new file mode 100644
index 0000000..982f93a
--- /dev/null
+++ b/dwm/patches/dwmblocks-statuscmd-20210402-96cbb45.diff
@@ -0,0 +1,126 @@
+# From 1669878c08607f481e3f879d6914fc4d3c9d7206 Mon Sep 17 00:00:00 2001
+# From: Daniel Bylinka <daniel.bylinka@gmail.com>
+# Date: Fri, 2 Apr 2021 19:20:17 +0200
+# Subject: [PATCH] [statuscmd] Format status text and handle button signals
+#
+# ---
+# dwmblocks.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
+# 1 file changed, 41 insertions(+), 7 deletions(-)
+
+diff --git a/dwmblocks.c b/dwmblocks.c
+index ded717c..78fdeb5 100644
+--- a/dwmblocks.c
++++ b/dwmblocks.c
+@@ -3,6 +3,7 @@
+ #include<string.h>
+ #include<unistd.h>
+ #include<signal.h>
++#include<sys/wait.h>
+ #ifndef NO_X
+ #include<X11/Xlib.h>
+ #endif
+@@ -27,14 +28,14 @@ typedef struct {
+ #ifndef __OpenBSD__
+ void dummysighandler(int num);
+ #endif
+-void sighandler(int num);
+ void getcmds(int time);
+ void getsigcmds(unsigned int signal);
+ void setupsignals();
+-void sighandler(int signum);
++void sighandler(int signum, siginfo_t *si, void *ucontext);
+ int getstatus(char *str, char *last);
+ void statusloop();
+ void termhandler();
++void chldhandler();
+ void pstdout();
+ #ifndef NO_X
+ void setroot();
+@@ -58,6 +59,8 @@ static int returnStatus = 0;
+ //opens process *cmd and stores output in *output
+ void getcmd(const Block *block, char *output)
+ {
++ if (block->signal)
++ *output++ = block->signal;
+ strcpy(output, block->icon);
+ FILE *cmdf = popen(block->command, "r");
+ if (!cmdf)
+@@ -102,15 +105,18 @@ void getsigcmds(unsigned int signal)
+
+ void setupsignals()
+ {
++ struct sigaction sa = { .sa_sigaction = sighandler, .sa_flags = SA_SIGINFO };
+ #ifndef __OpenBSD__
+ /* initialize all real time signals with dummy handler */
+- for (int i = SIGRTMIN; i <= SIGRTMAX; i++)
++ for (int i = SIGRTMIN; i <= SIGRTMAX; i++) {
+ signal(i, dummysighandler);
++ sigaddset(&sa.sa_mask, i);
++ }
+ #endif
+
+ for (unsigned int i = 0; i < LENGTH(blocks); i++) {
+ if (blocks[i].signal > 0)
+- signal(SIGMINUS+blocks[i].signal, sighandler);
++ sigaction(SIGMINUS+blocks[i].signal, &sa, NULL);
+ }
+
+ }
+@@ -178,10 +184,32 @@ void dummysighandler(int signum)
+ }
+ #endif
+
+-void sighandler(int signum)
++void sighandler(int signum, siginfo_t *si, void *ucontext)
+ {
+- getsigcmds(signum-SIGPLUS);
+- writestatus();
++ if (si->si_value.sival_int) {
++ pid_t parent = getpid();
++ if (fork() == 0) {
++#ifndef NO_X
++ if (dpy)
++ close(ConnectionNumber(dpy));
++#endif
++ int i;
++ for (i = 0; i < LENGTH(blocks) && blocks[i].signal != signum-SIGRTMIN; i++);
++
++ char shcmd[1024];
++ sprintf(shcmd, "%s; kill -%d %d", blocks[i].command, SIGRTMIN+blocks[i].signal, parent);
++ char *cmd[] = { "/bin/sh", "-c", shcmd, NULL };
++ char button[2] = { '0' + si->si_value.sival_int, '\0' };
++ setenv("BUTTON", button, 1);
++ setsid();
++ execvp(cmd[0], cmd);
++ perror(cmd[0]);
++ exit(EXIT_SUCCESS);
++ }
++ } else {
++ getsigcmds(signum-SIGPLUS);
++ writestatus();
++ }
+ }
+
+ void termhandler()
+@@ -189,6 +217,11 @@ void termhandler()
+ statusContinue = 0;
+ }
+
++void chldhandler()
++{
++ while (0 < waitpid(-1, NULL, WNOHANG));
++}
++
+ int main(int argc, char** argv)
+ {
+ for (int i = 0; i < argc; i++) {//Handle command line arguments
+@@ -205,6 +238,7 @@ int main(int argc, char** argv)
+ delim[delimLen++] = '\0';
+ signal(SIGTERM, termhandler);
+ signal(SIGINT, termhandler);
++ signal(SIGCHLD, chldhandler);
+ statusloop();
+ #ifndef NO_X
+ XCloseDisplay(dpy);
+--
+2.31.0
diff --git a/dwm/shift-tools-scratchpads.c b/dwm/shift-tools-scratchpads.c
index a8e15d8..d1dc6b5 100644
--- a/dwm/shift-tools-scratchpads.c
+++ b/dwm/shift-tools-scratchpads.c
@@ -160,3 +160,10 @@ shiftswaptags(const Arg *arg)
// uncomment if you also want to "go" (view) the tag where the the clients are going
//view(&shifted);
}
+void
+tagandview(const Arg *arg)
+{
+ tag(arg);
+ view(arg);
+}
+
diff --git a/dwm/tagandview.c b/dwm/tagandview.c
deleted file mode 100644
index 0f98214..0000000
--- a/dwm/tagandview.c
+++ /dev/null
@@ -1,4 +0,0 @@
-void tagandview(const Arg *arg) {
- tag(arg);
- view(arg);
-}
diff --git a/dwm/thesiah-default.mom b/dwm/thesiah-default.mom
deleted file mode 100644
index fdf9173..0000000
--- a/dwm/thesiah-default.mom
+++ /dev/null
@@ -1,188 +0,0 @@
-.de LI
-.LIST
-.SHIFT_LIST 10p
-..
-.PARA_SPACE 1m
-.TITLE "\s+(10A Friendly Guide to THESIAH!\s0"
-.AUTHOR "\s+5Soomin Im\s0"
-.DOCTYPE DEFAULT
-.COPYSTYLE FINAL
-.PRINTSTYLE TYPESET
-.PT_SIZE 12
-.START
-Use vim keys (\f(CWh/j/k/l\fP) to navigate this document.
-Pressing \f(CWs\fP will fit it to window width (\f(CWa\fP to revert).
-\f(CWK\fP and \f(CWJ\fP zoom in and out.
-\f(CWSuper+f\fP to toggle fullscreen.
-\f(CWq\fP to quit.
-\f(CW/\fP to search for text.
-(These are general binds set for \fBzathura\fP, the pdf reader.)
-.LI
-.ITEM
-\f(CWMod+F1\fP will show this document at any time.
-.ITEM
-By \f(CWMod\fP, I mean the Super Key, usually known as "the Windows Key."
-.LIST OFF
-.PP
-FAQs are at the end of this document.
-.HEADING 1 "Welcome!"
-.HEADING 2 "Basic goals and principles of this system:"
-.LI
-.ITEM
-\fBNaturalness\fP \(en
-Remove the border between mind and matter:
-everything important should be as few keypresses as possible away from you,
-and you shouldn't have to think about what you're doing.
-Immersion.
-.ITEM
-\fBEconomy\fP \(en
-Programs should be simple and light on system resources and highly extensible.
-Because of this, many are terminal or small ncurses programs that have all the magic inside of them.
-.ITEM
-\fBKeyboard/vim-centrality\fP \(en
-All terminal programs (and other programs) use vim keys when possible.
-Your hands never need leave the home row or thereabout.
-.ITEM
-\fBDecentralization\fP \(en
-This system is a web of small, modifiable and replaceable programs that users can easily customize.
-.LIST OFF
-.HEADING 2 "General keyboard changes"
-.LI
-.ITEM
-Capslock is a useless key in high quality space.
-It's now remapped.
-If you press it alone, it will function as escape, making vimcraft much more natural,
-but you can also hold it down and it will act as another Windows/super/mod key.
-.ITEM
-The menu button (usually between the right Alt and Ctrl) is an alternative Super/Mod button.
-This is to make one-handing on laptops easier.
-.LIST OFF
-.PP
-If you'd like to change any of these keyboard changes, you need only open and change the \f(CWremaps\fP script.
-All custom scripts in THESIAH are located in \f(CW~/.local/bin/\fP.
-Actually, this should go without saying, but \fIeverything\fP here can easily be changed.
-Below in this document, there is information about where to change programs/components.
-.PP
-Additionally, while this isn't a part of the desktop environment, the default editing mode in the shell is using vi bindings.
-If you want to learn more of this, run \f(CWMod+F2\fP and type and select the option for "vi mode in shell".
-This setting can be changed if you don't like it by deleting or commenting out the contents of \f(CW~/.config/shell/inputrc\fP.
-.HEADING 2 "The Status Bar"
-.PP
-To the left, you'll see the numbers of your current workspace/tag(s).
-On the right, you'll see various system status notifiers, the date, volume, even music and local weather if possible, etc.
-Each module on the right of the statusbar is a script located in \f(CW~/.local/bin/statusbar/\fP.
-You can see what they do and modify them from there.
-I'm sure you can figure it out.
-You can also right click on the module to see what it does.
-.PP
-The program dwmblocks is what is run to generate the statusbar from those scripts.
-You can edit its config/source code in \f(CW~/.local/src/suckless/dwmblocks/\fP to tell it what scripts/commands you want it to display.
-Alternatively, you can open the script by \f(CWShift+left click\fP on a program in the status bar. This is a default setting for all programs in status bar. Buttons are \f(CWleft click\fP, \f(CWmiddle click\fP, and \f(CWright click\fP. You can combine with a modifier, \f(CWShift\fP or \f(CWControl\fP.
-.HEADING 3 "HiDPI and 4K Displays"
-.PP
-If you have a screen with a very high dots-per-inch, the interface, particularly the status bar at the top may be very small. To change this, you can run \f(CWxrandr --dpi 96\fP, replacing 96 with a higher number, then you can refresh the window manager in the menu at \f(CWsuper+backspace\fP. To make this change persistent after reboot, edit \f(CW~/.xprofile\fP and you will see that same command which you can change to have the dots-per-inch value you want.
-.HEADING 2 "Deeper Tutorials"
-.PP
-Press \f(CWmod+F2\fP at any time to get a menu of programs to watch videos about streaming directly from YouTube.
-You can also check the config files for programs which detail a lot of the specific bindings.
-.HEADING 1 "Key Bindings"
-.PP
-The window manager dwm abstractly orders all of your windows into a stack from most important to least based on when you last manipulated it.
-dwm is an easy to use window manager, but you should understand that it makes use of that stack layout.
-If you're not familiar, I recommend you press \f(CWMod+F2\fP and select the "dwm" option to watch my brief tutorial (note that the bindings I discuss in the video are the default dwm binds, which are different (inferior) to those here).
-.PP
-Notice also the case sensitivity of the shortcuts\c
-.FOOTNOTE
-To type capital letters, hold down the \f(CWShift\fP key\(emthat might sound like an obvious and condescending thing to tell you, but there have literally been multiple people (Boomers) who have emailed me asking how to type a capital letter since caps lock isn't enabled.
-.FOOTNOTE OFF
- , Be sure you play around with these. Be flexible with the basic commands and the system will grow on you quick.
-.HEADING 2 "Suckless Programs"
-.PP
-The \f(CWMOD\fP key differs between DWM and ST. In DWM, if the \f(CWMOD\fP key is the \f(CWSuper\fP key, then in ST, the \f(CWMOD\fP key is the \f(CWAlt\fP key. Conversely, if the \f(CWMOD\fP key in DWM is the \f(CWAlt\fP key, then in ST, the \f(CWMOD\fP key is the \f(CWSuper\fP key.
-.PP
-When config.def.h in DWM and ST is saved, key bindings will be extracted and updated below.
-.HEADING 2 "Other buttons"
-.PP
-I've mapped those extra buttons that some keyboards have (play and pause buttons, screen brightness, email, web browsing buttons, etc.) to what you would expect. Even there are gestures for simple mouse movements (up, down, left, and right). Each movement opens or runs a program.
-.PP
-Check files under .config/shell, .config/zsh, and .local/share/thesiah. There are also files under .config.
-.HEADING 1 "Configuration"
-.PP
-Dotfiles/settings files are located in \f(CW~/.dotfiles/\fP and \f(CW~/.config/\fP.
-.PP
-Suckless programs, dwm (the window manager), st (the terminal), dmenu (the dynamic menu), and slock (the screen locker) among others do not have traditional config files, but have their source code location in \f(CW~/.local/src/suckless/\fP (press \f(CWrr\fP to jump to that directory).
-There you can modify their \f(CWconfig.def.h\fP files or other source code, then \f(CWsudo make install\fP to reinstall.
-.PP
-vim is set to automatically recompile and install these programs whenever you save changes to any \f(CWconfig.def.h\fP file
-(compilation will be nearly instantaneous).
-You'll have to restart the program to see its effects obviously.
-.HEADING 1 "Frequently Asked Questions (FAQs)"
-.HEADING 2 "My keyboard isn't working as expected!"
-.PP
-As mentioned above, THESIAH makes some keyboard changes with the \f(CWremaps\fP script.
-These settings may override your preferred settings, so you should open this file and comment out troublesome lines if you have issues.
-.HEADING 2 "My audio isn't working!"
-.PP
-On fresh install, the Linux audio system often mutes outputs.
-You may also need to set your preferred default output sink which you can do by the command line, or by selecting one with \f(CWpulsemixer\fP (\f(CWMod+F4\fP).
-.HEADING 2 "How do I copy and paste?"
-.PP
-Copying and pasting is always program-specific on any system.
-In most graphical programs, copy and paste will be the same as they are on Windows: \f(CWctrl-c\fP and \f(CWctrl-v\fP.
-In the Linux terminal, those binds have other more important purposes, so you can run \f(CWman st\fP to see how to copy and paste in my terminal build.
-To paste the copied/saved content from the clipboard in dmenu, use \f(CWshift+ctrl-y\fP.
-.PP
-Additionally, I've set vim to use the clipboard as the default buffer, which means when you yank or delete something in vim, it will be in your system clipboard as well, so you can \f(CWctrl-p\fP it into your browser instance, etc. You can also paste material copied from other programs into vim with the typical vim bindings.
-.HEADING 2 "How do I change the background/wallpaper?"
-.PP
-The system will always read the file \f(CW~/.local/share/bg\fP as the wallpaper.
-The script \f(CWsetbg\fP, if run on an image will set it as the persistent background.
-When using the file manager, you can simply hover over an image name and type \f(CWb\fP and this will run \f(CWsetbg\fP.
-.HEADING 2 "How I change the colorscheme?"
-.PP
-THESIAH no longer deploys Xresources by default, but check \f(CW~/.config/x11/xresources\fP for a list of color schemes you can activate or add your own. When you save the file, vim will automatically update the colorscheme. If you'd like these colors activated by default on login, there is a line in \f(CW~/.config/x11/xprofile\fP you can uncomment to allow that.
-.PP
-Or, if you want to use \f(CWwal\fP to automatically generate colorschemes from your wallpapers, just install it and \f(CWsetbg\fP will automatically detect and run it on startup and wallpaper change.
-.HEADING 2 "How do I set up my email?"
-.PP
-THESIAH comes with mutt-wizard, which gives the ability to receive and send all your email and keep an offline store of it all in your terminal, without the need for browser.
-You can add email accounts by running \f(CWmw -a your@email.com\fP.
-See \f(CWman mw\fP for all the information you need about mutt-wizard.
-.PP
-Once you have successfully added your email address(es), you can open your mail with \f(CWneomutt\fP which is also bound to \f(CWMod+e\fP.
-You can sync your mail by pressing \f(CWMod+F8\fP and you can set a cronjob to sync mail every 10 minutes by running \f(CWmw -t 10\fP.
-.PP
-You may also want to install \f(CWpam-gnupg-git\fP, which can be set up to automatically unlock your GPG key on login, which will allow you avoid having put in a password to sync and send, all while keeping your password safe and encrypted on your machine.
-.HEADING 2 "How do I set up my music?"
-.PP
-By default, mpd, the music daemon assumes that \f(CW~/Music\fP is your music directory.
-This can be changed in \f(CW~/.config/mpd/mpd.conf\fP.
-When you add music to your music folder, you may have to run \f(CWmpc up\fP in the terminal to update the database.
-mpd is controlled by ncmpcpp, which is accessible by \f(CWMod+m\fP.
-.HEADING 2 "How do I update THESIAH?"
-.PP
-THESIAH is deployed as a git repository in your home directory.
-You can use it as such to fetch, diff and merge changes from the remote repository.
-If you don't want to do that or don't know how to use git, you can actually just rerun the script (as root) and reinstall THESIAH and it will automatically update an existing install if you select the same username.
-This will overwrite the original config files though, including changes you made for them, but this is an easier brute force approach that will also install any new dependencies.
-.HEADING 1 "Important Links"
-.PP
-You can follow links via the keyboard in this pdf reader by pressing \f(CWf\fP followed by the number that appears on the desired link.
-.LI
-.ITEM
-.PDF_WWW_LINK "mailto:si@thesiah.xyz" "si@thesiah.xyz"
-\(en For questions!
-.ITEM
-.PDF_WWW_LINK "http://thesiah.xyz" "https://thesiah.xyz"
-\(en For stalking!
-.ITEM
-.PDF_WWW_LINK "https://thesiah.xyz/donate" "https://thesiah.xyz/donate"
-\(en To incentivize more development of THESIAH!
-.ITEM
-.PDF_WWW_LINK "https://github.com/TheSiahxyz" "https://github.com/TheSiahxyz"
-\(en For the code behind it!
-.ITEM
-.PDF_WWW_LINK "http://thesiah.xyz/rss.xml" "RSS"
-\(en For updates!
-.LIST OFF
-.END
diff --git a/dwm/unpatched/dwm-preview-all-windows-6.5.diff b/dwm/unpatched/dwm-preview-all-windows-6.5.diff
new file mode 100644
index 0000000..93e5d25
--- /dev/null
+++ b/dwm/unpatched/dwm-preview-all-windows-6.5.diff
@@ -0,0 +1,287 @@
+diff --git a/config.def.h b/config.def.h
+index 9efa774..f462e32 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -95,6 +95,7 @@ static const Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_r, previewallwin, {0} },
+ };
+
+ /* button definitions */
+diff --git a/config.mk b/config.mk
+index 8efca9a..8d7c303 100644
+--- a/config.mk
++++ b/config.mk
+@@ -23,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2
+
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 -lXrender -lXcomposite ${XINERAMALIBS} ${FREETYPELIBS}
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/dwm.c b/dwm.c
+index 67c6b2b..0ddd58e 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -40,6 +40,8 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <X11/extensions/Xcomposite.h>
++#include <X11/extensions/Xrender.h>
+
+ #include "drw.h"
+ #include "util.h"
+@@ -84,6 +86,16 @@ typedef struct {
+
+ typedef struct Monitor Monitor;
+ typedef struct Client Client;
++
++typedef struct Preview Preview;
++struct Preview {
++ XImage *orig_image;
++ XImage *scaled_image;
++ Window win;
++ unsigned int x, y;
++ Preview *next;
++};
++
+ struct Client {
+ char name[256];
+ float mina, maxa;
+@@ -97,6 +109,7 @@ struct Client {
+ Client *snext;
+ Monitor *mon;
+ Window win;
++ Preview pre;
+ };
+
+ typedef struct {
+@@ -233,6 +246,10 @@ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
++static void previewallwin();
++static void setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi);
++static XImage *getwindowximage(Client *c);
++static XImage *scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -2140,6 +2157,212 @@ zoom(const Arg *arg)
+ pop(c);
+ }
+
++void
++previewallwin(){
++ int composite_event_base, composite_error_base;
++ if (!XCompositeQueryExtension(dpy, &composite_event_base, &composite_error_base)) {
++ fprintf(stderr, "Error: XComposite extension not available.\n");
++ return;
++ }
++ Monitor *m = selmon;
++ Client *c, *focus_c = NULL;
++ unsigned int n;
++ for (n = 0, c = m->clients; c; c = c->next, n++){
++ /* If you hit actualfullscreen patch Unlock the notes below */
++ // if (c->isfullscreen)
++ // togglefullscr(&(Arg){0});
++ /* If you hit awesomebar patch Unlock the notes below */
++ // if (HIDDEN(c))
++ // continue;
++ c->pre.orig_image = getwindowximage(c);
++ }
++ if (n == 0)
++ return;
++ setpreviewwindowsizepositions(n, m, 60, 15);
++ XEvent event;
++ for(c = m->clients; c; c = c->next){
++ if (!c->pre.win)
++ c->pre.win = XCreateSimpleWindow(dpy, root, c->pre.x, c->pre.y, c->pre.scaled_image->width, c->pre.scaled_image->height, 1, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
++ else
++ XMoveResizeWindow(dpy, c->pre.win, c->pre.x, c->pre.y, c->pre.scaled_image->width, c->pre.scaled_image->height);
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
++ XSetWindowBorderWidth(dpy, c->pre.win, borderpx);
++ XUnmapWindow(dpy, c->win);
++ if (c->pre.win){
++ XSelectInput(dpy, c->pre.win, ButtonPress | EnterWindowMask | LeaveWindowMask );
++ XMapWindow(dpy, c->pre.win);
++ XPutImage(dpy, c->pre.win, drw->gc, c->pre.scaled_image, 0, 0, 0, 0, c->pre.scaled_image->width, c->pre.scaled_image->height);
++ }
++ }
++ while (1) {
++ XNextEvent(dpy, &event);
++ if (event.type == ButtonPress)
++ if (event.xbutton.button == Button1){
++ for(c = m->clients; c; c = c->next){
++ XUnmapWindow(dpy, c->pre.win);
++ if (event.xbutton.window == c->pre.win){
++ selmon->seltags ^= 1; /* toggle sel tagset */
++ m->tagset[selmon->seltags] = c->tags;
++ focus_c = c;
++ focus(NULL);
++ /* If you hit awesomebar patch Unlock the notes below */
++ // if (HIDDEN(c)){
++ // showwin(c);
++ // continue;
++ // }
++ }
++ /* If you hit awesomebar patch Unlock the notes below;
++ * And you should add the following line to "hidewin" Function
++ * c->pre.orig_image = getwindowximage(c);
++ * */
++ // if (HIDDEN(c)){
++ // continue;
++ // }
++ XMapWindow(dpy, c->win);
++ XDestroyImage(c->pre.orig_image);
++ XDestroyImage(c->pre.scaled_image);
++ }
++ break;
++ }
++ if (event.type == EnterNotify)
++ for(c = m->clients; c; c = c->next)
++ if (event.xcrossing.window == c->pre.win){
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeSel][ColBorder].pixel);
++ break;
++ }
++ if (event.type == LeaveNotify)
++ for(c = m->clients; c; c = c->next)
++ if (event.xcrossing.window == c->pre.win){
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
++ break;
++ }
++ }
++ arrange(m);
++ focus(focus_c);
++}
++
++void
++setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi){
++ unsigned int i, j;
++ unsigned int cx, cy, cw, ch, cmaxh;
++ unsigned int cols, rows;
++ Client *c, *tmpc;
++
++ if (n == 1) {
++ c = m->clients;
++ cw = (m->ww - 2 * gappo) * 0.8;
++ ch = (m->wh - 2 * gappo) * 0.9;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width) / 2;
++ c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
++ return;
++ }
++ if (n == 2) {
++ c = m->clients;
++ cw = (m->ww - 2 * gappo - gappi) / 2;
++ ch = (m->wh - 2 * gappo) * 0.7;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->next->pre.scaled_image = scaledownimage(c->next->pre.orig_image, cw, ch);
++ c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width - gappi - c->next->pre.scaled_image->width) / 2;
++ c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
++ c->next->pre.x = c->pre.x + c->pre.scaled_image->width + gappi;
++ c->next->pre.y = m->my + (m->mh - c->next->pre.scaled_image->height) / 2;
++ return;
++ }
++ for (cols = 0; cols <= n / 2; cols++)
++ if (cols * cols >= n)
++ break;
++ rows = (cols && (cols - 1) * cols >= n) ? cols - 1 : cols;
++ ch = (m->wh - 2 * gappo) / rows;
++ cw = (m->ww - 2 * gappo) / cols;
++ c = m->clients;
++ cy = 0;
++ for (i = 0; i < rows; i++) {
++ cx = 0;
++ cmaxh = 0;
++ tmpc = c;
++ for (int j = 0; j < cols; j++) {
++ if (!c)
++ break;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->pre.x = cx;
++ cmaxh = c->pre.scaled_image->height > cmaxh ? c->pre.scaled_image->height : cmaxh;
++ cx += c->pre.scaled_image->width + gappi;
++ c = c->next;
++ }
++ c = tmpc;
++ cx = m->wx + (m->ww - cx) / 2;
++ for (j = 0; j < cols; j++) {
++ if (!c)
++ break;
++ c->pre.x += cx;
++ c->pre.y = cy + (cmaxh - c->pre.scaled_image->height) / 2;
++ c = c->next;
++ }
++ cy += cmaxh + gappi;
++ }
++ cy = m->wy + (m->wh - cy) / 2;
++ for (c = m->clients; c; c = c->next)
++ c->pre.y += cy;
++}
++
++XImage
++*getwindowximage(Client *c) {
++ XCompositeRedirectWindow(dpy, c->win, CompositeRedirectAutomatic);
++ XWindowAttributes attr;
++ XGetWindowAttributes( dpy, c->win, &attr );
++ XRenderPictFormat *format = XRenderFindVisualFormat( dpy, attr.visual );
++ int hasAlpha = ( format->type == PictTypeDirect && format->direct.alphaMask );
++ XRenderPictureAttributes pa;
++ pa.subwindow_mode = IncludeInferiors;
++ Picture picture = XRenderCreatePicture( dpy, c->win, format, CPSubwindowMode, &pa );
++ Pixmap pixmap = XCreatePixmap(dpy, root, c->w, c->h, 32);
++ XRenderPictureAttributes pa2;
++ XRenderPictFormat *format2 = XRenderFindStandardFormat(dpy, PictStandardARGB32);
++ Picture pixmapPicture = XRenderCreatePicture( dpy, pixmap, format2, 0, &pa2 );
++ XRenderColor color;
++ color.red = 0x0000;
++ color.green = 0x0000;
++ color.blue = 0x0000;
++ color.alpha = 0x0000;
++ XRenderFillRectangle (dpy, PictOpSrc, pixmapPicture, &color, 0, 0, c->w, c->h);
++ XRenderComposite(dpy, hasAlpha ? PictOpOver : PictOpSrc, picture, 0,
++ pixmapPicture, 0, 0, 0, 0, 0, 0,
++ c->w, c->h);
++ XImage* temp = XGetImage( dpy, pixmap, 0, 0, c->w, c->h, AllPlanes, ZPixmap );
++ temp->red_mask = format2->direct.redMask << format2->direct.red;
++ temp->green_mask = format2->direct.greenMask << format2->direct.green;
++ temp->blue_mask = format2->direct.blueMask << format2->direct.blue;
++ temp->depth = DefaultDepth(dpy, screen);
++ XCompositeUnredirectWindow(dpy, c->win, CompositeRedirectAutomatic);
++ return temp;
++}
++
++XImage
++*scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch) {
++ int factor_w = orig_image->width / cw + 1;
++ int factor_h = orig_image->height / ch + 1;
++ int scale_factor = factor_w > factor_h ? factor_w : factor_h;
++ int scaled_width = orig_image->width / scale_factor;
++ int scaled_height = orig_image->height / scale_factor;
++ XImage *scaled_image = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)),
++ orig_image->depth,
++ ZPixmap, 0, NULL,
++ scaled_width, scaled_height,
++ 32, 0);
++ scaled_image->data = malloc(scaled_image->height * scaled_image->bytes_per_line);
++ for (int y = 0; y < scaled_height; y++) {
++ for (int x = 0; x < scaled_width; x++) {
++ int orig_x = x * scale_factor;
++ int orig_y = y * scale_factor;
++ unsigned long pixel = XGetPixel(orig_image, orig_x, orig_y);
++ XPutPixel(scaled_image, x, y, pixel);
++ }
++ }
++ scaled_image->depth = orig_image->depth;
++ return scaled_image;
++}
++
+ int
+ main(int argc, char *argv[])
+ {
diff --git a/dwm/unpatched/dwm-tag-preview-6.3.diff b/dwm/unpatched/dwm-tag-preview-6.3.diff
new file mode 100644
index 0000000..514690c
--- /dev/null
+++ b/dwm/unpatched/dwm-tag-preview-6.3.diff
@@ -0,0 +1,314 @@
+# From 841ad7d5767f945ee9da6c5afc8cff98ca2f8231 Mon Sep 17 00:00:00 2001
+# From: explosion-mental <explosion0mental@gmail.com>
+# Date: Thu, 1 Sep 2022 16:21:58 -0500
+# Subject: [PATCH] [PATCH] tag previews: free() tagmap and add previewtag func
+#
+# Allows you to see the contents of an already viewed tag. So a more
+# accurate description would be to re-view a tag.
+#
+# Allows you to see the contents of an already viewed tag. So a more
+# accurate description would be to re-view a tag.
+#
+# Compatibility with the alpha patch (replacing DefaultDepth() and
+# DefaultVisual() with depth and visual + window masks) and hide vacants can be
+# achieved, I left some lines to uncomment.
+#
+# added:
+# * more compact structure, more probable to patch on top of other patches
+# or easier to patch manually (like not moving the Monitor struct..)
+# * create the window preview in updatebars()
+# * renamed switchtag() -> takepreview(), makes more sense since it's
+# "taking" the preview (basically a screenshot).
+# * option previewbar, whether to show the bar in the preview or not.
+# * previewtag which takes a tag (unsigned int from 0 to the last tag) and
+# previews it. This allows to preview tags without using the
+# cursor/mouse (which avoids a recursive previews preview).
+# adding it to the TAGKEYS macro makes more sense so I've added it
+# replacing (keybinding wise, not functionality) toggletag.
+# ```
+# \#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, previewtag, {.ui = TAG } },
+# ```
+# ---
+# config.def.h | 4 +-
+# config.mk | 5 +-
+# dwm.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+# 3 files changed, 145 insertions(+), 3 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..eb70348 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -3,6 +3,8 @@
+ /* appearance */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
++static const int scalepreview = 4; /* preview scaling (display w and h / scalepreview) */
++static const int previewbar = 1; /* show the bar in the preview window */
+ static const int showbar = 1; /* 0 means no bar */
+ static const int topbar = 1; /* 0 means bottom bar */
+ static const char *fonts[] = { "monospace:size=10" };
+@@ -50,7 +52,7 @@ static const Layout layouts[] = {
+ { 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} },
++ { MODKEY|ControlMask|ShiftMask, KEY, previewtag, {.ui = TAG } }, \
+
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+diff --git a/config.mk b/config.mk
+index b6eb7e0..6f5129e 100644
+--- a/config.mk
++++ b/config.mk
+@@ -20,9 +20,12 @@ FREETYPEINC = /usr/include/freetype2
+ # OpenBSD (uncomment)
+ #FREETYPEINC = ${X11INC}/freetype2
+
++# Imlib2 (tag previews)
++IMLIB2LIBS = -lImlib2
++
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${IMLIB2LIBS}
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/dwm.c b/dwm.c
+index a96f33c..0c0ba12 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -40,6 +40,7 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <Imlib2.h>
+
+ #include "drw.h"
+ #include "util.h"
+@@ -112,6 +113,9 @@ typedef struct {
+ } Layout;
+
+ struct Monitor {
++ int previewshow;
++ Window tagwin;
++ Pixmap *tagmap;
+ char ltsymbol[16];
+ float mfact;
+ int nmaster;
+@@ -235,6 +239,10 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
+
++static void showtagpreview(unsigned int i);
++static void takepreview(void);
++static void previewtag(const Arg *arg);
++
+ /* variables */
+ static const char broken[] = "broken";
+ static char stext[256];
+@@ -438,6 +446,11 @@ buttonpress(XEvent *e)
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+ arg.ui = 1 << i;
++ /* hide preview if we click the bar */
++ if (selmon->previewshow) {
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ }
+ } else if (ev->x < x + blw)
+ click = ClkLtSymbol;
+ else if (ev->x > selmon->ww - (int)TEXTW(stext))
+@@ -498,6 +511,7 @@ void
+ cleanupmon(Monitor *mon)
+ {
+ Monitor *m;
++ size_t i;
+
+ if (mon == mons)
+ mons = mons->next;
+@@ -505,8 +519,14 @@ cleanupmon(Monitor *mon)
+ for (m = mons; m && m->next != mon; m = m->next);
+ m->next = mon->next;
+ }
++ for (i = 0; i < LENGTH(tags); i++)
++ if (mon->tagmap[i])
++ XFreePixmap(dpy, mon->tagmap[i]);
++ free(mon->tagmap);
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
++ XUnmapWindow(dpy, mon->tagwin);
++ XDestroyWindow(dpy, mon->tagwin);
+ free(mon);
+ }
+
+@@ -641,6 +661,7 @@ createmon(void)
+ m->topbar = topbar;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
++ m->tagmap = ecalloc(LENGTH(tags), sizeof(Pixmap));
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ return m;
+ }
+@@ -1125,6 +1146,36 @@ motionnotify(XEvent *e)
+ static Monitor *mon = NULL;
+ Monitor *m;
+ XMotionEvent *ev = &e->xmotion;
++ unsigned int i, x;
++
++ if (ev->window == selmon->barwin) {
++ i = x = 0;
++ do
++ x += TEXTW(tags[i]);
++ while (ev->x >= x && ++i < LENGTH(tags));
++ /* FIXME when hovering the mouse over the tags and we view the tag,
++ * the preview window get's in the preview shot */
++
++ if (i < LENGTH(tags)) {
++ if (selmon->previewshow != (i + 1)
++ && !(selmon->tagset[selmon->seltags] & 1 << i)) {
++ selmon->previewshow = i + 1;
++ showtagpreview(i);
++ } else if (selmon->tagset[selmon->seltags] & 1 << i) {
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ }
++ } else if (selmon->previewshow) {
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ }
++ } else if (ev->window == selmon->tagwin) {
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ } else if (selmon->previewshow) {
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ }
+
+ if (ev->window != root)
+ return;
+@@ -1530,6 +1581,82 @@ setmfact(const Arg *arg)
+ arrange(selmon);
+ }
+
++void
++showtagpreview(unsigned int i)
++{
++ if (!selmon->previewshow || !selmon->tagmap[i]) {
++ XUnmapWindow(dpy, selmon->tagwin);
++ return;
++ }
++
++ XSetWindowBackgroundPixmap(dpy, selmon->tagwin, selmon->tagmap[i]);
++ XCopyArea(dpy, selmon->tagmap[i], selmon->tagwin, drw->gc, 0, 0,
++ selmon->mw / scalepreview, selmon->mh / scalepreview,
++ 0, 0);
++ XSync(dpy, False);
++ XMapRaised(dpy, selmon->tagwin);
++}
++
++void
++takepreview(void)
++{
++ Client *c;
++ Imlib_Image image;
++ unsigned int occ = 0, i;
++
++ for (c = selmon->clients; c; c = c->next)
++ occ |= c->tags;
++ //occ |= c->tags == 255 ? 0 : c->tags; /* hide vacants */
++
++ for (i = 0; i < LENGTH(tags); i++) {
++ /* searching for tags that are occupied && selected */
++ if (!(occ & 1 << i) || !(selmon->tagset[selmon->seltags] & 1 << i))
++ continue;
++
++ if (selmon->tagmap[i]) { /* tagmap exist, clean it */
++ XFreePixmap(dpy, selmon->tagmap[i]);
++ selmon->tagmap[i] = 0;
++ }
++
++ /* try to unmap the window so it doesn't show the preview on the preview */
++ selmon->previewshow = 0;
++ XUnmapWindow(dpy, selmon->tagwin);
++ XSync(dpy, False);
++
++ if (!(image = imlib_create_image(sw, sh))) {
++ fprintf(stderr, "dwm: imlib: failed to create image, skipping.");
++ continue;
++ }
++ imlib_context_set_image(image);
++ imlib_context_set_display(dpy);
++ /* uncomment if using alpha patch */
++ // imlib_image_set_has_alpha(1);
++ // imlib_context_set_blend(0);
++ // imlib_context_set_visual(visual);
++ imlib_context_set_visual(DefaultVisual(dpy, screen));
++ imlib_context_set_drawable(root);
++
++ if (previewbar)
++ imlib_copy_drawable_to_image(0, selmon->wx, selmon->wy, selmon->ww, selmon->wh, 0, 0, 1);
++ else
++ imlib_copy_drawable_to_image(0, selmon->mx, selmon->my, selmon->mw ,selmon->mh, 0, 0, 1);
++ selmon->tagmap[i] = XCreatePixmap(dpy, selmon->tagwin, selmon->mw / scalepreview, selmon->mh / scalepreview, DefaultDepth(dpy, screen));
++ imlib_context_set_drawable(selmon->tagmap[i]);
++ imlib_render_image_part_on_drawable_at_size(0, 0, selmon->mw, selmon->mh, 0, 0, selmon->mw / scalepreview, selmon->mh / scalepreview);
++ imlib_free_image();
++ }
++}
++
++void
++previewtag(const Arg *arg)
++{
++ if (selmon->previewshow != (arg->ui + 1))
++ selmon->previewshow = arg->ui + 1;
++ else
++ selmon->previewshow = 0;
++ showtagpreview(arg->ui);
++}
++
+ void
+ setup(void)
+ {
+@@ -1746,6 +1873,7 @@ toggleview(const Arg *arg)
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+
+ if (newtagset) {
++ takepreview();
+ selmon->tagset[selmon->seltags] = newtagset;
+ focus(NULL);
+ arrange(selmon);
+@@ -1811,10 +1939,18 @@ updatebars(void)
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+ .background_pixmap = ParentRelative,
+- .event_mask = ButtonPressMask|ExposureMask
++ .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask
+ };
++
+ XClassHint ch = {"dwm", "dwm"};
+ for (m = mons; m; m = m->next) {
++ if (!m->tagwin) {
++ m->tagwin = XCreateWindow(dpy, root, m->wx, m->by + bh, m->mw / scalepreview,
++ m->mh / scalepreview, 0, DefaultDepth(dpy, screen), CopyFromParent,
++ DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
++ XDefineCursor(dpy, m->tagwin, cursor[CurNormal]->cursor);
++ XUnmapWindow(dpy, m->tagwin);
++ }
+ if (m->barwin)
+ continue;
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+@@ -2043,6 +2179,7 @@ view(const Arg *arg)
+ {
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
++ takepreview();
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+--
+2.37.3
diff --git a/dwm/util.c b/dwm/util.c
index 96b82c9..8e26a51 100644
--- a/dwm/util.c
+++ b/dwm/util.c
@@ -1,4 +1,5 @@
/* See LICENSE file for copyright and license details. */
+#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -10,17 +11,17 @@ void
die(const char *fmt, ...)
{
va_list ap;
+ int saved_errno;
+
+ saved_errno = errno;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
- if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
- fputc(' ', stderr);
- perror(NULL);
- } else {
- fputc('\n', stderr);
- }
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':')
+ fprintf(stderr, " %s", strerror(saved_errno));
+ fputc('\n', stderr);
exit(1);
}
diff --git a/dwm/util.h b/dwm/util.h
index f633b51..c0a50d4 100644
--- a/dwm/util.h
+++ b/dwm/util.h
@@ -3,6 +3,7 @@
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
+#define LENGTH(X) (sizeof (X) / sizeof (X)[0])
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
diff --git a/dwm/vanitygaps.c b/dwm/vanitygaps.c
index aebbb99..09e62b6 100644
--- a/dwm/vanitygaps.c
+++ b/dwm/vanitygaps.c
@@ -13,19 +13,18 @@ static void bstack(Monitor *m);
static void bstackhoriz(Monitor *m);
static void centeredmaster(Monitor *m);
static void centeredfloatingmaster(Monitor *m);
-static void col(Monitor *);
+static void col(Monitor *m);
static void deck(Monitor *m);
static void dwindle(Monitor *m);
static void fibonacci(Monitor *m, int s);
static void grid(Monitor *m);
static void nrowgrid(Monitor *m);
static void spiral(Monitor *m);
+static void stairs(Monitor *m);
static void tile(Monitor *m);
/* Internals */
-static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv,
- unsigned int *nc);
-static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf,
- int *mr, int *sr);
+static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
+static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr);
static void setgaps(int oh, int ov, int ih, int iv);
/* Settings */
@@ -33,117 +32,162 @@ static void setgaps(int oh, int ov, int ih, int iv);
static int enablegaps = 1;
#endif // PERTAG_PATCH
-void setgaps(int oh, int ov, int ih, int iv) {
- if (oh < 0)
- oh = 0;
- if (ov < 0)
- ov = 0;
- if (ih < 0)
- ih = 0;
- if (iv < 0)
- iv = 0;
-
- selmon->gappoh = oh;
- selmon->gappov = ov;
- selmon->gappih = ih;
- selmon->gappiv = iv;
- arrange(selmon);
+void
+setgaps(int oh, int ov, int ih, int iv)
+{
+ if (oh < 0) oh = 0;
+ if (ov < 0) ov = 0;
+ if (ih < 0) ih = 0;
+ if (iv < 0) iv = 0;
+
+ selmon->gappoh = oh;
+ selmon->gappov = ov;
+ selmon->gappih = ih;
+ selmon->gappiv = iv;
+ arrange(selmon);
}
-void togglegaps(const Arg *arg) {
-#if PERTAG_PATCH
- selmon->pertag->enablegaps[selmon->pertag->curtag] =
- !selmon->pertag->enablegaps[selmon->pertag->curtag];
-#else
- enablegaps = !enablegaps;
-#endif // PERTAG_PATCH
- arrange(NULL);
+void
+togglegaps(const Arg *arg)
+{
+ #if PERTAG_PATCH
+ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag];
+ #else
+ enablegaps = !enablegaps;
+ #endif // PERTAG_PATCH
+ arrange(NULL);
}
-void defaultgaps(const Arg *arg) { setgaps(gappoh, gappov, gappih, gappiv); }
-
-void incrgaps(const Arg *arg) {
- setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i,
- selmon->gappih + arg->i, selmon->gappiv + arg->i);
+void
+defaultgaps(const Arg *arg)
+{
+ setgaps(gappoh, gappov, gappih, gappiv);
}
-void incrigaps(const Arg *arg) {
- setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i,
- selmon->gappiv + arg->i);
+void
+incrgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov + arg->i,
+ selmon->gappih + arg->i,
+ selmon->gappiv + arg->i
+ );
}
-void incrogaps(const Arg *arg) {
- setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih,
- selmon->gappiv);
+void
+incrigaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih + arg->i,
+ selmon->gappiv + arg->i
+ );
}
-void incrohgaps(const Arg *arg) {
- setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih,
- selmon->gappiv);
+void
+incrogaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov + arg->i,
+ selmon->gappih,
+ selmon->gappiv
+ );
}
-void incrovgaps(const Arg *arg) {
- setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih,
- selmon->gappiv);
+void
+incrohgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh + arg->i,
+ selmon->gappov,
+ selmon->gappih,
+ selmon->gappiv
+ );
}
-void incrihgaps(const Arg *arg) {
- setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i,
- selmon->gappiv);
+void
+incrovgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov + arg->i,
+ selmon->gappih,
+ selmon->gappiv
+ );
}
-void incrivgaps(const Arg *arg) {
- setgaps(selmon->gappoh, selmon->gappov, selmon->gappih,
- selmon->gappiv + arg->i);
+void
+incrihgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih + arg->i,
+ selmon->gappiv
+ );
}
-void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc) {
- unsigned int n, oe, ie;
-#if PERTAG_PATCH
- oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag];
-#else
- oe = ie = enablegaps;
-#endif // PERTAG_PATCH
- Client *c;
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
- ;
- if (smartgaps && n == 1) {
- oe = 0; // outer gaps disabled when only one client
- }
-
- *oh = m->gappoh * oe; // outer horizontal gap
- *ov = m->gappov * oe; // outer vertical gap
- *ih = m->gappih * ie; // inner horizontal gap
- *iv = m->gappiv * ie; // inner vertical gap
- *nc = n; // number of clients
+void
+incrivgaps(const Arg *arg)
+{
+ setgaps(
+ selmon->gappoh,
+ selmon->gappov,
+ selmon->gappih,
+ selmon->gappiv + arg->i
+ );
}
-void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr,
- int *sr) {
- unsigned int n;
- float mfacts = 0, sfacts = 0;
- int mtotal = 0, stotal = 0;
- Client *c;
+void
+getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
+{
+ unsigned int n, oe, ie;
+ #if PERTAG_PATCH
+ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag];
+ #else
+ oe = ie = enablegaps;
+ #endif // PERTAG_PATCH
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (smartgaps && n == 1) {
+ oe = 0; // outer gaps disabled when only one client
+ }
+
+ *oh = m->gappoh*oe; // outer horizontal gap
+ *ov = m->gappov*oe; // outer vertical gap
+ *ih = m->gappih*ie; // inner horizontal gap
+ *iv = m->gappiv*ie; // inner vertical gap
+ *nc = n; // number of clients
+}
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
- if (n < m->nmaster)
- mfacts += c->cfact;
- else
- sfacts += c->cfact;
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
- if (n < m->nmaster)
- mtotal += msize * (c->cfact / mfacts);
- else
- stotal += ssize * (c->cfact / sfacts);
-
- *mf = mfacts; // total factor of master area
- *sf = sfacts; // total factor of stack area
- *mr = msize -
- mtotal; // the remainder (rest) of pixels after a cfacts master split
- *sr = ssize -
- stotal; // the remainder (rest) of pixels after a cfacts stack split
+void
+getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
+{
+ unsigned int n;
+ float mfacts = 0, sfacts = 0;
+ int mtotal = 0, stotal = 0;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+ if (n < m->nmaster)
+ mfacts += c->cfact;
+ else
+ sfacts += c->cfact;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+ if (n < m->nmaster)
+ mtotal += msize * (c->cfact / mfacts);
+ else
+ stotal += ssize * (c->cfact / sfacts);
+
+ *mf = mfacts; // total factor of master area
+ *sf = sfacts; // total factor of stack area
+ *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split
+ *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split
}
/***
@@ -154,248 +198,233 @@ void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr,
* Bottomstack layout + gaps
* https://dwm.suckless.org/patches/bottomstack/
*/
-static void bstack(Monitor *m) {
- unsigned int i, n;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- float mfacts, sfacts;
- int mrest, srest;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- sh = mh = m->wh - 2 * oh;
- mw = m->ww - 2 * ov - iv * (MIN(n, m->nmaster) - 1);
- sw = m->ww - 2 * ov - iv * (n - m->nmaster - 1);
-
- if (m->nmaster && n > m->nmaster) {
- sh = (mh - ih) * (1 - m->mfact);
- mh = mh - ih - sh;
- sx = mx;
- sy = my + mh + ih;
- }
-
- getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- if (i < m->nmaster) {
- resize(c, mx, my,
- mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw),
- mh - (2 * c->bw), 0);
- mx += WIDTH(c) + iv;
- } else {
- resize(c, sx, sy,
- sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) -
- (2 * c->bw),
- sh - (2 * c->bw), 0);
- sx += WIDTH(c) + iv;
- }
- }
+static void
+bstack(Monitor *m)
+{
+ unsigned int i, n;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ float mfacts, sfacts;
+ int mrest, srest;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
+ sw = m->ww - 2*ov - iv * (n - m->nmaster - 1);
+
+ if (m->nmaster && n > m->nmaster) {
+ sh = (mh - ih) * (1 - m->mfact);
+ mh = mh - ih - sh;
+ sx = mx;
+ sy = my + mh + ih;
+ }
+
+ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ mx += WIDTH(c) + iv;
+ } else {
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ sx += WIDTH(c) + iv;
+ }
+ }
}
-static void bstackhoriz(Monitor *m) {
- unsigned int i, n;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- float mfacts, sfacts;
- int mrest, srest;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- mh = m->wh - 2 * oh;
- sh = m->wh - 2 * oh - ih * (n - m->nmaster - 1);
- mw = m->ww - 2 * ov - iv * (MIN(n, m->nmaster) - 1);
- sw = m->ww - 2 * ov;
-
- if (m->nmaster && n > m->nmaster) {
- sh = (mh - ih) * (1 - m->mfact);
- mh = mh - ih - sh;
- sy = my + mh + ih;
- sh = m->wh - mh - 2 * oh - ih * (n - m->nmaster);
- }
-
- getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- if (i < m->nmaster) {
- resize(c, mx, my,
- mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw),
- mh - (2 * c->bw), 0);
- mx += WIDTH(c) + iv;
- } else {
- resize(c, sx, sy, sw - (2 * c->bw),
- sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) -
- (2 * c->bw),
- 0);
- sy += HEIGHT(c) + ih;
- }
- }
+static void
+bstackhoriz(Monitor *m)
+{
+ unsigned int i, n;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ float mfacts, sfacts;
+ int mrest, srest;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ mh = m->wh - 2*oh;
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
+ sw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sh = (mh - ih) * (1 - m->mfact);
+ mh = mh - ih - sh;
+ sy = my + mh + ih;
+ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster);
+ }
+
+ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ mx += WIDTH(c) + iv;
+ } else {
+ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ sy += HEIGHT(c) + ih;
+ }
+ }
}
/*
* Centred master layout + gaps
* https://dwm.suckless.org/patches/centeredmaster/
*/
-void centeredmaster(Monitor *m) {
- unsigned int i, n;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int lx = 0, ly = 0, lw = 0, lh = 0;
- int rx = 0, ry = 0, rw = 0, rh = 0;
- float mfacts = 0, lfacts = 0, rfacts = 0;
- int mtotal = 0, ltotal = 0, rtotal = 0;
- int mrest = 0, lrest = 0, rrest = 0;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- /* initialize areas */
- mx = m->wx + ov;
- my = m->wy + oh;
- mh = m->wh - 2 * oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
- mw = m->ww - 2 * ov;
- lh = m->wh - 2 * oh - ih * (((n - m->nmaster) / 2) - 1);
- rh = m->wh - 2 * oh -
- ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
-
- if (m->nmaster && n > m->nmaster) {
- /* go mfact box in the center if more than nmaster clients */
- if (n - m->nmaster > 1) {
- /* ||<-S->|<---M--->|<-S->|| */
- mw = (m->ww - 2 * ov - 2 * iv) * m->mfact;
- lw = (m->ww - mw - 2 * ov - 2 * iv) / 2;
- rw = (m->ww - mw - 2 * ov - 2 * iv) - lw;
- mx += lw + iv;
- } else {
- /* ||<---M--->|<-S->|| */
- mw = (mw - iv) * m->mfact;
- lw = 0;
- rw = m->ww - mw - iv - 2 * ov;
- }
- lx = m->wx + ov;
- ly = m->wy + oh;
- rx = mx + mw + iv;
- ry = m->wy + oh;
- }
-
- /* calculate facts */
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
- if (!m->nmaster || n < m->nmaster)
- mfacts += c->cfact;
- else if ((n - m->nmaster) % 2)
- lfacts += c->cfact; // total factor of left hand stack area
- else
- rfacts += c->cfact; // total factor of right hand stack area
- }
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
- if (!m->nmaster || n < m->nmaster)
- mtotal += mh * (c->cfact / mfacts);
- else if ((n - m->nmaster) % 2)
- ltotal += lh * (c->cfact / lfacts);
- else
- rtotal += rh * (c->cfact / rfacts);
-
- mrest = mh - mtotal;
- lrest = lh - ltotal;
- rrest = rh - rtotal;
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- if (!m->nmaster || i < m->nmaster) {
- /* nmaster clients are stacked vertically, in the center of the screen */
- resize(c, mx, my, mw - (2 * c->bw),
- mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw), 0);
- my += HEIGHT(c) + ih;
- } else {
- /* stack clients are stacked vertically */
- if ((i - m->nmaster) % 2) {
- resize(c, lx, ly, lw - (2 * c->bw),
- lh * (c->cfact / lfacts) +
- ((i - 2 * m->nmaster) < 2 * lrest ? 1 : 0) - (2 * c->bw),
- 0);
- ly += HEIGHT(c) + ih;
- } else {
- resize(c, rx, ry, rw - (2 * c->bw),
- rh * (c->cfact / rfacts) +
- ((i - 2 * m->nmaster) < 2 * rrest ? 1 : 0) - (2 * c->bw),
- 0);
- ry += HEIGHT(c) + ih;
- }
- }
- }
+void
+centeredmaster(Monitor *m)
+{
+ unsigned int i, n;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int lx = 0, ly = 0, lw = 0, lh = 0;
+ int rx = 0, ry = 0, rw = 0, rh = 0;
+ float mfacts = 0, lfacts = 0, rfacts = 0;
+ int mtotal = 0, ltotal = 0, rtotal = 0;
+ int mrest = 0, lrest = 0, rrest = 0;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ /* initialize areas */
+ mx = m->wx + ov;
+ my = m->wy + oh;
+ mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
+ mw = m->ww - 2*ov;
+ lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1);
+ rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
+
+ if (m->nmaster && n > m->nmaster) {
+ /* go mfact box in the center if more than nmaster clients */
+ if (n - m->nmaster > 1) {
+ /* ||<-S->|<---M--->|<-S->|| */
+ mw = (m->ww - 2*ov - 2*iv) * m->mfact;
+ lw = (m->ww - mw - 2*ov - 2*iv) / 2;
+ rw = (m->ww - mw - 2*ov - 2*iv) - lw;
+ mx += lw + iv;
+ } else {
+ /* ||<---M--->|<-S->|| */
+ mw = (mw - iv) * m->mfact;
+ lw = 0;
+ rw = m->ww - mw - iv - 2*ov;
+ }
+ lx = m->wx + ov;
+ ly = m->wy + oh;
+ rx = mx + mw + iv;
+ ry = m->wy + oh;
+ }
+
+ /* calculate facts */
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
+ if (!m->nmaster || n < m->nmaster)
+ mfacts += c->cfact;
+ else if ((n - m->nmaster) % 2)
+ lfacts += c->cfact; // total factor of left hand stack area
+ else
+ rfacts += c->cfact; // total factor of right hand stack area
+ }
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
+ if (!m->nmaster || n < m->nmaster)
+ mtotal += mh * (c->cfact / mfacts);
+ else if ((n - m->nmaster) % 2)
+ ltotal += lh * (c->cfact / lfacts);
+ else
+ rtotal += rh * (c->cfact / rfacts);
+
+ mrest = mh - mtotal;
+ lrest = lh - ltotal;
+ rrest = rh - rtotal;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (!m->nmaster || i < m->nmaster) {
+ /* nmaster clients are stacked vertically, in the center of the screen */
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ my += HEIGHT(c) + ih;
+ } else {
+ /* stack clients are stacked vertically */
+ if ((i - m->nmaster) % 2 ) {
+ resize(c, lx, ly, lw - (2*c->bw), lh * (c->cfact / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
+ ly += HEIGHT(c) + ih;
+ } else {
+ resize(c, rx, ry, rw - (2*c->bw), rh * (c->cfact / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
+ ry += HEIGHT(c) + ih;
+ }
+ }
+ }
}
-void centeredfloatingmaster(Monitor *m) {
- unsigned int i, n;
- float mfacts, sfacts;
- float mivf = 1.0; // master inner vertical gap factor
- int oh, ov, ih, iv, mrest, srest;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- sh = mh = m->wh - 2 * oh;
- mw = m->ww - 2 * ov - iv * (n - 1);
- sw = m->ww - 2 * ov - iv * (n - m->nmaster - 1);
-
- if (m->nmaster && n > m->nmaster) {
- mivf = 0.8;
- /* go mfact box in the center if more than nmaster clients */
- if (m->ww > m->wh) {
- mw = m->ww * m->mfact - iv * mivf * (MIN(n, m->nmaster) - 1);
- mh = m->wh * 0.9;
- } else {
- mw = m->ww * 0.9 - iv * mivf * (MIN(n, m->nmaster) - 1);
- mh = m->wh * m->mfact;
- }
- mx = m->wx + (m->ww - mw) / 2;
- my = m->wy + (m->wh - mh - 2 * oh) / 2;
-
- sx = m->wx + ov;
- sy = m->wy + oh;
- sh = m->wh - 2 * oh;
- }
-
- getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- /* nmaster clients are stacked horizontally, in the center of the screen
- */
- resize(c, mx, my,
- mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw),
- mh - (2 * c->bw), 0);
- mx += WIDTH(c) + iv * mivf;
- } else {
- /* stack clients are stacked horizontally */
- resize(c, sx, sy,
- sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) -
- (2 * c->bw),
- sh - (2 * c->bw), 0);
- sx += WIDTH(c) + iv;
- }
+void
+centeredfloatingmaster(Monitor *m)
+{
+ unsigned int i, n;
+ float mfacts, sfacts;
+ float mivf = 1.0; // master inner vertical gap factor
+ int oh, ov, ih, iv, mrest, srest;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ mw = m->ww - 2*ov - iv*(n - 1);
+ sw = m->ww - 2*ov - iv*(n - m->nmaster - 1);
+
+ if (m->nmaster && n > m->nmaster) {
+ mivf = 0.8;
+ /* go mfact box in the center if more than nmaster clients */
+ if (m->ww > m->wh) {
+ mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1);
+ mh = m->wh * 0.9;
+ } else {
+ mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1);
+ mh = m->wh * m->mfact;
+ }
+ mx = m->wx + (m->ww - mw) / 2;
+ my = m->wy + (m->wh - mh - 2*oh) / 2;
+
+ sx = m->wx + ov;
+ sy = m->wy + oh;
+ sh = m->wh - 2*oh;
+ }
+
+ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ /* nmaster clients are stacked horizontally, in the center of the screen */
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ mx += WIDTH(c) + iv*mivf;
+ } else {
+ /* stack clients are stacked horizontally */
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ sx += WIDTH(c) + iv;
+ }
}
-static void col(Monitor *m) {
+void
+col(Monitor *m) {
unsigned int i, n;
int oh, ov, ih, iv, x, y, w, h;
Client *c;
@@ -419,381 +448,443 @@ static void col(Monitor *m) {
* Deck layout + gaps
* https://dwm.suckless.org/patches/deck/
*/
-void deck(Monitor *m) {
- unsigned int i, n;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- float mfacts, sfacts;
- int mrest, srest;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- sh = mh = m->wh - 2 * oh - ih * (MIN(n, m->nmaster) - 1);
- sw = mw = m->ww - 2 * ov;
-
- if (m->nmaster && n > m->nmaster) {
- sw = (mw - iv) * (1 - m->mfact);
- mw = mw - iv - sw;
- sx = mx + mw + iv;
- sh = m->wh - 2 * oh;
- }
-
- getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
-
- if (n - m->nmaster > 0) /* override layout symbol */
- snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- resize(c, mx, my, mw - (2 * c->bw),
- mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw), 0);
- my += HEIGHT(c) + ih;
- } else {
- resize(c, sx, sy, sw - (2 * c->bw), sh - (2 * c->bw), 0);
- }
+void
+deck(Monitor *m)
+{
+ unsigned int i, n;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ float mfacts, sfacts;
+ int mrest, srest;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
+ sw = mw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sw = (mw - iv) * (1 - m->mfact);
+ mw = mw - iv - sw;
+ sx = mx + mw + iv;
+ sh = m->wh - 2*oh;
+ }
+
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
+
+ if (n - m->nmaster > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ my += HEIGHT(c) + ih;
+ } else {
+ resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
+ }
}
/*
* Fibonacci layout + gaps
* https://dwm.suckless.org/patches/fibonacci/
*/
-void fibonacci(Monitor *m, int s) {
- unsigned int i, n;
- int nx, ny, nw, nh;
- int oh, ov, ih, iv;
- int nv, hrest = 0, wrest = 0, r = 1;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- nx = m->wx + ov;
- ny = m->wy + oh;
- nw = m->ww - 2 * ov;
- nh = m->wh - 2 * oh;
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
- if (r) {
- if ((i % 2 && (nh - ih) / 2 <= (bh + 2 * c->bw)) ||
- (!(i % 2) && (nw - iv) / 2 <= (bh + 2 * c->bw))) {
- r = 0;
- }
- if (r && i < n - 1) {
- if (i % 2) {
- nv = (nh - ih) / 2;
- hrest = nh - 2 * nv - ih;
- nh = nv;
- } else {
- nv = (nw - iv) / 2;
- wrest = nw - 2 * nv - iv;
- nw = nv;
- }
-
- if ((i % 4) == 2 && !s)
- nx += nw + iv;
- else if ((i % 4) == 3 && !s)
- ny += nh + ih;
- }
-
- if ((i % 4) == 0) {
- if (s) {
- ny += nh + ih;
- nh += hrest;
- } else {
- nh -= hrest;
- ny -= nh + ih;
- }
- } else if ((i % 4) == 1) {
- nx += nw + iv;
- nw += wrest;
- } else if ((i % 4) == 2) {
- ny += nh + ih;
- nh += hrest;
- if (i < n - 1)
- nw += wrest;
- } else if ((i % 4) == 3) {
- if (s) {
- nx += nw + iv;
- nw -= wrest;
- } else {
- nw -= wrest;
- nx -= nw + iv;
- nh += hrest;
- }
- }
- if (i == 0) {
- if (n != 1) {
- nw = (m->ww - iv - 2 * ov) - (m->ww - iv - 2 * ov) * (1 - m->mfact);
- wrest = 0;
- }
- ny = m->wy + oh;
- } else if (i == 1)
- nw = m->ww - nw - iv - 2 * ov;
- i++;
- }
-
- resize(c, nx, ny, nw - (2 * c->bw), nh - (2 * c->bw), False);
- }
+void
+fibonacci(Monitor *m, int s)
+{
+ unsigned int i, n;
+ int nx, ny, nw, nh;
+ int oh, ov, ih, iv;
+ int nv, hrest = 0, wrest = 0, r = 1;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ nx = m->wx + ov;
+ ny = m->wy + oh;
+ nw = m->ww - 2*ov;
+ nh = m->wh - 2*oh;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
+ if (r) {
+ if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw))
+ || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) {
+ r = 0;
+ }
+ if (r && i < n - 1) {
+ if (i % 2) {
+ nv = (nh - ih) / 2;
+ hrest = nh - 2*nv - ih;
+ nh = nv;
+ } else {
+ nv = (nw - iv) / 2;
+ wrest = nw - 2*nv - iv;
+ nw = nv;
+ }
+
+ if ((i % 4) == 2 && !s)
+ nx += nw + iv;
+ else if ((i % 4) == 3 && !s)
+ ny += nh + ih;
+ }
+
+ if ((i % 4) == 0) {
+ if (s) {
+ ny += nh + ih;
+ nh += hrest;
+ }
+ else {
+ nh -= hrest;
+ ny -= nh + ih;
+ }
+ }
+ else if ((i % 4) == 1) {
+ nx += nw + iv;
+ nw += wrest;
+ }
+ else if ((i % 4) == 2) {
+ ny += nh + ih;
+ nh += hrest;
+ if (i < n - 1)
+ nw += wrest;
+ }
+ else if ((i % 4) == 3) {
+ if (s) {
+ nx += nw + iv;
+ nw -= wrest;
+ } else {
+ nw -= wrest;
+ nx -= nw + iv;
+ nh += hrest;
+ }
+ }
+ if (i == 0) {
+ if (n != 1) {
+ nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact);
+ wrest = 0;
+ }
+ ny = m->wy + oh;
+ }
+ else if (i == 1)
+ nw = m->ww - nw - iv - 2*ov;
+ i++;
+ }
+
+ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
+ }
}
-void dwindle(Monitor *m) { fibonacci(m, 1); }
+void
+dwindle(Monitor *m)
+{
+ fibonacci(m, 1);
+}
-void spiral(Monitor *m) { fibonacci(m, 0); }
+void
+spiral(Monitor *m)
+{
+ fibonacci(m, 0);
+}
/*
* Gappless grid layout + gaps (ironically)
* https://dwm.suckless.org/patches/gaplessgrid/
*/
-void gaplessgrid(Monitor *m) {
- unsigned int i, n;
- int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
- int oh, ov, ih, iv;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- /* grid dimensions */
- for (cols = 0; cols <= n / 2; cols++)
- if (cols * cols >= n)
- break;
- if (n ==
- 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
- cols = 2;
- rows = n / cols;
- cn = rn = 0; // reset column no, row no, client count
-
- ch = (m->wh - 2 * oh - ih * (rows - 1)) / rows;
- cw = (m->ww - 2 * ov - iv * (cols - 1)) / cols;
- rrest = (m->wh - 2 * oh - ih * (rows - 1)) - ch * rows;
- crest = (m->ww - 2 * ov - iv * (cols - 1)) - cw * cols;
- x = m->wx + ov;
- y = m->wy + oh;
-
- for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
- if (i / rows + 1 > cols - n % cols) {
- rows = n / cols + 1;
- ch = (m->wh - 2 * oh - ih * (rows - 1)) / rows;
- rrest = (m->wh - 2 * oh - ih * (rows - 1)) - ch * rows;
- }
- resize(c, x, y + rn * (ch + ih) + MIN(rn, rrest),
- cw + (cn < crest ? 1 : 0) - 2 * c->bw,
- ch + (rn < rrest ? 1 : 0) - 2 * c->bw, 0);
- rn++;
- if (rn >= rows) {
- rn = 0;
- x += cw + ih + (cn < crest ? 1 : 0);
- cn++;
- }
- }
+void
+gaplessgrid(Monitor *m)
+{
+ unsigned int i, n;
+ int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
+ int oh, ov, ih, iv;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ /* grid dimensions */
+ for (cols = 0; cols <= n/2; cols++)
+ if (cols*cols >= n)
+ break;
+ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
+ cols = 2;
+ rows = n/cols;
+ cn = rn = 0; // reset column no, row no, client count
+
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / cols;
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
+ x = m->wx + ov;
+ y = m->wy + oh;
+
+ for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
+ if (i/rows + 1 > cols - n%cols) {
+ rows = n/cols + 1;
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ }
+ resize(c,
+ x,
+ y + rn*(ch + ih) + MIN(rn, rrest),
+ cw + (cn < crest ? 1 : 0) - 2*c->bw,
+ ch + (rn < rrest ? 1 : 0) - 2*c->bw,
+ 0);
+ rn++;
+ if (rn >= rows) {
+ rn = 0;
+ x += cw + ih + (cn < crest ? 1 : 0);
+ cn++;
+ }
+ }
}
/*
* Gridmode layout + gaps
* https://dwm.suckless.org/patches/gridmode/
*/
-void grid(Monitor *m) {
- unsigned int i, n;
- int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
- int oh, ov, ih, iv;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
-
- /* grid dimensions */
- for (rows = 0; rows <= n / 2; rows++)
- if (rows * rows >= n)
- break;
- cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
-
- /* window geoms (cell height/width) */
- ch = (m->wh - 2 * oh - ih * (rows - 1)) / (rows ? rows : 1);
- cw = (m->ww - 2 * ov - iv * (cols - 1)) / (cols ? cols : 1);
- chrest = (m->wh - 2 * oh - ih * (rows - 1)) - ch * rows;
- cwrest = (m->ww - 2 * ov - iv * (cols - 1)) - cw * cols;
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- cc = i / rows;
- cr = i % rows;
- cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest);
- cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest);
- resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2 * c->bw,
- ch + (cr < chrest ? 1 : 0) - 2 * c->bw, False);
- }
+void
+grid(Monitor *m)
+{
+ unsigned int i, n;
+ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
+ int oh, ov, ih, iv;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+
+ /* grid dimensions */
+ for (rows = 0; rows <= n/2; rows++)
+ if (rows*rows >= n)
+ break;
+ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
+
+ /* window geoms (cell height/width) */
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1);
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1);
+ chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
+ cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ cc = i / rows;
+ cr = i % rows;
+ cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest);
+ cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest);
+ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
+ }
}
/*
* Horizontal grid layout + gaps
* https://dwm.suckless.org/patches/horizgrid/
*/
-void horizgrid(Monitor *m) {
- Client *c;
- unsigned int n, i;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- int ntop, nbottom = 1;
- float mfacts = 0, sfacts = 0;
- int mrest, srest, mtotal = 0, stotal = 0;
-
- /* Count windows */
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- if (n <= 2)
- ntop = n;
- else {
- ntop = n / 2;
- nbottom = n - ntop;
- }
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- sh = mh = m->wh - 2 * oh;
- sw = mw = m->ww - 2 * ov;
-
- if (n > ntop) {
- sh = (mh - ih) / 2;
- mh = mh - ih - sh;
- sy = my + mh + ih;
- mw = m->ww - 2 * ov - iv * (ntop - 1);
- sw = m->ww - 2 * ov - iv * (nbottom - 1);
- }
-
- /* calculate facts */
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < ntop)
- mfacts += c->cfact;
- else
- sfacts += c->cfact;
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < ntop)
- mtotal += mh * (c->cfact / mfacts);
- else
- stotal += sw * (c->cfact / sfacts);
-
- mrest = mh - mtotal;
- srest = sw - stotal;
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < ntop) {
- resize(c, mx, my,
- mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw),
- mh - (2 * c->bw), 0);
- mx += WIDTH(c) + iv;
- } else {
- resize(c, sx, sy,
- sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) -
- (2 * c->bw),
- sh - (2 * c->bw), 0);
- sx += WIDTH(c) + iv;
- }
+void
+horizgrid(Monitor *m) {
+ Client *c;
+ unsigned int n, i;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ int ntop, nbottom = 1;
+ float mfacts = 0, sfacts = 0;
+ int mrest, srest, mtotal = 0, stotal = 0;
+
+ /* Count windows */
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ if (n <= 2)
+ ntop = n;
+ else {
+ ntop = n / 2;
+ nbottom = n - ntop;
+ }
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ sh = mh = m->wh - 2*oh;
+ sw = mw = m->ww - 2*ov;
+
+ if (n > ntop) {
+ sh = (mh - ih) / 2;
+ mh = mh - ih - sh;
+ sy = my + mh + ih;
+ mw = m->ww - 2*ov - iv * (ntop - 1);
+ sw = m->ww - 2*ov - iv * (nbottom - 1);
+ }
+
+ /* calculate facts */
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop)
+ mfacts += c->cfact;
+ else
+ sfacts += c->cfact;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop)
+ mtotal += mh * (c->cfact / mfacts);
+ else
+ stotal += sw * (c->cfact / sfacts);
+
+ mrest = mh - mtotal;
+ srest = sw - stotal;
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < ntop) {
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
+ mx += WIDTH(c) + iv;
+ } else {
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
+ sx += WIDTH(c) + iv;
+ }
}
/*
* nrowgrid layout + gaps
* https://dwm.suckless.org/patches/nrowgrid/
*/
-void nrowgrid(Monitor *m) {
- unsigned int n;
- int ri = 0, ci = 0; /* counters */
- int oh, ov, ih, iv; /* vanitygap settings */
- unsigned int cx, cy, cw, ch; /* client geometry */
- unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
- unsigned int cols, rows = m->nmaster + 1;
- Client *c;
-
- /* count clients */
- getgaps(m, &oh, &ov, &ih, &iv, &n);
-
- /* nothing to do here */
- if (n == 0)
- return;
-
- /* force 2 clients to always split vertically */
- if (FORCE_VSPLIT && n == 2)
- rows = 1;
-
- /* never allow empty rows */
- if (n < rows)
- rows = n;
-
- /* define first row */
- cols = n / rows;
- uc = cols;
- cy = m->wy + oh;
- ch = (m->wh - 2 * oh - ih * (rows - 1)) / rows;
- uh = ch;
-
- for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) {
- if (ci == cols) {
- uw = 0;
- ci = 0;
- ri++;
-
- /* next row */
- cols = (n - uc) / (rows - ri);
- uc += cols;
- cy = m->wy + oh + uh + ih;
- uh += ch + ih;
- }
-
- cx = m->wx + ov + uw;
- cw = (m->ww - 2 * ov - uw) / (cols - ci);
- uw += cw + iv;
-
- resize(c, cx, cy, cw - (2 * c->bw), ch - (2 * c->bw), 0);
- }
+void
+nrowgrid(Monitor *m)
+{
+ unsigned int n;
+ int ri = 0, ci = 0; /* counters */
+ int oh, ov, ih, iv; /* vanitygap settings */
+ unsigned int cx, cy, cw, ch; /* client geometry */
+ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
+ unsigned int cols, rows = m->nmaster + 1;
+ Client *c;
+
+ /* count clients */
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+
+ /* nothing to do here */
+ if (n == 0)
+ return;
+
+ /* force 2 clients to always split vertically */
+ if (FORCE_VSPLIT && n == 2)
+ rows = 1;
+
+ /* never allow empty rows */
+ if (n < rows)
+ rows = n;
+
+ /* define first row */
+ cols = n / rows;
+ uc = cols;
+ cy = m->wy + oh;
+ ch = (m->wh - 2*oh - ih*(rows - 1)) / rows;
+ uh = ch;
+
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) {
+ if (ci == cols) {
+ uw = 0;
+ ci = 0;
+ ri++;
+
+ /* next row */
+ cols = (n - uc) / (rows - ri);
+ uc += cols;
+ cy = m->wy + oh + uh + ih;
+ uh += ch + ih;
+ }
+
+ cx = m->wx + ov + uw;
+ cw = (m->ww - 2*ov - uw) / (cols - ci);
+ uw += cw + iv;
+
+ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0);
+ }
}
/*
* Default tile layout + gaps
*/
-static void tile(Monitor *m) {
- unsigned int i, n;
- int oh, ov, ih, iv;
- int mx = 0, my = 0, mh = 0, mw = 0;
- int sx = 0, sy = 0, sh = 0, sw = 0;
- float mfacts, sfacts;
- int mrest, srest;
- Client *c;
-
- getgaps(m, &oh, &ov, &ih, &iv, &n);
- if (n == 0)
- return;
-
- sx = mx = m->wx + ov;
- sy = my = m->wy + oh;
- mh = m->wh - 2 * oh - ih * (MIN(n, m->nmaster) - 1);
- sh = m->wh - 2 * oh - ih * (n - m->nmaster - 1);
- sw = mw = m->ww - 2 * ov;
-
- if (m->nmaster && n > m->nmaster) {
- sw = (mw - iv) * (1 - m->mfact);
- mw = mw - iv - sw;
- sx = mx + mw + iv;
- }
+static void
+tile(Monitor *m)
+{
+ unsigned int i, n;
+ int oh, ov, ih, iv;
+ int mx = 0, my = 0, mh = 0, mw = 0;
+ int sx = 0, sy = 0, sh = 0, sw = 0;
+ float mfacts, sfacts;
+ int mrest, srest;
+ Client *c;
+
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
+ if (n == 0)
+ return;
+
+ sx = mx = m->wx + ov;
+ sy = my = m->wy + oh;
+ mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
+ sw = mw = m->ww - 2*ov;
+
+ if (m->nmaster && n > m->nmaster) {
+ sw = (mw - iv) * (1 - m->mfact);
+ mw = mw - iv - sw;
+ sx = mx + mw + iv;
+ }
+
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
+
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
+ my += HEIGHT(c) + ih;
+ } else {
+ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
+ sy += HEIGHT(c) + ih;
+ }
+}
- getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
-
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- resize(c, mx, my, mw - (2 * c->bw),
- mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2 * c->bw), 0);
- my += HEIGHT(c) + ih;
- } else {
- resize(c, sx, sy, sw - (2 * c->bw),
- sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) -
- (2 * c->bw),
- 0);
- sy += HEIGHT(c) + ih;
- }
+void
+stairs(Monitor *m)
+{
+ unsigned int i, n, h, mw, my;
+ unsigned int ox, oy, ow, oh; /* stair offset values */
+ Client *c;
+ int gappoh, gappov, gappih, gappiv; // Corrected to int, as these can be negative
+ unsigned int nc; // Keep nc as unsigned int
+
+ // Get the current gaps
+ getgaps(m, &gappoh, &gappov, &gappih, &gappiv, &nc);
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ // Determine the master width (mw) based on the number of clients
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww - gappoh; // Outer gap for horizontal alignment
+
+ // Now layout the clients, factoring in gaps
+ for (i = 0, my = gappov, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gappiv; // Use inner vertical gap for spacing
+ resize(c, m->wx + gappoh, m->wy + my, mw - (2 * c->bw) - gappoh, h - (2 * c->bw), 0);
+ if (my + HEIGHT(c) + gappiv < m->wh)
+ my += HEIGHT(c) + gappiv; // Update my using inner vertical gap
+ } else {
+ oy = i - m->nmaster;
+ ox = stairdirection ? n - i - 1 : (stairsamesize ? i - m->nmaster : 0);
+ ow = stairsamesize ? n - m->nmaster - 1 : n - i - 1;
+ oh = stairsamesize ? ow : i - m->nmaster;
+ resize(c,
+ m->wx + mw + (ox * stairpx) + gappoh,
+ m->wy + (oy * stairpx) + gappov,
+ m->ww - mw - (2 * c->bw) - (ow * stairpx) - (2 * gappoh),
+ m->wh - (2 * c->bw) - (oh * stairpx) - (2 * gappov),
+ 0);
+ }
+ }
}
+
diff --git a/dwmblocks/.clang-format b/dwmblocks/.clang-format
new file mode 100644
index 0000000..299675f
--- /dev/null
+++ b/dwmblocks/.clang-format
@@ -0,0 +1,8 @@
+BasedOnStyle: Google
+IndentWidth: 4
+InsertBraces: true
+ColumnLimit: 79
+AlignConsecutiveMacros: Consecutive
+AllowShortFunctionsOnASingleLine: None
+AllowShortLoopsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: Never
diff --git a/dwmblocks/.clang-tidy b/dwmblocks/.clang-tidy
new file mode 100644
index 0000000..17ce268
--- /dev/null
+++ b/dwmblocks/.clang-tidy
@@ -0,0 +1,30 @@
+Checks: |
+ -*,
+ abseil-*,
+ bugprone-*,
+ clang-analyzer-*,
+ misc-*,
+ modernize-*,
+ performance-*,
+ portability-*,
+ readability-*,
+ llvm-*,
+ -bugprone-easily-swappable-parameters,
+ -readability-avoid-const-params-in-decls,
+ -readability-identifier-length
+
+CheckOptions:
+ - key: readability-inconsistent-declaration-parameter-name.Strict
+ value: true
+ - key: readability-identifier-naming.StructCase
+ value: lower_case
+ - key: readability-identifier-naming.FunctionCase
+ value: lower_case
+ - key: readability-identifier-naming.VariableCase
+ value: lower_case
+ - key: readability-identifier-naming.EnumConstantCase
+ value: UPPER_CASE
+ - key: readability-identifier-naming.MacroDefinitionCase
+ value: UPPER_CASE
+ - key: readability-function-cognitive-complexity.Threshold
+ value: 15
diff --git a/dwmblocks/.clangd b/dwmblocks/.clangd
new file mode 100644
index 0000000..d5ba524
--- /dev/null
+++ b/dwmblocks/.clangd
@@ -0,0 +1,5 @@
+Diagnostics:
+ UnusedIncludes: Strict
+ MissingIncludes: Strict
+ Includes:
+ IgnoreHeader: bits/getopt_core.h
diff --git a/dwmblocks/.github/FUNDING.yml b/dwmblocks/.github/FUNDING.yml
new file mode 100644
index 0000000..c7fd590
--- /dev/null
+++ b/dwmblocks/.github/FUNDING.yml
@@ -0,0 +1,4 @@
+patreon: UtkarshVerma
+ko_fi: UtkarshVerma
+liberapay: UtkarshVerma
+custom: https://paypal.me/UtkarshVermaI
diff --git a/dwmblocks/.gitignore b/dwmblocks/.gitignore
new file mode 100644
index 0000000..902f3c7
--- /dev/null
+++ b/dwmblocks/.gitignore
@@ -0,0 +1,3 @@
+build/
+.cache/
+compile_commands.json
diff --git a/dwmblocks/Makefile b/dwmblocks/Makefile
index 159a71a..3e07f93 100644
--- a/dwmblocks/Makefile
+++ b/dwmblocks/Makefile
@@ -1,36 +1,60 @@
-PREFIX := /usr/local
-CC := cc
-CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os
-LDFLAGS := -lX11
+.POSIX:
-# FreeBSD (uncomment)
-#LDFLAGS += -L/usr/local/lib -I/usr/local/include
-# # OpenBSD (uncomment)
-#LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include
+BIN := dwmblocks
+BUILD_DIR := build
+SRC_DIR := src
+INC_DIR := include
-all: options dwmblocks
+DEBUG := 0
+VERBOSE := 0
+LIBS := xcb-atom
-options:
- @echo dwmblocks build options:
- @echo "CFLAGS = ${CFLAGS}"
- @echo "LDFLAGS = ${LDFLAGS}"
- @echo "CC = ${CC}"
+PREFIX := /usr/local
+CFLAGS := -Ofast -I. -I$(INC_DIR) -std=c99
+CFLAGS += -DBINARY=\"$(BIN)\" -D_POSIX_C_SOURCE=200809L
+CFLAGS += -Wall -Wpedantic -Wextra -Wswitch-enum
+CFLAGS += $(shell pkg-config --cflags $(LIBS))
+LDLIBS := $(shell pkg-config --libs $(LIBS))
-dwmblocks: dwmblocks.c config.def.h config.h
- ${CC} -o dwmblocks dwmblocks.c ${CFLAGS} ${LDFLAGS}
+SRCS := $(wildcard $(SRC_DIR)/*.c)
+OBJS := $(subst $(SRC_DIR)/,$(BUILD_DIR)/,$(SRCS:.c=.o))
+
+INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin
+
+# Prettify output
+PRINTF := @printf "%-8s %s\n"
+ifeq ($(VERBOSE), 0)
+ Q := @
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -g
+endif
+
+all: $(BUILD_DIR)/$(BIN)
+
+$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.def.h config.h
+ $Qmkdir -p $(@D)
+ $(PRINTF) "CC" $@
+ $Q$(COMPILE.c) -o $@ $<
+
+$(BUILD_DIR)/$(BIN): $(OBJS)
+ $(PRINTF) "LD" $@
+ $Q$(LINK.o) $^ $(LDLIBS) -o $@
config.h:
cp config.def.h $@
clean:
- rm -f *.o *.gch dwmblocks
+ $(PRINTF) "CLEAN" $(BUILD_DIR)
+ $Q$(RM) $(BUILD_DIR)/*
-install: dwmblocks
- mkdir -p ${DESTDIR}${PREFIX}/bin
- cp -f dwmblocks ${DESTDIR}${PREFIX}/bin
- chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks
+install: $(BUILD_DIR)/$(BIN)
+ $(PRINTF) "INSTALL" $(INSTALL_DIR)/$(BIN)
+ $Qinstall -D -m 755 $< $(INSTALL_DIR)/$(BIN)
uninstall:
- rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks
+ $(PRINTF) "RM" $(INSTALL_DIR)/$(BIN)
+ $Q$(RM) $(INSTALL_DIR)/$(BIN)
-.PHONY: all options clean install uninstall
+.PHONY: all clean install uninstall
diff --git a/dwmblocks/README.md b/dwmblocks/README.md
index 7d21e30..1b389f6 100644
--- a/dwmblocks/README.md
+++ b/dwmblocks/README.md
@@ -1,44 +1,164 @@
-# dwmblocks
+# dwmblocks-async
-Modular status bar for dwm written in c.
+A [`dwm`](https://dwm.suckless.org) status bar that has a modular, async
+design, so it is always responsive. Imagine `i3blocks`, but for `dwm`.
-# Modifying blocks
+![A lean config of dwmblocks-async.](preview.png)
-The statusbar is made from text output from commandline programs. Blocks are
-added and removed by editing the config.h file.
+## Features
-# Luke's build
+- [Modular](#modifying-the-blocks)
+- Lightweight
+- [Suckless](https://suckless.org/philosophy)
+- Blocks:
+ - [Clickable](#clickable-blocks)
+ - Loaded asynchronously
+ - [Updates can be externally triggered](#signalling-changes)
+- Compatible with `i3blocks` scripts
-I have dwmblocks read my preexisting scripts
-[here in my dotfiles repo](https://github.com/LukeSmithxyz/voidrice/tree/master/.local/bin/statusbar).
-So if you want my build out of the box, download those and put them in your
-`$PATH`. I do this to avoid redundancy in LARBS, both i3 and dwm use the same
-statusbar scripts.
+> Additionally, this build of `dwmblocks` is more optimized and fixes the
+> flickering of the status bar when scrolling.
-# Signaling changes
+## Why `dwmblocks`?
-Most statusbars constantly rerun every script every several seconds to update.
-This is an option here, but a superior choice is giving your module a signal
-that you can signal to it to update on a relevant event, rather than having it
-rerun idly.
+In `dwm`, you have to set the status bar through an infinite loop, like so:
-For example, the audio module has the update signal 10 by default. Thus,
-running `pkill -RTMIN+10 dwmblocks` will update it.
+```sh
+while :; do
+ xsetroot -name "$(date)"
+ sleep 30
+done
+```
-You can also run `kill -44 $(pidof dwmblocks)` which will have the same effect,
-but is faster. Just add 34 to your typical signal number.
+This is inefficient when running multiple commands that need to be updated at
+different frequencies. For example, to display an unread mail count and a clock
+in the status bar:
-My volume module *never* updates on its own, instead I have this command run
-along side my volume shortcuts in dwm to only update it when relevant.
+```sh
+while :; do
+ xsetroot -name "$(mailCount) $(date)"
+ sleep 60
+done
+```
-Note that all modules must have different signal numbers.
+Both are executed at the same rate, which is wasteful. Ideally, the mail
+counter would be updated every thirty minutes, since there's a limit to the
+number of requests I can make using Gmail's APIs (as a free user).
-# Clickable modules
+`dwmblocks` allows you to divide the status bar into multiple blocks, each of
+which can be updated at its own interval. This effectively addresses the
+previous issue, because the commands in a block are only executed once within
+that time frame.
-Like i3blocks, this build allows you to build in additional actions into your
-scripts in response to click events. See the above linked scripts for examples
-of this using the `$BLOCK_BUTTON` variable.
+## Why `dwmblocks-async`?
-For this feature to work, you need the appropriate patch in dwm as well. See
-[here](https://dwm.suckless.org/patches/statuscmd/).
-Credit for those patches goes to Daniel Bylinka (daniel.bylinka@gmail.com).
+The magic of `dwmblocks-async` is in the `async` part. Since vanilla
+`dwmblocks` executes the commands of each block sequentially, it leads to
+annoying freezes. In cases where one block takes several seconds to execute,
+like in the mail and date blocks example from above, the delay is clearly
+visible. Fire up a new instance of `dwmblocks` and you'll see!
+
+With `dwmblocks-async`, the computer executes each block asynchronously
+(simultaneously).
+
+## Installation
+
+Clone this repository, modify `config.h` appropriately, then compile the
+program:
+
+```sh
+git clone https://github.com/UtkarshVerma/dwmblocks-async.git
+cd dwmblocks-async
+vi config.h
+sudo make install
+```
+
+## Usage
+
+To set `dwmblocks-async` as your status bar, you need to run it as a background
+process on startup. One way is to add the following to `~/.xinitrc`:
+
+```sh
+# The binary of `dwmblocks-async` is named `dwmblocks`
+dwmblocks &
+```
+
+### Modifying the blocks
+
+You can define your status bar blocks in `config.h`:
+
+```c
+#define BLOCKS(X) \
+ ...
+ X(" ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -d' ' -f2", 0, 5) \
+ X("󰥔 ", "date '+%H:%M:%S'", 1, 1) \
+ ...
+```
+
+Each block has the following properties:
+
+| Property | Description |
+| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Icon | An icon you wish to prepend to your block output. |
+| Command | The command you wish to execute in your block. |
+| Update interval | Time in seconds, after which you want the block to update. If `0`, the block will never be updated. |
+| Update signal | Signal to be used for triggering the block. Must be a positive integer. If `0`, a signal won't be set up for the block and it will be unclickable. |
+
+Apart from defining the blocks, features can be toggled through `config.h`:
+
+```c
+// String used to delimit block outputs in the status.
+#define DELIMITER " "
+
+// Maximum number of Unicode characters that a block can output.
+#define MAX_BLOCK_OUTPUT_LENGTH 45
+
+// Control whether blocks are clickable.
+#define CLICKABLE_BLOCKS 1
+
+// Control whether a leading delimiter should be prepended to the status.
+#define LEADING_DELIMITER 0
+
+// Control whether a trailing delimiter should be appended to the status.
+#define TRAILING_DELIMITER 0
+```
+
+### Signalling changes
+
+Most status bars constantly rerun all scripts every few seconds. This is an
+option here, but a superior choice is to give your block a signal through which
+you can indicate it to update on relevant event, rather than have it rerun
+idly.
+
+For example, the volume block has the update signal `5` by default. I run
+`kill -39 $(pidof dwmblocks)` alongside my volume shortcuts in `dwm` to only
+update it when relevant. Just add `34` to your signal number! You could also
+run `pkill -RTMIN+5 dwmblocks`, but it's slower.
+
+To refresh all the blocks, run `kill -10 $(pidof dwmblocks)` or
+`pkill -SIGUSR1 dwmblocks`.
+
+> All blocks must have different signal numbers!
+
+### Clickable blocks
+
+Like `i3blocks`, this build allows you to build in additional actions into your
+scripts in response to click events. You can check out
+[my status bar scripts](https://github.com/UtkarshVerma/dotfiles/tree/main/.local/bin/statusbar)
+as references for using the `$BLOCK_BUTTON` variable.
+
+To use this feature, define the `CLICKABLE_BLOCKS` feature macro in your
+`config.h`:
+
+```c
+#define CLICKABLE_BLOCKS 1
+```
+
+Apart from that, you need `dwm` to be patched with
+[statuscmd](https://dwm.suckless.org/patches/statuscmd/).
+
+## Credits
+
+This work would not have been possible without
+[Luke's build of dwmblocks](https://github.com/LukeSmithxyz/dwmblocks) and
+[Daniel Bylinka's statuscmd patch](https://dwm.suckless.org/patches/statuscmd/).
diff --git a/dwmblocks/config.def.h b/dwmblocks/config.def.h
index 7054f95..5cb2015 100644
--- a/dwmblocks/config.def.h
+++ b/dwmblocks/config.def.h
@@ -1,49 +1,53 @@
-// Modify this file to change what commands output to your statusbar, and recompile using the make command.
-static const Block blocks[] = {
- /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal (1-31)*/
- {"", "sb-music", 0, 23}, // Music (far left)
- {"", "cat /tmp/recordingicon 2>/dev/null", 0, 24}, // Recording
- {"", "sb-torrent", 20, 22}, // Torrent
- {"", "sb-queues", 10, 21}, // Queues
- {"", "sb-mailbox", 300, 20}, // Mailbox
- {"", "sb-news", 0, 19}, // News
- {"", "sb-repos", 60, 18}, // Git repositories
- {"", "sb-tasks", 60, 17}, // Tasks
- {"", "sb-packages", 0, 16}, // Packages
- {"", "sb-forecast", 10800, 15}, // Weather
- /* {"", "sb-price xmr-btc \"Monero to Bitcoin\" 🔒 30", 9000, 31}, */
- /* {"", "sb-price xmr Monero 🔒 29", 9000, 30}, */
- /* {"", "sb-price bnb Binance 🫧 28", 9000, 29}, */
- /* {"", "sb-price xrp XRP 🪓 27", 9000, 28}, */
- /* {"", "sb-price usdt Tether ⛺ 26", 9000, 27}, */
- /* {"", "sb-price eth Ethereum 🍸 25", 9000, 26}, */
- /* {"", "sb-price btc Bitcoin 💰 24", 9000, 25}, */
- /* {"", "sb-nettraf", 1, 14}, // Network */
- {"", "sb-cpu", 60, 13}, // CPU
- {"", "sb-memory", 60, 12}, // Memory
- {"", "sb-disk", 10800, 11}, // Disk
- {"", "sb-keyboard", 0, 10}, // Inputs
- {"", "sb-bghitness", 0, 9}, // Background Lightness
- {"", "sb-brightness", 0, 8}, // Brightness
- {"", "sb-internet", 5, 7}, // Internet
- /* {"", "sb-iplocate", 0, 6}, // ip */
- {"", "sb-volume", 0, 5}, // Volume
- {"", "sb-battery", 5, 4}, // Battery
- {"", "sb-clock", 60, 3}, // Clock
- {"", "sb-ecrypt", 0, 2}, // Ecrypt (rightmost)
- {"", "sb-help-icon", 0, 1}, // Help Icon (rightmost)
-};
-
-// Sets delimiter between status commands. NULL character ('\0') means no delimiter.
-static char *delim = " ";
-
-// Have dwmblocks automatically recompile and run when you edit this file in
-// vim with the following line in your vimrc/init.vim:
-
-// autocmd BufWritePost ~/.local/src/suckless/dwmblocks/config.def.h !cd ~/.local/src/suckless/dwmblocks/; sudo make install && { killall -q dwmblocks;setsid -f dwmblocks }
-
-// Although, pkill is slightly slower than the command kill, which can
-// make a big difference if we are making semi-frequent changes in a script.
-// To signal with kill, we must send the value plus 34. Just remember 34.
-// So, 10 + 34 = 44, so we use this command: kill -44 $(pidof dwmblocks)
+#ifndef CONFIG_H
+#define CONFIG_H
+
+// String used to delimit block outputs in the status.
+#define DELIMITER " "
+
+// Maximum number of Unicode characters that a block can output.
+#define MAX_BLOCK_OUTPUT_LENGTH 50
+
+// Control whether blocks are clickable.
+#define CLICKABLE_BLOCKS 1
+
+// Control whether a leading delimiter should be prepended to the status.
+#define LEADING_DELIMITER 0
+
+// Control whether a trailing delimiter should be appended to the status.
+#define TRAILING_DELIMITER 0
+
+// Define blocks for the status feed as X(icon, cmd, interval, signal).
+#define BLOCKS(X)\
+ X("", "sb-music", 0, 23) \
+ X("", "sb-torrent", 0, 22) \
+ X("", "sb-queues", 10, 21) \
+ X("", "sb-mailbox", 300, 20) \
+ X("", "sb-news", 0, 19) \
+ X("", "sb-repos", 60, 18) \
+ X("", "sb-tasks", 60, 17) \
+ X("", "sb-packages", 0, 16) \
+ X("", "sb-forecast", 10800, 15) \
+ X("", "sb-cpu", 60, 13) \
+ X("", "sb-memory", 60, 12) \
+ X("", "sb-disk", 10800, 11) \
+ X("", "sb-keyboard", 0, 10) \
+ X("", "sb-bghitness", 0, 9) \
+ X("", "sb-brightness", 0, 8) \
+ X("", "sb-internet", 5, 7) \
+ X("", "sb-volume", 0, 5) \
+ X("", "sb-battery", 5, 4) \
+ X("", "sb-clock", 60, 3) \
+ X("", "sb-ecrypt", 0, 2) \
+ X("", "sb-help-icon", 0, 1)
+
+ /* X("", "sb-price xmr-btc \"Monero to Bitcoin\" 🔒 30", 9000, 31) \ */
+ /* X("", "sb-price xmr Monero 🔒 29", 9000, 30) \ */
+ /* X("", "sb-price bnb Binance 🫧 28", 9000, 29) \ */
+ /* X("", "sb-price xrp XRP 🪓 27", 9000, 28) \ */
+ /* X("", "sb-price usdt Tether ⛺ 26", 9000, 27) \ */
+ /* X("", "sb-price eth Ethereum 🍸 25", 9000, 26) \ */
+ /* X("", "sb-price btc Bitcoin 💰 24", 9000, 25) \ */
+ /* X("", "sb-iplocate", 0, 6) \ */
+
+#endif // CONFIG_H
diff --git a/dwmblocks/dwmblocks.c b/dwmblocks/dwmblocks.c
deleted file mode 100644
index 1bd87f0..0000000
--- a/dwmblocks/dwmblocks.c
+++ /dev/null
@@ -1,296 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <signal.h>
-#include <errno.h>
-#include <X11/Xlib.h>
-#include <sys/signalfd.h>
-#include <poll.h>
-#define LENGTH(X) (sizeof(X) / sizeof (X[0]))
-#define CMDLENGTH 100
-
-typedef struct {
- char* icon;
- char* command;
- unsigned int interval;
- unsigned int signal;
-} Block;
-void sighandler();
-void buttonhandler(int ssi_int);
-void replace(char *str, char old, char new);
-void remove_all(char *str, char to_remove);
-void getcmds(int time);
-void getsigcmds(int signal);
-void setupsignals();
-int getstatus(char *str, char *last);
-void setroot();
-void statusloop();
-void termhandler(int signum);
-
-
-#include "config.h"
-
-static Display *dpy;
-static int screen;
-static Window root;
-static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
-static char statusstr[2][256];
-static int statusContinue = 1;
-static int signalFD;
-static int timerInterval = -1;
-static void (*writestatus) () = setroot;
-
-void replace(char *str, char old, char new)
-{
- for(char * c = str; *c; c++)
- if(*c == old)
- *c = new;
-}
-
-// the previous function looked nice but unfortunately it didnt work if to_remove was in any position other than the last character
-// theres probably still a better way of doing this
-void remove_all(char *str, char to_remove) {
- char *read = str;
- char *write = str;
- while (*read) {
- if (*read != to_remove) {
- *write++ = *read;
- }
- ++read;
- }
- *write = '\0';
-}
-
-int gcd(int a, int b)
-{
- int temp;
- while (b > 0){
- temp = a % b;
-
- a = b;
- b = temp;
- }
- return a;
-}
-
-
-//opens process *cmd and stores output in *output
-void getcmd(const Block *block, char *output)
-{
- if (block->signal)
- {
- output[0] = block->signal;
- output++;
- }
- char *cmd = block->command;
- FILE *cmdf = popen(cmd,"r");
- if (!cmdf){
- //printf("failed to run: %s, %d\n", block->command, errno);
- return;
- }
- char tmpstr[CMDLENGTH] = "";
- // TODO decide whether its better to use the last value till next time or just keep trying while the error was the interrupt
- // this keeps trying to read if it got nothing and the error was an interrupt
- // could also just read to a separate buffer and not move the data over if interrupted
- // this way will take longer trying to complete 1 thing but will get it done
- // the other way will move on to keep going with everything and the part that failed to read will be wrong till its updated again
- // either way you have to save the data to a temp buffer because when it fails it writes nothing and then then it gets displayed before this finishes
- char * s;
- int e;
- do {
- errno = 0;
- s = fgets(tmpstr, CMDLENGTH-(strlen(delim)+1), cmdf);
- e = errno;
- } while (!s && e == EINTR);
- pclose(cmdf);
- int i = strlen(block->icon);
- strcpy(output, block->icon);
- strcpy(output+i, tmpstr);
- remove_all(output, '\n');
- i = strlen(output);
- if ((i > 0 && block != &blocks[LENGTH(blocks) - 1])){
- strcat(output, delim);
- }
- i+=strlen(delim);
- output[i++] = '\0';
-}
-
-void getcmds(int time)
-{
- const Block* current;
- for(int i = 0; i < LENGTH(blocks); i++)
- {
- current = blocks + i;
- if ((current->interval != 0 && time % current->interval == 0) || time == -1){
- getcmd(current,statusbar[i]);
- }
- }
-}
-
-void getsigcmds(int signal)
-{
- const Block *current;
- for (int i = 0; i < LENGTH(blocks); i++)
- {
- current = blocks + i;
- if (current->signal == signal){
- getcmd(current,statusbar[i]);
- }
- }
-}
-
-void setupsignals()
-{
- sigset_t signals;
- sigemptyset(&signals);
- sigaddset(&signals, SIGALRM); // Timer events
- sigaddset(&signals, SIGUSR1); // Button events
- // All signals assigned to blocks
- for (size_t i = 0; i < LENGTH(blocks); i++)
- if (blocks[i].signal > 0)
- sigaddset(&signals, SIGRTMIN + blocks[i].signal);
- // Create signal file descriptor for pooling
- signalFD = signalfd(-1, &signals, 0);
- // Block all real-time signals
- for (int i = SIGRTMIN; i <= SIGRTMAX; i++) sigaddset(&signals, i);
- sigprocmask(SIG_BLOCK, &signals, NULL);
- // Do not transform children into zombies
- struct sigaction sigchld_action = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_NOCLDWAIT
- };
- sigaction(SIGCHLD, &sigchld_action, NULL);
-
-}
-
-int getstatus(char *str, char *last)
-{
- strcpy(last, str);
- str[0] = '\0';
- for(int i = 0; i < LENGTH(blocks); i++) {
- strcat(str, statusbar[i]);
- if (i == LENGTH(blocks) - 1)
- strcat(str, " ");
- }
- str[strlen(str)-1] = '\0';
- return strcmp(str, last);//0 if they are the same
-}
-
-void setroot()
-{
- if (!getstatus(statusstr[0], statusstr[1]))//Only set root if text has changed.
- return;
- Display *d = XOpenDisplay(NULL);
- if (d) {
- dpy = d;
- }
- screen = DefaultScreen(dpy);
- root = RootWindow(dpy, screen);
- XStoreName(dpy, root, statusstr[0]);
- XCloseDisplay(dpy);
-}
-
-void pstdout()
-{
- if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed.
- return;
- printf("%s\n",statusstr[0]);
- fflush(stdout);
-}
-
-
-void statusloop()
-{
- setupsignals();
- // first figure out the default wait interval by finding the
- // greatest common denominator of the intervals
- for(int i = 0; i < LENGTH(blocks); i++){
- if(blocks[i].interval){
- timerInterval = gcd(blocks[i].interval, timerInterval);
- }
- }
- getcmds(-1); // Fist time run all commands
- raise(SIGALRM); // Schedule first timer event
- int ret;
- struct pollfd pfd[] = {{.fd = signalFD, .events = POLLIN}};
- while (statusContinue) {
- // Wait for new signal
- ret = poll(pfd, sizeof(pfd) / sizeof(pfd[0]), -1);
- if (ret < 0 || !(pfd[0].revents & POLLIN)) break;
- sighandler(); // Handle signal
- }
-}
-
-void sighandler()
-{
- static int time = 0;
- struct signalfd_siginfo si;
- int ret = read(signalFD, &si, sizeof(si));
- if (ret < 0) return;
- int signal = si.ssi_signo;
- switch (signal) {
- case SIGALRM:
- // Execute blocks and schedule the next timer event
- getcmds(time);
- alarm(timerInterval);
- time += timerInterval;
- break;
- case SIGUSR1:
- // Handle buttons
- buttonhandler(si.ssi_int);
- return;
- default:
- // Execute the block that has the given signal
- getsigcmds(signal - SIGRTMIN);
- break;
- }
- writestatus();
-}
-
-void buttonhandler(int ssi_int)
-{
- char button[2] = {('0' + ssi_int) & 0xff, '\0'};
- pid_t process_id = getpid();
- int sig = ssi_int >> 8;
- if (fork() == 0)
- {
- const Block *current;
- for (int i = 0; i < LENGTH(blocks); i++)
- {
- current = blocks + i;
- if (current->signal == sig)
- break;
- }
- char shcmd[1024];
- sprintf(shcmd,"%s && kill -%d %d",current->command, current->signal+34,process_id);
- char *command[] = { "/bin/sh", "-c", shcmd, NULL };
- setenv("BLOCK_BUTTON", button, 1);
- setsid();
- execvp(command[0], command);
- exit(EXIT_SUCCESS);
- }
-}
-
-
-void termhandler(int signum)
-{
- statusContinue = 0;
-}
-
-int main(int argc, char** argv)
-{
- for(int i = 0; i < argc; i++)
- {
- if (!strcmp("-d",argv[i]))
- delim = argv[++i];
- else if(!strcmp("-p",argv[i]))
- writestatus = pstdout;
- }
- signal(SIGTERM, termhandler);
- signal(SIGINT, termhandler);
- statusloop();
- close(signalFD);
-}
-
diff --git a/dwmblocks/include/block.h b/dwmblocks/include/block.h
new file mode 100644
index 0000000..c4f8d54
--- /dev/null
+++ b/dwmblocks/include/block.h
@@ -0,0 +1,29 @@
+#ifndef BLOCK_H
+#define BLOCK_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "util.h"
+
+typedef struct {
+ const char *const icon;
+ const char *const command;
+ const unsigned int interval;
+ const int signal;
+
+ int pipe[PIPE_FD_COUNT];
+ char output[MAX_BLOCK_OUTPUT_LENGTH * UTF8_MAX_BYTE_COUNT + 1];
+ pid_t fork_pid;
+} block;
+
+block block_new(const char *const icon, const char *const command,
+ const unsigned int interval, const int signal);
+int block_init(block *const block);
+int block_deinit(block *const block);
+int block_execute(block *const block, const uint8_t button);
+int block_update(block *const block);
+
+#endif // BLOCK_H
diff --git a/dwmblocks/include/cli.h b/dwmblocks/include/cli.h
new file mode 100644
index 0000000..2f93f62
--- /dev/null
+++ b/dwmblocks/include/cli.h
@@ -0,0 +1,12 @@
+#ifndef CLI_H
+#define CLI_H
+
+#include <stdbool.h>
+
+typedef struct {
+ bool is_debug_mode;
+} cli_arguments;
+
+cli_arguments cli_parse_arguments(const char* const argv[], const int argc);
+
+#endif // CLI_H
diff --git a/dwmblocks/include/main.h b/dwmblocks/include/main.h
new file mode 100644
index 0000000..b37a6b1
--- /dev/null
+++ b/dwmblocks/include/main.h
@@ -0,0 +1,16 @@
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <signal.h>
+
+#include "config.h"
+#include "util.h"
+
+#define REFRESH_SIGNAL SIGUSR1
+
+// Utilise C's adjacent string concatenation to count the number of blocks.
+#define X(...) "."
+enum { BLOCK_COUNT = LEN(BLOCKS(X)) - 1 };
+#undef X
+
+#endif // MAIN_H
diff --git a/dwmblocks/include/signal-handler.h b/dwmblocks/include/signal-handler.h
new file mode 100644
index 0000000..da2d471
--- /dev/null
+++ b/dwmblocks/include/signal-handler.h
@@ -0,0 +1,33 @@
+#ifndef SIGNAL_HANDLER_H
+#define SIGNAL_HANDLER_H
+
+#include <signal.h>
+
+#include "block.h"
+#include "timer.h"
+
+typedef sigset_t signal_set;
+typedef int (*signal_refresh_callback)(block* const blocks,
+ const unsigned short block_count);
+typedef int (*signal_timer_callback)(block* const blocks,
+ const unsigned short block_code,
+ timer* const timer);
+
+typedef struct {
+ int fd;
+ const signal_refresh_callback refresh_callback;
+ const signal_timer_callback timer_callback;
+
+ block* const blocks;
+ const unsigned short block_count;
+} signal_handler;
+
+signal_handler signal_handler_new(
+ block* const blocks, const unsigned short block_count,
+ const signal_refresh_callback refresh_callback,
+ const signal_timer_callback timer_callback);
+int signal_handler_init(signal_handler* const handler);
+int signal_handler_deinit(signal_handler* const handler);
+int signal_handler_process(signal_handler* const handler, timer* const timer);
+
+#endif // SIGNAL_HANDLER_H
diff --git a/dwmblocks/include/status.h b/dwmblocks/include/status.h
new file mode 100644
index 0000000..48fb3d8
--- /dev/null
+++ b/dwmblocks/include/status.h
@@ -0,0 +1,31 @@
+#ifndef STATUS_H
+#define STATUS_H
+
+#include <stdbool.h>
+
+#include "block.h"
+#include "config.h"
+#include "main.h"
+#include "util.h"
+#include "x11.h"
+
+typedef struct {
+#define STATUS_LENGTH \
+ ((BLOCK_COUNT * (MEMBER_LENGTH(block, output) - 1) + CLICKABLE_BLOCKS) + \
+ (BLOCK_COUNT - 1 + LEADING_DELIMITER + TRAILING_DELIMITER) * \
+ (LEN(DELIMITER) - 1) + \
+ 1)
+ char current[STATUS_LENGTH];
+ char previous[STATUS_LENGTH];
+#undef STATUS_LENGTH
+
+ const block* const blocks;
+ const unsigned short block_count;
+} status;
+
+status status_new(const block* const blocks, const unsigned short block_count);
+bool status_update(status* const status);
+int status_write(const status* const status, const bool is_debug_mode,
+ x11_connection* const connection);
+
+#endif // STATUS_H
diff --git a/dwmblocks/include/timer.h b/dwmblocks/include/timer.h
new file mode 100644
index 0000000..1ec7f75
--- /dev/null
+++ b/dwmblocks/include/timer.h
@@ -0,0 +1,21 @@
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <signal.h>
+#include <stdbool.h>
+
+#include "block.h"
+
+#define TIMER_SIGNAL SIGALRM
+
+typedef struct {
+ unsigned int time;
+ const unsigned int tick;
+ const unsigned int reset_value;
+} timer;
+
+timer timer_new(const block *const blocks, const unsigned short block_count);
+int timer_arm(timer *const timer);
+bool timer_must_run_block(const timer *const timer, const block *const block);
+
+#endif // TIMER_H
diff --git a/dwmblocks/include/util.h b/dwmblocks/include/util.h
new file mode 100644
index 0000000..a3bdcce
--- /dev/null
+++ b/dwmblocks/include/util.h
@@ -0,0 +1,28 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stddef.h>
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define BIT(n) (1 << (n))
+
+// NOLINTBEGIN(bugprone-macro-parentheses)
+#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member)
+#define MEMBER_LENGTH(type, member) \
+ (MEMBER_SIZE(type, member) / MEMBER_SIZE(type, member[0]))
+// NOLINTEND(bugprone-macro-parentheses)
+
+#define UTF8_MAX_BYTE_COUNT 4
+
+enum pipe_fd_index {
+ READ_END,
+ WRITE_END,
+ PIPE_FD_COUNT,
+};
+
+unsigned int gcd(unsigned int a, unsigned int b);
+size_t truncate_utf8_string(char* const buffer, const size_t size,
+ const size_t char_limit);
+
+#endif // UTIL_H
diff --git a/dwmblocks/include/watcher.h b/dwmblocks/include/watcher.h
new file mode 100644
index 0000000..ff31809
--- /dev/null
+++ b/dwmblocks/include/watcher.h
@@ -0,0 +1,28 @@
+#ifndef WATCHER_H
+#define WATCHER_H
+
+#include <poll.h>
+#include <stdbool.h>
+
+#include "block.h"
+#include "main.h"
+
+enum watcher_fd_index {
+ SIGNAL_FD = BLOCK_COUNT,
+ WATCHER_FD_COUNT,
+};
+
+typedef struct pollfd watcher_fd;
+
+typedef struct {
+ watcher_fd fds[WATCHER_FD_COUNT];
+ unsigned short active_blocks[BLOCK_COUNT];
+ unsigned short active_block_count;
+ bool got_signal;
+} watcher;
+
+int watcher_init(watcher *const watcher, const block *const blocks,
+ const unsigned short block_count, const int signal_fd);
+int watcher_poll(watcher *const watcher, const int timeout_ms);
+
+#endif // WATCHER_H
diff --git a/dwmblocks/include/x11.h b/dwmblocks/include/x11.h
new file mode 100644
index 0000000..6faaced
--- /dev/null
+++ b/dwmblocks/include/x11.h
@@ -0,0 +1,13 @@
+#ifndef X11_H
+#define X11_H
+
+#include <xcb/xcb.h>
+
+typedef xcb_connection_t x11_connection;
+
+x11_connection* x11_connection_open(void);
+void x11_connection_close(x11_connection* const connection);
+int x11_set_root_name(x11_connection* const connection,
+ const char* const name);
+
+#endif // X11_H
diff --git a/dwmblocks/src/block.c b/dwmblocks/src/block.c
new file mode 100644
index 0000000..a6c919d
--- /dev/null
+++ b/dwmblocks/src/block.c
@@ -0,0 +1,147 @@
+#include "block.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "util.h"
+
+block block_new(const char *const icon, const char *const command,
+ const unsigned int interval, const int signal) {
+ block block = {
+ .icon = icon,
+ .command = command,
+ .interval = interval,
+ .signal = signal,
+
+ .output = {[0] = '\0'},
+ .fork_pid = -1,
+ };
+
+ return block;
+}
+
+int block_init(block *const block) {
+ if (pipe(block->pipe) != 0) {
+ (void)fprintf(stderr,
+ "error: could not create a pipe for \"%s\" block\n",
+ block->command);
+ return 1;
+ }
+
+ return 0;
+}
+
+int block_deinit(block *const block) {
+ int status = close(block->pipe[READ_END]);
+ status |= close(block->pipe[WRITE_END]);
+ if (status != 0) {
+ (void)fprintf(stderr, "error: could not close \"%s\" block's pipe\n",
+ block->command);
+ return 1;
+ }
+
+ return 0;
+}
+
+int block_execute(block *const block, const uint8_t button) {
+ // Ensure only one child process exists per block at an instance.
+ if (block->fork_pid != -1) {
+ return 0;
+ }
+
+ block->fork_pid = fork();
+ if (block->fork_pid == -1) {
+ (void)fprintf(
+ stderr, "error: could not create a subprocess for \"%s\" block\n",
+ block->command);
+ return 1;
+ }
+
+ if (block->fork_pid == 0) {
+ const int write_fd = block->pipe[WRITE_END];
+ int status = close(block->pipe[READ_END]);
+
+ if (button != 0) {
+ char button_str[4];
+ (void)snprintf(button_str, LEN(button_str), "%hhu", button);
+ status |= setenv("BLOCK_BUTTON", button_str, 1);
+ }
+
+ const char null = '\0';
+ if (status != 0) {
+ (void)write(write_fd, &null, sizeof(null));
+ exit(EXIT_FAILURE);
+ }
+
+ FILE *const file = popen(block->command, "r");
+ if (file == NULL) {
+ (void)write(write_fd, &null, sizeof(null));
+ exit(EXIT_FAILURE);
+ }
+
+ // Ensure null-termination since fgets() will leave buffer untouched on
+ // no output.
+ char buffer[LEN(block->output)] = {[0] = null};
+ (void)fgets(buffer, LEN(buffer), file);
+
+ // Remove trailing newlines.
+ const size_t length = strcspn(buffer, "\n");
+ buffer[length] = null;
+
+ // Exit if command execution failed or if file could not be closed.
+ if (pclose(file) != 0) {
+ (void)write(write_fd, &null, sizeof(null));
+ exit(EXIT_FAILURE);
+ }
+
+ const size_t output_size =
+ truncate_utf8_string(buffer, LEN(buffer), MAX_BLOCK_OUTPUT_LENGTH);
+ (void)write(write_fd, buffer, output_size);
+
+ exit(EXIT_SUCCESS);
+ }
+
+ return 0;
+}
+
+int block_update(block *const block) {
+ char buffer[LEN(block->output)];
+
+ const ssize_t bytes_read =
+ read(block->pipe[READ_END], buffer, LEN(buffer));
+ if (bytes_read == -1) {
+ (void)fprintf(stderr,
+ "error: could not fetch output of \"%s\" block\n",
+ block->command);
+ return 2;
+ }
+
+ // Collect exit-status of the subprocess to avoid zombification.
+ int fork_status = 0;
+ if (waitpid(block->fork_pid, &fork_status, 0) == -1) {
+ (void)fprintf(stderr,
+ "error: could not obtain exit status for \"%s\" block\n",
+ block->command);
+ return 2;
+ }
+ block->fork_pid = -1;
+
+ if (fork_status != 0) {
+ (void)fprintf(stderr,
+ "error: \"%s\" block exited with non-zero status\n",
+ block->command);
+ return 1;
+ }
+
+ (void)strncpy(block->output, buffer, LEN(buffer));
+
+ return 0;
+}
diff --git a/dwmblocks/src/cli.c b/dwmblocks/src/cli.c
new file mode 100644
index 0000000..b1849ec
--- /dev/null
+++ b/dwmblocks/src/cli.c
@@ -0,0 +1,33 @@
+#include "cli.h"
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+cli_arguments cli_parse_arguments(const char *const argv[], const int argc) {
+ errno = 0;
+ cli_arguments args = {
+ .is_debug_mode = false,
+ };
+
+ int opt = -1;
+ opterr = 0; // Suppress getopt's built-in invalid opt message
+ while ((opt = getopt(argc, (char *const *)argv, "dh")) != -1) {
+ switch (opt) {
+ case 'd':
+ args.is_debug_mode = true;
+ break;
+ case '?':
+ (void)fprintf(stderr, "error: unknown option `-%c'\n", optopt);
+ // fall through
+ case 'h':
+ // fall through
+ default:
+ (void)fprintf(stderr, "usage: %s [-d]\n", BINARY);
+ errno = 1;
+ }
+ }
+
+ return args;
+}
diff --git a/dwmblocks/src/main.c b/dwmblocks/src/main.c
new file mode 100644
index 0000000..747b075
--- /dev/null
+++ b/dwmblocks/src/main.c
@@ -0,0 +1,168 @@
+#include "main.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "block.h"
+#include "cli.h"
+#include "config.h"
+#include "signal-handler.h"
+#include "status.h"
+#include "timer.h"
+#include "util.h"
+#include "watcher.h"
+#include "x11.h"
+
+static int init_blocks(block *const blocks, const unsigned short block_count) {
+ for (unsigned short i = 0; i < block_count; ++i) {
+ block *const block = &blocks[i];
+ if (block_init(block) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int deinit_blocks(block *const blocks,
+ const unsigned short block_count) {
+ for (unsigned short i = 0; i < block_count; ++i) {
+ block *const block = &blocks[i];
+ if (block_deinit(block) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int execute_blocks(block *const blocks,
+ const unsigned short block_count,
+ const timer *const timer) {
+ for (unsigned short i = 0; i < block_count; ++i) {
+ block *const block = &blocks[i];
+ if (!timer_must_run_block(timer, block)) {
+ continue;
+ }
+
+ if (block_execute(&blocks[i], 0) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int trigger_event(block *const blocks, const unsigned short block_count,
+ timer *const timer) {
+ if (execute_blocks(blocks, block_count, timer) != 0) {
+ return 1;
+ }
+
+ if (timer_arm(timer) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int refresh_callback(block *const blocks,
+ const unsigned short block_count) {
+ if (execute_blocks(blocks, block_count, NULL) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int event_loop(block *const blocks, const unsigned short block_count,
+ const bool is_debug_mode,
+ x11_connection *const connection,
+ signal_handler *const signal_handler) {
+ timer timer = timer_new(blocks, block_count);
+
+ // Kickstart the event loop with an initial execution.
+ if (trigger_event(blocks, block_count, &timer) != 0) {
+ return 1;
+ }
+
+ watcher watcher;
+ if (watcher_init(&watcher, blocks, block_count, signal_handler->fd) != 0) {
+ return 1;
+ }
+
+ status status = status_new(blocks, block_count);
+ bool is_alive = true;
+ while (is_alive) {
+ if (watcher_poll(&watcher, -1) != 0) {
+ return 1;
+ }
+
+ if (watcher.got_signal) {
+ is_alive = signal_handler_process(signal_handler, &timer) == 0;
+ }
+
+ for (unsigned short i = 0; i < watcher.active_block_count; ++i) {
+ (void)block_update(&blocks[watcher.active_blocks[i]]);
+ }
+
+ const bool has_status_changed = status_update(&status);
+ if (has_status_changed &&
+ status_write(&status, is_debug_mode, connection) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int main(const int argc, const char *const argv[]) {
+ const cli_arguments cli_args = cli_parse_arguments(argv, argc);
+ if (errno != 0) {
+ return 1;
+ }
+
+ x11_connection *const connection = x11_connection_open();
+ if (connection == NULL) {
+ return 1;
+ }
+
+#define BLOCK(icon, command, interval, signal) \
+ block_new(icon, command, interval, signal),
+ block blocks[BLOCK_COUNT] = {BLOCKS(BLOCK)};
+#undef BLOCK
+ const unsigned short block_count = LEN(blocks);
+
+ int status = 0;
+ if (init_blocks(blocks, block_count) != 0) {
+ status = 1;
+ goto x11_close;
+ }
+
+ signal_handler signal_handler = signal_handler_new(
+ blocks, block_count, refresh_callback, trigger_event);
+ if (signal_handler_init(&signal_handler) != 0) {
+ status = 1;
+ goto deinit_blocks;
+ }
+
+ if (event_loop(blocks, block_count, cli_args.is_debug_mode, connection,
+ &signal_handler) != 0) {
+ status = 1;
+ }
+
+ if (signal_handler_deinit(&signal_handler) != 0) {
+ status = 1;
+ }
+
+deinit_blocks:
+ if (deinit_blocks(blocks, block_count) != 0) {
+ status = 1;
+ }
+
+x11_close:
+ x11_connection_close(connection);
+
+ return status;
+}
diff --git a/dwmblocks/src/signal-handler.c b/dwmblocks/src/signal-handler.c
new file mode 100644
index 0000000..d816dcd
--- /dev/null
+++ b/dwmblocks/src/signal-handler.c
@@ -0,0 +1,124 @@
+#include "signal-handler.h"
+
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "block.h"
+#include "main.h"
+#include "timer.h"
+
+typedef struct signalfd_siginfo signal_info;
+
+signal_handler signal_handler_new(
+ block *const blocks, const unsigned short block_count,
+ const signal_refresh_callback refresh_callback,
+ const signal_timer_callback timer_callback) {
+ signal_handler handler = {
+ .refresh_callback = refresh_callback,
+ .timer_callback = timer_callback,
+
+ .blocks = blocks,
+ .block_count = block_count,
+ };
+
+ return handler;
+}
+
+int signal_handler_init(signal_handler *const handler) {
+ signal_set set;
+ (void)sigemptyset(&set);
+
+ // Handle user-generated signal for refreshing the status.
+ (void)sigaddset(&set, REFRESH_SIGNAL);
+
+ // Handle SIGALRM generated by the timer.
+ (void)sigaddset(&set, TIMER_SIGNAL);
+
+ // Handle termination signals.
+ (void)sigaddset(&set, SIGINT);
+ (void)sigaddset(&set, SIGTERM);
+
+ for (unsigned short i = 0; i < handler->block_count; ++i) {
+ const block *const block = &handler->blocks[i];
+ if (block->signal > 0) {
+ if (sigaddset(&set, SIGRTMIN + block->signal) != 0) {
+ (void)fprintf(
+ stderr,
+ "error: invalid or unsupported signal specified for "
+ "\"%s\" block\n",
+ block->command);
+ return 1;
+ }
+ }
+ }
+
+ // Create a signal file descriptor for epoll to watch.
+ handler->fd = signalfd(-1, &set, 0);
+ if (handler->fd == -1) {
+ (void)fprintf(stderr,
+ "error: could not create file descriptor for signals\n");
+ return 1;
+ }
+
+ // Block all realtime and handled signals.
+ for (int i = SIGRTMIN; i <= SIGRTMAX; ++i) {
+ (void)sigaddset(&set, i);
+ }
+ (void)sigprocmask(SIG_BLOCK, &set, NULL);
+
+ return 0;
+}
+
+int signal_handler_deinit(signal_handler *const handler) {
+ if (close(handler->fd) != 0) {
+ (void)fprintf(stderr,
+ "error: could not close signal file descriptor\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int signal_handler_process(signal_handler *const handler, timer *const timer) {
+ signal_info info;
+ const ssize_t bytes_read = read(handler->fd, &info, sizeof(info));
+ if (bytes_read == -1) {
+ (void)fprintf(stderr, "error: could not read info of incoming signal");
+ return 1;
+ }
+
+ const int signal = (int)info.ssi_signo;
+ switch (signal) {
+ case TIMER_SIGNAL:
+ if (handler->timer_callback(handler->blocks, handler->block_count,
+ timer) != 0) {
+ return 1;
+ }
+ return 0;
+ case REFRESH_SIGNAL:
+ if (handler->refresh_callback(handler->blocks,
+ handler->block_count) != 0) {
+ return 1;
+ }
+ return 0;
+ case SIGTERM:
+ // fall through
+ case SIGINT:
+ return 1;
+ }
+
+ for (unsigned short i = 0; i < handler->block_count; ++i) {
+ block *const block = &handler->blocks[i];
+ if (block->signal == signal - SIGRTMIN) {
+ const uint8_t button = (uint8_t)info.ssi_int;
+ block_execute(block, button);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/dwmblocks/src/status.c b/dwmblocks/src/status.c
new file mode 100644
index 0000000..cf0911a
--- /dev/null
+++ b/dwmblocks/src/status.c
@@ -0,0 +1,78 @@
+#include "status.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "block.h"
+#include "config.h"
+#include "util.h"
+#include "x11.h"
+
+static bool has_status_changed(const status *const status) {
+ return strcmp(status->current, status->previous) != 0;
+}
+
+status status_new(const block *const blocks,
+ const unsigned short block_count) {
+ status status = {
+ .current = {[0] = '\0'},
+ .previous = {[0] = '\0'},
+
+ .blocks = blocks,
+ .block_count = block_count,
+ };
+
+ return status;
+}
+
+bool status_update(status *const status) {
+ (void)strncpy(status->previous, status->current, LEN(status->current));
+ status->current[0] = '\0';
+
+ for (unsigned short i = 0; i < status->block_count; ++i) {
+ const block *const block = &status->blocks[i];
+
+ if (strlen(block->output) > 0) {
+#if LEADING_DELIMITER
+ (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
+#else
+ if (status->current[0] != '\0') {
+ (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
+ }
+#endif
+
+#if CLICKABLE_BLOCKS
+ if (block->signal > 0) {
+ const char signal[] = {(char)block->signal, '\0'};
+ (void)strncat(status->current, signal, LEN(signal));
+ }
+#endif
+
+ (void)strncat(status->current, block->icon, LEN(block->output));
+ (void)strncat(status->current, block->output, LEN(block->output));
+ }
+ }
+
+#if TRAILING_DELIMITER
+ if (status->current[0] != '\0') {
+ (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
+ }
+#endif
+
+ return has_status_changed(status);
+}
+
+int status_write(const status *const status, const bool is_debug_mode,
+ x11_connection *const connection) {
+ if (is_debug_mode) {
+ (void)printf("%s\n", status->current);
+ return 0;
+ }
+
+ if (x11_set_root_name(connection, status->current) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/dwmblocks/src/timer.c b/dwmblocks/src/timer.c
new file mode 100644
index 0000000..2ee555b
--- /dev/null
+++ b/dwmblocks/src/timer.c
@@ -0,0 +1,72 @@
+#include "timer.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "block.h"
+#include "util.h"
+
+static unsigned int compute_tick(const block *const blocks,
+ const unsigned short block_count) {
+ unsigned int tick = 0;
+
+ for (unsigned short i = 0; i < block_count; ++i) {
+ const block *const block = &blocks[i];
+ tick = gcd(block->interval, tick);
+ }
+
+ return tick;
+}
+
+static unsigned int compute_reset_value(const block *const blocks,
+ const unsigned short block_count) {
+ unsigned int reset_value = 1;
+
+ for (unsigned short i = 0; i < block_count; ++i) {
+ const block *const block = &blocks[i];
+ reset_value = MAX(block->interval, reset_value);
+ }
+
+ return reset_value;
+}
+
+timer timer_new(const block *const blocks, const unsigned short block_count) {
+ const unsigned int reset_value = compute_reset_value(blocks, block_count);
+
+ timer timer = {
+ .time = reset_value, // Initial value to execute all blocks.
+ .tick = compute_tick(blocks, block_count),
+ .reset_value = reset_value,
+ };
+
+ return timer;
+}
+
+int timer_arm(timer *const timer) {
+ errno = 0;
+ (void)alarm(timer->tick);
+
+ if (errno != 0) {
+ (void)fprintf(stderr, "error: could not arm timer\n");
+ return 1;
+ }
+
+ // Wrap `time` to the interval [1, reset_value].
+ timer->time = (timer->time + timer->tick) % timer->reset_value;
+
+ return 0;
+}
+
+bool timer_must_run_block(const timer *const timer, const block *const block) {
+ if (timer == NULL || timer->time == timer->reset_value) {
+ return true;
+ }
+
+ if (block->interval == 0) {
+ return false;
+ }
+
+ return timer->time % block->interval == 0;
+}
diff --git a/dwmblocks/src/util.c b/dwmblocks/src/util.c
new file mode 100644
index 0000000..10485db
--- /dev/null
+++ b/dwmblocks/src/util.c
@@ -0,0 +1,49 @@
+#include "util.h"
+
+#define UTF8_MULTIBYTE_BIT BIT(7)
+
+unsigned int gcd(unsigned int a, unsigned int b) {
+ while (b > 0) {
+ const unsigned int temp = a % b;
+ a = b;
+ b = temp;
+ }
+
+ return a;
+}
+
+size_t truncate_utf8_string(char* const buffer, const size_t size,
+ const size_t char_limit) {
+ size_t char_count = 0;
+ size_t i = 0;
+ while (char_count < char_limit) {
+ char ch = buffer[i];
+ if (ch == '\0') {
+ break;
+ }
+
+ unsigned short skip = 1;
+
+ // Multibyte unicode character.
+ if ((ch & UTF8_MULTIBYTE_BIT) != 0) {
+ // Skip continuation bytes.
+ ch <<= 1;
+ while ((ch & UTF8_MULTIBYTE_BIT) != 0) {
+ ch <<= 1;
+ ++skip;
+ }
+ }
+
+ // Avoid buffer overflow.
+ if (i + skip >= size) {
+ break;
+ }
+
+ ++char_count;
+ i += skip;
+ }
+
+ buffer[i] = '\0';
+
+ return i + 1;
+}
diff --git a/dwmblocks/src/watcher.c b/dwmblocks/src/watcher.c
new file mode 100644
index 0000000..71b6c52
--- /dev/null
+++ b/dwmblocks/src/watcher.c
@@ -0,0 +1,69 @@
+#include "watcher.h"
+
+#include <errno.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "block.h"
+#include "util.h"
+
+static bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) {
+ return (watcher_fd->revents & POLLIN) != 0;
+}
+
+int watcher_init(watcher* const watcher, const block* const blocks,
+ const unsigned short block_count, const int signal_fd) {
+ if (signal_fd == -1) {
+ (void)fprintf(
+ stderr,
+ "error: invalid signal file descriptor passed to watcher\n");
+ return 1;
+ }
+
+ watcher_fd* const fd = &watcher->fds[SIGNAL_FD];
+ fd->fd = signal_fd;
+ fd->events = POLLIN;
+
+ for (unsigned short i = 0; i < block_count; ++i) {
+ const int block_fd = blocks[i].pipe[READ_END];
+ if (block_fd == -1) {
+ (void)fprintf(
+ stderr,
+ "error: invalid block file descriptors passed to watcher\n");
+ return 1;
+ }
+
+ watcher_fd* const fd = &watcher->fds[i];
+ fd->fd = block_fd;
+ fd->events = POLLIN;
+ }
+
+ return 0;
+}
+
+int watcher_poll(watcher* watcher, const int timeout_ms) {
+ int event_count = poll(watcher->fds, LEN(watcher->fds), timeout_ms);
+
+ // Don't return non-zero status for signal interruptions.
+ if (event_count == -1 && errno != EINTR) {
+ (void)fprintf(stderr, "error: watcher could not poll blocks\n");
+ return 1;
+ }
+
+ watcher->got_signal = watcher_fd_is_readable(&watcher->fds[SIGNAL_FD]);
+
+ watcher->active_block_count = event_count - (int)watcher->got_signal;
+ unsigned short i = 0;
+ unsigned short j = 0;
+ while (i < event_count && j < LEN(watcher->active_blocks)) {
+ if (watcher_fd_is_readable(&watcher->fds[j])) {
+ watcher->active_blocks[i] = j;
+ ++i;
+ }
+
+ ++j;
+ }
+
+ return 0;
+}
diff --git a/dwmblocks/src/x11.c b/dwmblocks/src/x11.c
new file mode 100644
index 0000000..7a310e9
--- /dev/null
+++ b/dwmblocks/src/x11.c
@@ -0,0 +1,44 @@
+#include "x11.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+
+x11_connection *x11_connection_open(void) {
+ xcb_connection_t *const connection = xcb_connect(NULL, NULL);
+ if (xcb_connection_has_error(connection)) {
+ (void)fprintf(stderr, "error: could not connect to X server\n");
+ return NULL;
+ }
+
+ return connection;
+}
+
+void x11_connection_close(xcb_connection_t *const connection) {
+ xcb_disconnect(connection);
+}
+
+int x11_set_root_name(x11_connection *const connection, const char *name) {
+ xcb_screen_t *const screen =
+ xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
+ const xcb_window_t root_window = screen->root;
+
+ const unsigned short name_format = 8;
+ const xcb_void_cookie_t cookie = xcb_change_property(
+ connection, XCB_PROP_MODE_REPLACE, root_window, XCB_ATOM_WM_NAME,
+ XCB_ATOM_STRING, name_format, strlen(name), name);
+
+ xcb_generic_error_t *error = xcb_request_check(connection, cookie);
+ if (error != NULL) {
+ (void)fprintf(stderr, "error: could not set X root name\n");
+ return 1;
+ }
+
+ if (xcb_flush(connection) <= 0) {
+ (void)fprintf(stderr, "error: could not flush X output buffer\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/slock/slock.c b/slock/slock.c
index 9af2dfe..45dbf6a 100644
--- a/slock/slock.c
+++ b/slock/slock.c
@@ -330,6 +330,7 @@ drawlogo(Display *dpy, struct lock *lock, int color)
XCopyArea(dpy, lock->drawable, lock->win, lock->gc, 0, 0, lock->x, lock->y, 0, 0);
XSync(dpy, False);
}
+
static void
refresh(Display *dpy, Window win , int screen, struct tm time, cairo_t* cr, cairo_surface_t* sfc)
{/*Function that displays given time on the given screen*/
@@ -348,7 +349,7 @@ refresh(Display *dpy, Window win , int screen, struct tm time, cairo_t* cr, cair
text_width = extents.width;
text_height = extents.height;
- xpos = (DisplayWidth(dpy, screen) - text_width) / 2;
+ xpos = DisplayWidth(dpy, screen) / 4 - text_width / 2;
ypos = (DisplayHeight(dpy, screen) + 12 * text_height) / 2;
cairo_move_to(cr, xpos, ypos);
cairo_show_text(cr, tm);
@@ -356,6 +357,7 @@ refresh(Display *dpy, Window win , int screen, struct tm time, cairo_t* cr, cair
writemessage(dpy, win, screen);
XFlush(dpy);
}
+
static void*
displayTime(void* input)
{ /*Thread that keeps track of time and refreshes it every 5 seconds */
@@ -374,8 +376,6 @@ displayTime(void* input)
return NULL;
}
-
-
static void
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
const char *hash,cairo_t **crs,cairo_surface_t **surfaces)
diff --git a/st/FAQ b/st/FAQ
new file mode 100644
index 0000000..6287a27
--- /dev/null
+++ b/st/FAQ
@@ -0,0 +1,253 @@
+## Why does st not handle utmp entries?
+
+Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
+
+
+## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
+
+It means that st doesn’t have any terminfo entry on your system. Chances are
+you did not `make install`. If you just want to test it without installing it,
+you can manually run `tic -sx st.info`.
+
+
+## Nothing works, and nothing is said about an unknown terminal!
+
+* Some programs just assume they’re running in xterm i.e. they don’t rely on
+ terminfo. What you see is the current state of the “xterm compliance”.
+* Some programs don’t complain about the lacking st description and default to
+ another terminal. In that case see the question about terminfo.
+
+
+## How do I scroll back up?
+
+* Using a terminal multiplexer.
+ * `st -e tmux` using C-b [
+ * `st -e screen` using C-a ESC
+* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
+* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
+
+
+## I would like to have utmp and/or scroll functionality by default
+
+You can add the absolute path of both programs in your config.h file. You only
+have to modify the value of utmp and scroll variables.
+
+
+## Why doesn't the Del key work in some programs?
+
+Taken from the terminfo manpage:
+
+ If the terminal has a keypad that transmits codes when the keys
+ are pressed, this information can be given. Note that it is not
+ possible to handle terminals where the keypad only works in
+ local (this applies, for example, to the unshifted HP 2621 keys).
+ If the keypad can be set to transmit or not transmit, give these
+ codes as smkx and rmkx. Otherwise the keypad is assumed to
+ always transmit.
+
+In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
+applications which want to test against keypad keys send these
+sequences.
+
+But buggy applications (like bash and irssi, for example) don't do this. A fast
+solution for them is to use the following command:
+
+ $ printf '\033[?1h\033=' >/dev/tty
+
+or
+ $ tput smkx
+
+In the case of bash, readline is used. Readline has a different note in its
+manpage about this issue:
+
+ enable-keypad (Off)
+ When set to On, readline will try to enable the
+ application keypad when it is called. Some systems
+ need this to enable arrow keys.
+
+Adding this option to your .inputrc will fix the keypad problem for all
+applications using readline.
+
+If you are using zsh, then read the zsh FAQ
+<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>:
+
+ It should be noted that the O / [ confusion can occur with other keys
+ such as Home and End. Some systems let you query the key sequences
+ sent by these keys from the system's terminal database, terminfo.
+ Unfortunately, the key sequences given there typically apply to the
+ mode that is not the one zsh uses by default (it's the "application"
+ mode rather than the "raw" mode). Explaining the use of terminfo is
+ outside of the scope of this FAQ, but if you wish to use the key
+ sequences given there you can tell the line editor to turn on
+ "application" mode when it starts and turn it off when it stops:
+
+ function zle-line-init () { echoti smkx }
+ function zle-line-finish () { echoti rmkx }
+ zle -N zle-line-init
+ zle -N zle-line-finish
+
+Putting these lines into your .zshrc will fix the problems.
+
+
+## How can I use meta in 8bit mode?
+
+St supports meta in 8bit mode, but the default terminfo entry doesn't
+use this capability. If you want it, you have to use the 'st-meta' value
+in TERM.
+
+
+## I cannot compile st in OpenBSD
+
+OpenBSD lacks librt, despite it being mandatory in POSIX
+<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
+If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and
+st will compile without any loss of functionality, because all the functions are
+included in libc on this platform.
+
+
+## The Backspace Case
+
+St is emulating the Linux way of handling backspace being delete and delete being
+backspace.
+
+This is an issue that was discussed in suckless mailing list
+<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
+terminal users wants its backspace to be how he feels it:
+
+ Well, I am going to comment why I want to change the behaviour
+ of this key. When ASCII was defined in 1968, communication
+ with computers was done using punched cards, or hardcopy
+ terminals (basically a typewriter machine connected with the
+ computer using a serial port). ASCII defines DELETE as 7F,
+ because, in punched-card terms, it means all the holes of the
+ card punched; it is thus a kind of 'physical delete'. In the
+ same way, the BACKSPACE key was a non-destructive backspace,
+ as on a typewriter. So, if you wanted to delete a character,
+ you had to BACKSPACE and then DELETE. Another use of BACKSPACE
+ was to type accented characters, for example 'a BACKSPACE `'.
+ The VT100 had no BACKSPACE key; it was generated using the
+ CONTROL key as another control character (CONTROL key sets to
+ 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code
+ 0x08)), but it had a DELETE key in a similar position where
+ the BACKSPACE key is located today on common PC keyboards.
+ All the terminal emulators emulated the difference between
+ these keys correctly: the backspace key generated a BACKSPACE
+ (^H) and delete key generated a DELETE (^?).
+
+ But a problem arose when Linus Torvalds wrote Linux. Unlike
+ earlier terminals, the Linux virtual terminal (the terminal
+ emulator integrated in the kernel) returned a DELETE when
+ backspace was pressed, due to the VT100 having a DELETE key in
+ the same position. This created a lot of problems (see [1]
+ and [2]). Since Linux has become the king, a lot of terminal
+ emulators today generate a DELETE when the backspace key is
+ pressed in order to avoid problems with Linux. The result is
+ that the only way of generating a BACKSPACE on these systems
+ is by using CONTROL + H. (I also think that emacs had an
+ important point here because the CONTROL + H prefix is used
+ in emacs in some commands (help commands).)
+
+ From point of view of the kernel, you can change the key
+ for deleting a previous character with stty erase. When you
+ connect a real terminal into a machine you describe the type
+ of terminal, so getty configures the correct value of stty
+ erase for this terminal. In the case of terminal emulators,
+ however, you don't have any getty that can set the correct
+ value of stty erase, so you always get the default value.
+ For this reason, it is necessary to add 'stty erase ^H' to your
+ profile if you have changed the value of the backspace key.
+ Of course, another solution is for st itself to modify the
+ value of stty erase. I usually have the inverse problem:
+ when I connect to non-Unix machines, I have to press CONTROL +
+ h to get a BACKSPACE. The inverse problem occurs when a user
+ connects to my Unix machines from a different system with a
+ correct backspace key.
+
+ [1] http://www.ibb.net/~anne/keyboard.html
+ [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
+
+
+## But I really want the old grumpy behaviour of my terminal
+
+Apply [1].
+
+[1] https://st.suckless.org/patches/delkey
+
+
+## Why do images not work in st using the w3m image hack?
+
+w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
+window. The hack relies on the terminal to use a single buffer to draw its
+contents directly.
+
+st uses double-buffered drawing so the image is quickly replaced and may show a
+short flicker effect.
+
+Below is a patch example to change st double-buffering to a single Drawable
+buffer.
+
+diff --git a/x.c b/x.c
+--- a/x.c
++++ b/x.c
+@@ -732,10 +732,6 @@ xresize(int col, int row)
+ win.tw = col * win.cw;
+ win.th = row * win.ch;
+
+- XFreePixmap(xw.dpy, xw.buf);
+- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
+- XftDrawChange(xw.draw, xw.buf);
+ xclear(0, 0, win.w, win.h);
+
+ /* resize to new width */
+@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
+ gcvalues.graphics_exposures = False;
+ dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+ &gcvalues);
+- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
++ xw.buf = xw.win;
+ XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
+ XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
+
+@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
+ void
+ xfinishdraw(void)
+ {
+- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
+- win.h, 0, 0);
+ XSetForeground(xw.dpy, dc.gc,
+ dc.col[IS_SET(MODE_REVERSE)?
+ defaultfg : defaultbg].pixel);
+
+
+## BadLength X error in Xft when trying to render emoji
+
+Xft makes st crash when rendering color emojis with the following error:
+
+"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
+ Major opcode of failed request: 139 (RENDER)
+ Minor opcode of failed request: 20 (RenderAddGlyphs)
+ Serial number of failed request: 1595
+ Current serial number in output stream: 1818"
+
+This is a known bug in Xft (not st) which happens on some platforms and
+combination of particular fonts and fontconfig settings.
+
+See also:
+https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
+https://bugs.freedesktop.org/show_bug.cgi?id=107534
+https://bugzilla.redhat.com/show_bug.cgi?id=1498269
+
+The solution is to remove color emoji fonts or disable this in the fontconfig
+XML configuration. As an ugly workaround (which may work only on newer
+fontconfig versions (FC_COLOR)), the following code can be used to mask color
+fonts:
+
+ FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
+
+Please don't bother reporting this bug to st, but notify the upstream Xft
+developers about fixing this bug.
+
+As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5:
+https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS
diff --git a/st/FUNDING.yml b/st/FUNDING.yml
deleted file mode 100644
index c7c9a22..0000000
--- a/st/FUNDING.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-custom: ["https://lukesmith.xyz/donate.html"]
-github: lukesmithxyz
diff --git a/st/LEGACY b/st/LEGACY
new file mode 100644
index 0000000..bf28b1e
--- /dev/null
+++ b/st/LEGACY
@@ -0,0 +1,17 @@
+A STATEMENT ON LEGACY SUPPORT
+
+In the terminal world there is much cruft that comes from old and unsup‐
+ported terminals that inherit incompatible modes and escape sequences
+which noone is able to know, except when he/she comes from that time and
+developed a graphical vt100 emulator at that time.
+
+One goal of st is to only support what is really needed. When you en‐
+counter a sequence which you really need, implement it. But while you
+are at it, do not add the other cruft you might encounter while sneek‐
+ing at other terminal emulators. History has bloated them and there is
+no real evidence that most of the sequences are used today.
+
+
+Christoph Lohmann <20h@r-36.net>
+2012-09-13T07:00:36.081271045+02:00
+
diff --git a/st/Makefile b/st/Makefile
index da95823..facf7d9 100644
--- a/st/Makefile
+++ b/st/Makefile
@@ -4,16 +4,10 @@
include config.mk
-SRC = st.c x.c boxdraw.c hb.c
+SRC = st.c x.c boxdraw.c
OBJ = $(SRC:.c=.o)
-all: options st
-
-options:
- @echo st build options:
- @echo "CFLAGS = $(STCFLAGS)"
- @echo "LDFLAGS = $(STLDFLAGS)"
- @echo "CC = $(CC)"
+all: st
config.h:
cp config.def.h config.h
@@ -22,8 +16,7 @@ config.h:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
-x.o: arg.h config.h st.h win.h hb.h
-hb.o: st.h
+x.o: arg.h config.h st.h win.h
boxdraw.o: config.h st.h boxdraw_data.h
$(OBJ): config.h config.mk
@@ -45,11 +38,9 @@ dist: clean
install: st
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f st $(DESTDIR)$(PREFIX)/bin
- cp -f st-copyout $(DESTDIR)$(PREFIX)/bin
- cp -f st-urlhandler $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/st
- chmod 755 $(DESTDIR)$(PREFIX)/bin/st-copyout
- chmod 755 $(DESTDIR)$(PREFIX)/bin/st-urlhandler
+ cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
@@ -57,9 +48,8 @@ install: st
@echo Please see the README file regarding the terminfo entry of st.
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/st\
- $(DESTDIR)$(PREFIX)/bin/st-copyout\
- $(DESTDIR)$(PREFIX)/bin/st-urlhandler\
- $(DESTDIR)$(MANPREFIX)/man1/st.1
+ rm -f $(DESTDIR)$(PREFIX)/bin/st
+ rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
+ rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
-.PHONY: all options clean dist install uninstall
+.PHONY: all clean dist install uninstall
diff --git a/st/PKGBUILD b/st/PKGBUILD
deleted file mode 100644
index 38dcb30..0000000
--- a/st/PKGBUILD
+++ /dev/null
@@ -1,45 +0,0 @@
-# Maintainer:
-
-pkgname=st-thesiah-git
-_pkgname=st
-pkgver=0.8.2.r1062.2087ab9
-pkgrel=1
-epoch=1
-pkgdesc="Soomin's simple (suckless) terminal with vim-bindings, transparency, xresources, etc. "
-url='https://github.com/TheSiahxyz/suckless/tree/main/st'
-arch=('i686' 'x86_64')
-license=('MIT')
-options=('zipman')
-depends=('libxft')
-makedepends=('ncurses' 'libxext' 'git')
-optdepends=('dmenu: feed urls to dmenu')
-source=(git+https://github.com/TheSiahxyz/suckless/tree/main/st)
-sha1sums=('SKIP')
-
-provides=("${_pkgname}")
-conflicts=("${_pkgname}")
-
-pkgver() {
- cd "${_pkgname}"
- printf "%s.r%s.%s" "$(awk '/^VERSION =/ {print $3}' config.mk)" \
- "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
-}
-
-prepare() {
- cd $srcdir/${_pkgname}
- # skip terminfo which conflicts with ncurses
- sed -i '/tic /d' Makefile
-}
-
-build() {
- cd "${_pkgname}"
- make X11INC=/usr/include/X11 X11LIB=/usr/lib/X11
-}
-
-package() {
- cd "${_pkgname}"
- make PREFIX=/usr DESTDIR="${pkgdir}" install
- install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
- install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"
- install -Dm644 Xdefaults "${pkgdir}/usr/share/doc/${pkgname}/Xdefaults.example"
-}
diff --git a/st/README b/st/README
new file mode 100644
index 0000000..6a846ed
--- /dev/null
+++ b/st/README
@@ -0,0 +1,34 @@
+st - simple terminal
+--------------------
+st is a simple terminal emulator for X which sucks less.
+
+
+Requirements
+------------
+In order to build st you need the Xlib header files.
+
+
+Installation
+------------
+Edit config.mk to match your local setup (st is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install st (if
+necessary as root):
+
+ make clean install
+
+
+Running st
+----------
+If you did not install st with make clean install, you must compile
+the st terminfo entry with the following command:
+
+ tic -sx st.info
+
+See the man page for additional details.
+
+Credits
+-------
+Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
+
diff --git a/st/README.md b/st/README.md
deleted file mode 100644
index a233146..0000000
--- a/st/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# Luke's build of st - the simple (suckless) terminal
-
-The [suckless terminal (st)](https://st.suckless.org/) with some additional
-features that make it literally the best terminal emulator ever:
-
-## Unique features (using dmenu)
-
-+ **follow urls** by pressing `alt-l`
-+ **copy urls** in the same way with `alt-y`
-+ **copy the output of commands** with `alt-o`
-
-## Bindings for
-
-+ **scrollback** with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the
- mouse.
-+ OR **vim-bindings**: scroll up/down in history with `alt-k` and `alt-j`.
- Faster with `alt-u`/`alt-d`.
-+ **zoom/change font size**: same bindings as above, but holding down shift as
- well. `alt-home` returns to default
-+ **copy text** with `alt-c`, **paste** is `alt-v` or `shift-insert`
-
-## Pretty stuff
-
-+ Compatibility with `Xresources` and `pywal` for dynamic colors.
-+ Default [gruvbox](https://github.com/morhetz/gruvbox) colors otherwise.
-+ Transparency/alpha, which is also adjustable from your `Xresources`.
-+ Default font is system "mono" at 14pt, meaning the font will match your
- system font.
-
-## Other st patches
-
-+ Boxdraw
-+ Ligatures
-+ font2
-+ updated to latest version 0.8.5
-
-## Installation for newbs
-
-You should have xlib header files and libharfbuzz build files installed.
-
-```
-git clone https://github.com/LukeSmithxyz/st
-cd st
-sudo make install
-```
-
-Obviously, `make` is required to build. `fontconfig` is required for the
-default build, since it asks `fontconfig` for your system monospace font. It
-might be obvious, but `libX11` and `libXft` are required as well. Chances are,
-you have all of this installed already.
-
-On OpenBSD, be sure to edit `config.mk` first and remove `-lrt` from the
-`$LIBS` before compiling.
-
-Be sure to have a composite manager (`xcompmgr`, `picom`, etc.) running if you
-want transparency.
-
-## How to configure dynamically with Xresources
-
-For many key variables, this build of `st` will look for X settings set in
-either `~/.Xdefaults` or `~/.Xresources`. You must run `xrdb` on one of these
-files to load the settings.
-
-For example, you can define your desired fonts, transparency or colors:
-
-```
-*.font: Liberation Mono:pixelsize=12:antialias=true:autohint=true;
-*.alpha: 0.9
-*.color0: #111
-...
-```
-
-The `alpha` value (for transparency) goes from `0` (transparent) to `1`
-(opaque). There is an example `Xdefaults` file in this respository.
-
-### Colors
-
-To be clear about the color settings:
-
-- This build will use gruvbox colors by default and as a fallback.
-- If there are Xresources colors defined, those will take priority.
-- But if `wal` has run in your session, its colors will take priority.
-
-Note that when you run `wal`, it will negate the transparency of existing windows, but new windows will continue with the previously defined transparency.
-
-## Contact
-
-- Luke Smith <luke@lukesmith.xyz>
-- [https://lukesmith.xyz](https://lukesmith.xyz)
diff --git a/st/TODO b/st/TODO
new file mode 100644
index 0000000..5f74cd5
--- /dev/null
+++ b/st/TODO
@@ -0,0 +1,28 @@
+vt emulation
+------------
+
+* double-height support
+
+code & interface
+----------------
+
+* add a simple way to do multiplexing
+
+drawing
+-------
+* add diacritics support to xdraws()
+ * switch to a suckless font drawing library
+* make the font cache simpler
+* add better support for brightening of the upper colors
+
+bugs
+----
+
+* fix shift up/down (shift selection in emacs)
+* remove DEC test sequence when appropriate
+
+misc
+----
+
+ $ grep -nE 'XXX|TODO' st.c
+
diff --git a/st/Xdefaults b/st/Xdefaults
deleted file mode 100644
index 69ec5d7..0000000
--- a/st/Xdefaults
+++ /dev/null
@@ -1,128 +0,0 @@
-!! Transparency (0-1):
-st.alpha: 0.8
-st.alphaOffset: 0.05
-
-!! Set a default font and font size as below:
-st.font: Monospace-11;
-
-! st.termname: st-256color
-! st.borderpx: 2
-
-!! Set the background, foreground and cursor colors as below:
-
-!! gruvbox:
-*.color0: #282828
-*.color1: #cc241d
-*.color2: #98971a
-*.color3: #d79921
-*.color4: #458588
-*.color5: #b16286
-*.color6: #689d6a
-*.color7: #a89984
-*.color8: #928374
-*.color9: #fb4934
-*.color10: #b8bb26
-*.color11: #fabd2f
-*.color12: #83a598
-*.color13: #d3869b
-*.color14: #8ec07c
-*.color15: #ebdbb2
-*.background: #282828
-*.foreground: #ebdbb2
-*.cursorColor: #add8e6
-
-/* /1* !! gruvbox light: *1/ */
-/* *.color0: #fbf1c7 */
-/* *.color1: #cc241d */
-/* *.color2: #98971a */
-/* *.color3: #d79921 */
-/* *.color4: #458588 */
-/* *.color5: #b16286 */
-/* *.color6: #689d6a */
-/* *.color7: #7c6f64 */
-/* *.color8: #928374 */
-/* *.color9: #9d0006 */
-/* *.color10: #79740e */
-/* *.color11: #b57614 */
-/* *.color12: #076678 */
-/* *.color13: #8f3f71 */
-/* *.color14: #427b58 */
-/* *.color15: #3c3836 */
-/* *.background: #fbf1c7 */
-/* *.foreground: #282828 */
-/* *.cursorColor: #282828 */
-
-/* !! brogrammer: */
-/* *.foreground: #d6dbe5 */
-/* *.background: #131313 */
-/* *.color0: #1f1f1f */
-/* *.color8: #d6dbe5 */
-/* *.color1: #f81118 */
-/* *.color9: #de352e */
-/* *.color2: #2dc55e */
-/* *.color10: #1dd361 */
-/* *.color3: #ecba0f */
-/* *.color11: #f3bd09 */
-/* *.color4: #2a84d2 */
-/* *.color12: #1081d6 */
-/* *.color5: #4e5ab7 */
-/* *.color13: #5350b9 */
-/* *.color6: #1081d6 */
-/* *.color14: #0f7ddb */
-/* *.color7: #d6dbe5 */
-/* *.color15: #ffffff */
-/* *.colorBD: #d6dbe5 */
-
-/* ! base16 */
-/* *.color0: #181818 */
-/* *.color1: #ab4642 */
-/* *.color2: #a1b56c */
-/* *.color3: #f7ca88 */
-/* *.color4: #7cafc2 */
-/* *.color5: #ba8baf */
-/* *.color6: #86c1b9 */
-/* *.color7: #d8d8d8 */
-/* *.color8: #585858 */
-/* *.color9: #ab4642 */
-/* *.color10: #a1b56c */
-/* *.color11: #f7ca88 */
-/* *.color12: #7cafc2 */
-/* *.color13: #ba8baf */
-/* *.color14: #86c1b9 */
-/* *.color15: #f8f8f8 */
-
-/* !! solarized */
-/* *.color0: #073642 */
-/* *.color1: #dc322f */
-/* *.color2: #859900 */
-/* *.color3: #b58900 */
-/* *.color4: #268bd2 */
-/* *.color5: #d33682 */
-/* *.color6: #2aa198 */
-/* *.color7: #eee8d5 */
-/* *.color9: #cb4b16 */
-/* *.color8: #fdf6e3 */
-/* *.color10: #586e75 */
-/* *.color11: #657b83 */
-/* *.color12: #839496 */
-/* *.color13: #6c71c4 */
-/* *.color14: #93a1a1 */
-/* *.color15: #fdf6e3 */
-
-/* !! xterm */
-/* *.color0: #000000 */
-/* *.color1: #cd0000 */
-/* *.color2: #00cd00 */
-/* *.color3: #cdcd00 */
-/* *.color4: #0000cd */
-/* *.color5: #cd00cd */
-/* *.color6: #00cdcd */
-/* *.color7: #e5e5e5 */
-/* *.color8: #4d4d4d */
-/* *.color9: #ff0000 */
-/* *.color10: #00ff00 */
-/* *.color11: #ffff00 */
-/* *.color12: #0000ff */
-/* *.color13: #ff00ff */
-/* *.color14: #00ffff */
-/* *.color15: #aabac8 */
diff --git a/st/autocomplete.h b/st/autocomplete.h
new file mode 100644
index 0000000..fc88447
--- /dev/null
+++ b/st/autocomplete.h
@@ -0,0 +1,16 @@
+# ifndef __ST_AUTOCOMPLETE_H
+# define __ST_AUTOCOMPLETE_H
+
+enum {
+ ACMPL_DEACTIVATE,
+ ACMPL_WORD,
+ ACMPL_WWORD,
+ ACMPL_FUZZY_WORD,
+ ACMPL_FUZZY_WWORD,
+ ACMPL_FUZZY,
+ ACMPL_SUFFIX,
+ ACMPL_SURROUND,
+ ACMPL_UNDO,
+};
+
+# endif // __ST_AUTOCOMPLETE_H
diff --git a/st/config.def.h b/st/config.def.h
index 453a78b..8edba7e 100644
--- a/st/config.def.h
+++ b/st/config.def.h
@@ -1,3 +1,4 @@
+char *externalpipe_sigusr1[] = {"/bin/sh", "-c", "externalpipe_buffer.sh st_strings_read"};
/* See LICENSE file for copyright and license details. */
/*
@@ -5,15 +6,22 @@
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
+static size_t currentfont = 0;
static char *fonts[] = {
- "monospace:pixelsize=16:antialias=true:autohint=true",
+ "monospace:pixelsize=16:antialias=true:autohint=true",
"nerdmono:pixelsize=16:antialias=true:autohint=true",
"ko:pixelsize=16:antialias=true:autohint=true",
};
-static size_t currentfont = 0;
+/* Spare fonts */
static char *font2[] = {
- "NotoColorEmoji:pixelsize=14:antialias=true:autohint=true",
+ "NotoColorEmoji:pixelsize=14:antialias=true:autohint=true",
};
+
+/* disable bold, italic and roman fonts globally */
+int disablebold = 0;
+int disableitalic = 0;
+int disableroman = 0;
+
static int borderpx = 2;
/*
@@ -36,7 +44,6 @@ char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
-
/* Character rendering offsets in pixels */
static short cxoffset = 0;
static short cyoffset = 0;
@@ -118,13 +125,14 @@ char *termname = "st-256color";
unsigned int tabspaces = 8;
/* bg opacity */
-float alpha = 0.8;
+float alpha = 0.8, alphaUnfocused = 0.85;
+
+/* Background opacity */
float alpha_def;
-float alphaOffset = 0.05;
-float alphaUnfocus;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
+ /* 8 normal colors */
"#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
"#cc241d",
"#839E45",
@@ -133,6 +141,8 @@ static const char *colorname[] = {
"#b16286",
"#689d6a",
"#a89984",
+
+ /* 8 bright colors */
"#928374",
"#fb4934",
"#b8bb26",
@@ -141,14 +151,19 @@ static const char *colorname[] = {
"#d3869b",
"#8ec07c",
"#ebdbb2",
- [255] = 0,
- /* more colors can be added after 255 to use with DefaultXX */
+
+ [255] = 0,
+
+ /* more colors can be added after 255 to use with DefaultXX */
"#add8e6", /* 256 -> cursor */
"#555555", /* 257 -> rev cursor*/
"#282828", /* 258 -> bg */
"#ebdbb2", /* 259 -> fg */
+ "#1d2021", /* 260 */
+ "#32302f", /* 261 */
};
+
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
@@ -156,8 +171,50 @@ static const char *colorname[] = {
unsigned int defaultfg = 259;
unsigned int defaultbg = 258;
unsigned int defaultcs = 256;
-unsigned int defaultrcs = 257;
-unsigned int background = 258;
+static unsigned int defaultrcs = 257;
+unsigned int bg = 258, bgUnfocused = 261;
+
+/*
+ * Xresources preferences to load at startup
+ */
+ResourcePref resources[] = {
+ { "fonts", STRING, &fonts },
+ { "font2", STRING, &font2 },
+ { "color0", STRING, &colorname[0] },
+ { "color1", STRING, &colorname[1] },
+ { "color2", STRING, &colorname[2] },
+ { "color3", STRING, &colorname[3] },
+ { "color4", STRING, &colorname[4] },
+ { "color5", STRING, &colorname[5] },
+ { "color6", STRING, &colorname[6] },
+ { "color7", STRING, &colorname[7] },
+ { "color8", STRING, &colorname[8] },
+ { "color9", STRING, &colorname[9] },
+ { "color10", STRING, &colorname[10] },
+ { "color11", STRING, &colorname[11] },
+ { "color12", STRING, &colorname[12] },
+ { "color13", STRING, &colorname[13] },
+ { "color14", STRING, &colorname[14] },
+ { "color15", STRING, &colorname[15] },
+ { "background", STRING, &colorname[256] },
+ { "foreground", STRING, &colorname[257] },
+ { "cursorColor", STRING, &colorname[258] },
+ { "termname", STRING, &termname },
+ { "shell", STRING, &shell },
+ { "minlatency", INTEGER, &minlatency },
+ { "maxlatency", INTEGER, &maxlatency },
+ { "blinktimeout", INTEGER, &blinktimeout },
+ { "bellvolume", INTEGER, &bellvolume },
+ { "tabspaces", INTEGER, &tabspaces },
+ { "borderpx", INTEGER, &borderpx },
+ { "cwscale", FLOAT, &cwscale },
+ { "chscale", FLOAT, &chscale },
+};
+
+/*
+ * Command used to query unicode glyphs.
+ */
+char *iso14755_cmd = "dmenu -i -w \"$WINDOWID\" -p codepoint: </dev/null";
/*
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
@@ -176,6 +233,12 @@ static unsigned int cursorstyle = 1;
static Rune stcursor = 0x2603; /* snowman ("☃") */
/*
+ * Whether to use pixel geometry or cell geometry
+ */
+
+static Geometry geometry = CellGeometry;
+
+/*
* Default columns and rows numbers
*/
@@ -183,6 +246,13 @@ static unsigned int cols = 80;
static unsigned int rows = 24;
/*
+ * Default width and height (including borders!)
+ */
+
+static unsigned int width = 564;
+static unsigned int height = 364;
+
+/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
@@ -202,120 +272,104 @@ static unsigned int defaultattr = 11;
*/
static uint forcemousemod = ShiftMask;
-/*
- * Xresources preferences to load at startup
- */
-ResourcePref resources[] = {
- { "fonts", STRING, &fonts },
- { "fontalt0", STRING, &font2[0] },
- { "color0", STRING, &colorname[0] },
- { "color1", STRING, &colorname[1] },
- { "color2", STRING, &colorname[2] },
- { "color3", STRING, &colorname[3] },
- { "color4", STRING, &colorname[4] },
- { "color5", STRING, &colorname[5] },
- { "color6", STRING, &colorname[6] },
- { "color7", STRING, &colorname[7] },
- { "color8", STRING, &colorname[8] },
- { "color9", STRING, &colorname[9] },
- { "color10", STRING, &colorname[10] },
- { "color11", STRING, &colorname[11] },
- { "color12", STRING, &colorname[12] },
- { "color13", STRING, &colorname[13] },
- { "color14", STRING, &colorname[14] },
- { "color15", STRING, &colorname[15] },
- { "background", STRING, &colorname[258] },
- { "foreground", STRING, &colorname[259] },
- { "cursorColor", STRING, &colorname[256] },
- { "termname", STRING, &termname },
- { "shell", STRING, &shell },
- { "minlatency", INTEGER, &minlatency },
- { "maxlatency", INTEGER, &maxlatency },
- { "blinktimeout", INTEGER, &blinktimeout },
- { "bellvolume", INTEGER, &bellvolume },
- { "tabspaces", INTEGER, &tabspaces },
- { "borderpx", INTEGER, &borderpx },
- { "cwscale", FLOAT, &cwscale },
- { "chscale", FLOAT, &chscale },
- { "alpha", FLOAT, &alpha },
- { "alphaOffset", FLOAT, &alphaOffset },
-};
+#include "autocomplete.h"
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
+const unsigned int mousescrollincrement = 1;
static MouseShortcut mshortcuts[] = {
- /* mask button function argument release */
- { XK_NO_MOD, Button4, kscrollup, { .i = 1 } },
- { XK_NO_MOD, Button5, kscrolldown, { .i = 1 } },
- { XK_ANY_MOD, Button2, selpaste, { .i = 0 }, 1 },
- { ShiftMask, Button4, ttysend, { .s = "\033[5;2~" } },
- { XK_ANY_MOD, Button4, ttysend, { .s = "\031" } },
- { ShiftMask, Button5, ttysend, { .s = "\033[6;2~" } },
- { XK_ANY_MOD, Button5, ttysend, { .s = "\005" } },
+ /* mask button function argument release */
+ { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement} },
+ { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement} },
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+ { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};
/* Internal keyboard shortcuts. */
-#define MODKEY Mod1Mask
-#define MODKEY2 Mod4Mask
-#define TERMMOD (MODKEY | ShiftMask)
-#define TERMMOD2 (MODKEY | ControlMask)
+#define ALTKEY Mod1Mask
+#define ALTCTRL (Mod1Mask|ControlMask)
+#define ALTSHIFT (Mod1Mask|ShiftMask)
+#define ALTULTRA (Mod1Mask|ControlMask|ShiftMask)
+#define WINKEY Mod4Mask
+#define WINCTRL (Mod4Mask|ControlMask)
+#define WISHIFT (Mod4Mask|ShiftMask)
+#define WINULTRA (Mod$Mask|ControlMask|ShiftMask)
+#define EXTRAMOD (ControlMask|ShiftMask)
static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -o", "externalpipe", NULL };
static char *copyurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -c", "externalpipe", NULL };
static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL };
static Shortcut shortcuts[] = {
- /* mask keysym function argument */
+ /* mask keysym function argument */
// APPEAREANCES
- { MODKEY, XK_a, changealpha, { .f = +0.05 } },
- { MODKEY, XK_s, changealpha, { .f = -0.05 } },
- { MODKEY, XK_equal, changealpha, { .f = 0 } },
- { TERMMOD, XK_Down, zoom, { .f = -1 } },
- { TERMMOD, XK_Up, zoom, { .f = +1 } },
- { TERMMOD, XK_Next, zoom, { .f = -1 } },
- { TERMMOD, XK_Prior, zoom, { .f = +1 } },
- { TERMMOD, XK_J, zoom, { .f = -1 } },
- { TERMMOD, XK_K, zoom, { .f = +1 } },
- { TERMMOD, XK_D, zoom, { .f = -5 } },
- { TERMMOD, XK_U, zoom, { .f = +5 } },
- { TERMMOD, XK_plus, zoomreset, { .f = 0 } },
+ { ALTKEY, XK_a, chgalpha, {.f = +0.05} }, /* Decrease opacity */
+ { ALTKEY, XK_s, chgalpha, {.f = -0.05} }, /* Increase opacity */
+ { ALTKEY, XK_equal, chgalpha, {.f = 0} }, /* Reset opacity */
+ { ALTSHIFT, XK_J, zoom, {.f = -1} },
+ { ALTSHIFT, XK_K, zoom, {.f = +1} },
+ { ALTSHIFT, XK_plus, zoomreset, {.f = 0} },
+ { ALTSHIFT, XK_Next, zoom, {.f = -1} },
+ { ALTSHIFT, XK_Prior, zoom, {.f = +1} },
+ { ALTSHIFT, XK_Home, zoomreset, {.f = 0} },
+ { ALTKEY, XK_f, fullscreen, {.i = 0} },
+ { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} },
+
+ // AUTOCOMPLETE
+ { ALTCTRL, XK_slash, autocomplete, {.i = ACMPL_WORD } },
+ { ALTCTRL, XK_period, autocomplete, {.i = ACMPL_FUZZY_WORD } },
+ { ALTCTRL, XK_comma, autocomplete, {.i = ACMPL_FUZZY } },
+ { ALTCTRL, XK_apostrophe, autocomplete, {.i = ACMPL_SUFFIX } },
+ { ALTCTRL, XK_semicolon, autocomplete, {.i = ACMPL_SURROUND } },
+ { ALTCTRL, XK_bracketright,autocomplete, {.i = ACMPL_WWORD } },
+ { ALTCTRL, XK_bracketleft, autocomplete, {.i = ACMPL_FUZZY_WWORD } },
+ { ALTCTRL, XK_equal, autocomplete, {.i = ACMPL_UNDO } },
// COPIES
- { MODKEY, XK_c, clipcopy, { .i = 0 } },
- { TERMMOD, XK_C, externalpipe, { .v = copyurlcmd } },
- { MODKEY, XK_o, externalpipe, { .v = copyoutput } },
+ { ALTKEY, XK_c, clipcopy, {.i = 0} },
+ { ALTSHIFT, XK_C, externalpipe, {.v = copyurlcmd } },
+ { ALTKEY, XK_o, externalpipe, {.v = copyoutput } },
+ { ALTSHIFT, XK_L, copyurl, {.i = 0} },
+ { ALTKEY, XK_l, copyurl, {.i = 1} },
// FONTS
- { TERMMOD, XK_I, cyclefonts, {} },
+ { ALTSHIFT, XK_F, cyclefonts, {} },
// PASTES
- { MODKEY, XK_v, clippaste, { .i = 0 } },
- { ShiftMask, XK_Insert, clippaste, { .i = 0 } },
- { ShiftMask, XK_Insert, selpaste, { .i = 0 } },
- { TERMMOD, XK_V, externalpipe, { .v = openurlcmd } },
+ { ALTKEY, XK_v, clippaste, {.i = 0} },
+ { ALTSHIFT, XK_V, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { ALTCTRL, XK_v, opencopied, {.v = "xdg-open"} },
+ { ALTKEY, XK_o, externalpipe, {.v = openurlcmd } },
// PRINTERS
- { MODKEY, XK_Print, printsel, { .i = 0 } },
- { TERMMOD, XK_Print, printscreen, { .i = 0 } },
- { TERMMOD2, XK_Print, toggleprinter, { .i = 0 } },
+ { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
+ { ShiftMask, XK_Print, printscreen, {.i = 0} },
+ { ControlMask, XK_Print, toggleprinter, {.i = 0} },
+
+ // TERMINAL
+ { ALTKEY, XK_Return, newterm, {.i = 0} },
// TRAVERSALS
- { MODKEY, XK_y, kscrollup, { .i = 1 } },
- { MODKEY, XK_e, kscrolldown, { .i = 1 } },
- { MODKEY, XK_u, kscrollup, { .i = -1 } },
- { MODKEY, XK_d, kscrolldown, { .i = -1 } },
- { MODKEY, XK_Up, kscrollup, { .i = 1 } },
- { MODKEY, XK_Down, kscrolldown, { .i = 1 } },
- { MODKEY, XK_Page_Up, kscrollup, { .i = -1 } },
- { MODKEY, XK_Page_Down, kscrolldown, { .i = -1 } },
- { ShiftMask, XK_Page_Up, kscrollup, { .i = -1 } },
- { ShiftMask, XK_Page_Down, kscrolldown, { .i = -1 } },
+ { ALTKEY, XK_y, kscrollup, {.i = 1} },
+ { ALTKEY, XK_e, kscrolldown, {.i = 1} },
+ { ALTSHIFT, XK_u, kscrollup, {.i = -1} },
+ { ALTSHIFT, XK_d, kscrolldown, {.i = -1} },
+ { ALTKEY, XK_Page_Up, kscrollup, {.i = 1} },
+ { ALTKEY, XK_Page_Down, kscrolldown, {.i = 1} },
+ { ALTSHIFT, XK_Page_Up, kscrollup, {.i = -1} },
+ { ALTSHIFT, XK_Page_Down, kscrolldown, {.i = -1} },
// EXTRAS
- { TERMMOD, XK_Num_Lock, numlock, { .i = 0 } },
- { XK_ANY_MOD, XK_Break, sendbreak, { .i = 0 } },
+ { EXTRAMOD, XK_I, iso14755, {.i = 0} },
+ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
+ { EXTRAMOD, XK_Escape, keyboard_select,{.i = 0} },
+ { EXTRAMOD, XK_Num_Lock, numlock, {.i = 0} },
};
/*
@@ -422,741 +476,741 @@ static KeySym mappedkeys[] = {
* State bits to ignore when matching key or button events. By default,
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
-static uint ignoremod = Mod2Mask | XK_SWITCH_MOD;
+static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
- /* keysym mask string appkey appcursor */
- { XK_KP_Home, ShiftMask, "\033[2J", 0, -1 },
- { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1 },
- { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0 },
- { XK_KP_End, ControlMask, "\033[J", -1, 0 },
- { XK_KP_End, ControlMask, "\033[1;5F", +1, 0 },
- { XK_KP_End, ShiftMask, "\033[K", -1, 0 },
- { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0 },
- { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0 },
- { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0 },
- { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0 },
- { XK_KP_Insert, ControlMask, "\033[L", -1, 0 },
- { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0 },
- { XK_KP_Delete, ControlMask, "\033[M", -1, 0 },
- { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0 },
- { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0 },
- { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0 },
- { XK_Up, ShiftMask, "\033[1;2A", 0, 0 },
- { XK_Up, MODKEY, "\033[1;3A", 0, 0 },
- { XK_Up, ShiftMask | MODKEY, "\033[1;4A", 0, 0 },
- { XK_Up, ControlMask, "\033[1;5A", 0, 0 },
- { XK_Up, ShiftMask | ControlMask, "\033[1;6A", 0, 0 },
- { XK_Up, ControlMask | MODKEY, "\033[1;7A", 0, 0 },
- { XK_Up, ShiftMask | ControlMask | MODKEY, "\033[1;8A", 0, 0 },
- { XK_Up, XK_ANY_MOD, "\033[A", 0, -1 },
- { XK_Up, XK_ANY_MOD, "\033OA", 0, +1 },
- { XK_Down, ShiftMask, "\033[1;2B", 0, 0 },
- { XK_Down, MODKEY, "\033[1;3B", 0, 0 },
- { XK_Down, ShiftMask | MODKEY, "\033[1;4B", 0, 0 },
- { XK_Down, ControlMask, "\033[1;5B", 0, 0 },
- { XK_Down, ShiftMask | ControlMask, "\033[1;6B", 0, 0 },
- { XK_Down, ControlMask | MODKEY, "\033[1;7B", 0, 0 },
- { XK_Down, ShiftMask | ControlMask | MODKEY, "\033[1;8B", 0, 0 },
- { XK_Down, XK_ANY_MOD, "\033[B", 0, -1 },
- { XK_Down, XK_ANY_MOD, "\033OB", 0, +1 },
- { XK_Left, ShiftMask, "\033[1;2D", 0, 0 },
- { XK_Left, MODKEY, "\033[1;3D", 0, 0 },
- { XK_Left, ShiftMask | MODKEY, "\033[1;4D", 0, 0 },
- { XK_Left, ControlMask, "\033[1;5D", 0, 0 },
- { XK_Left, ShiftMask | ControlMask, "\033[1;6D", 0, 0 },
- { XK_Left, ControlMask | MODKEY, "\033[1;7D", 0, 0 },
- { XK_Left, ShiftMask | ControlMask | MODKEY, "\033[1;8D", 0, 0 },
- { XK_Left, XK_ANY_MOD, "\033[D", 0, -1 },
- { XK_Left, XK_ANY_MOD, "\033OD", 0, +1 },
- { XK_Right, ShiftMask, "\033[1;2C", 0, 0 },
- { XK_Right, MODKEY, "\033[1;3C", 0, 0 },
- { XK_Right, ShiftMask | MODKEY, "\033[1;4C", 0, 0 },
- { XK_Right, ControlMask, "\033[1;5C", 0, 0 },
- { XK_Right, ShiftMask | ControlMask, "\033[1;6C", 0, 0 },
- { XK_Right, ControlMask | MODKEY, "\033[1;7C", 0, 0 },
- { XK_Right, ShiftMask | ControlMask | MODKEY, "\033[1;8C", 0, 0 },
- { XK_Right, XK_ANY_MOD, "\033[C", 0, -1 },
- { XK_Right, XK_ANY_MOD, "\033OC", 0, +1 },
- { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0 },
- { XK_Return, MODKEY, "\033\r", 0, 0 },
- { XK_Return, XK_NO_MOD, "\r", 0, 0 },
- { XK_Insert, ShiftMask, "\033[4l", -1, 0 },
- { XK_Insert, ShiftMask, "\033[2;2~", +1, 0 },
- { XK_Insert, ControlMask, "\033[L", -1, 0 },
- { XK_Insert, ControlMask, "\033[2;5~", +1, 0 },
- { XK_Delete, ControlMask, "\033[M", -1, 0 },
- { XK_Delete, ControlMask, "\033[3;5~", +1, 0 },
- { XK_Delete, ShiftMask, "\033[2K", -1, 0 },
- { XK_Delete, ShiftMask, "\033[3;2~", +1, 0 },
- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0 },
- { XK_BackSpace, MODKEY, "\033\177", 0, 0 },
- { XK_Home, ShiftMask, "\033[2J", 0, -1 },
- { XK_Home, ShiftMask, "\033[1;2H", 0, +1 },
- { XK_End, ControlMask, "\033[J", -1, 0 },
- { XK_End, ControlMask, "\033[1;5F", +1, 0 },
- { XK_End, ShiftMask, "\033[K", -1, 0 },
- { XK_End, ShiftMask, "\033[1;2F", +1, 0 },
- { XK_Prior, ControlMask, "\033[5;5~", 0, 0 },
- { XK_Prior, ShiftMask, "\033[5;2~", 0, 0 },
- { XK_Next, ControlMask, "\033[6;5~", 0, 0 },
- { XK_Next, ShiftMask, "\033[6;2~", 0, 0 },
- { XK_F1, XK_NO_MOD, "\033OP", 0, 0 },
- { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0 },
- { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0 },
- { XK_F1, /* F37 */ MODKEY2, "\033[1;6P", 0, 0 },
- { XK_F1, /* F49 */ MODKEY, "\033[1;3P", 0, 0 },
- { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0 },
- { XK_F2, XK_NO_MOD, "\033OQ", 0, 0 },
- { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0 },
- { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0 },
- { XK_F2, /* F38 */ MODKEY2, "\033[1;6Q", 0, 0 },
- { XK_F2, /* F50 */ MODKEY, "\033[1;3Q", 0, 0 },
- { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0 },
- { XK_F3, XK_NO_MOD, "\033OR", 0, 0 },
- { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0 },
- { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0 },
- { XK_F3, /* F39 */ MODKEY2, "\033[1;6R", 0, 0 },
- { XK_F3, /* F51 */ MODKEY, "\033[1;3R", 0, 0 },
- { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0 },
- { XK_F4, XK_NO_MOD, "\033OS", 0, 0 },
- { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0 },
- { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0 },
- { XK_F4, /* F40 */ MODKEY2, "\033[1;6S", 0, 0 },
- { XK_F4, /* F52 */ MODKEY, "\033[1;3S", 0, 0 },
- { XK_F5, XK_NO_MOD, "\033[15~", 0, 0 },
- { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0 },
- { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0 },
- { XK_F5, /* F41 */ MODKEY2, "\033[15;6~", 0, 0 },
- { XK_F5, /* F53 */ MODKEY, "\033[15;3~", 0, 0 },
- { XK_F6, XK_NO_MOD, "\033[17~", 0, 0 },
- { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0 },
- { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0 },
- { XK_F6, /* F42 */ MODKEY2, "\033[17;6~", 0, 0 },
- { XK_F6, /* F54 */ MODKEY, "\033[17;3~", 0, 0 },
- { XK_F7, XK_NO_MOD, "\033[18~", 0, 0 },
- { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0 },
- { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0 },
- { XK_F7, /* F43 */ MODKEY2, "\033[18;6~", 0, 0 },
- { XK_F7, /* F55 */ MODKEY, "\033[18;3~", 0, 0 },
- { XK_F8, XK_NO_MOD, "\033[19~", 0, 0 },
- { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0 },
- { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0 },
- { XK_F8, /* F44 */ MODKEY2, "\033[19;6~", 0, 0 },
- { XK_F8, /* F56 */ MODKEY, "\033[19;3~", 0, 0 },
- { XK_F9, XK_NO_MOD, "\033[20~", 0, 0 },
- { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0 },
- { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0 },
- { XK_F9, /* F45 */ MODKEY2, "\033[20;6~", 0, 0 },
- { XK_F9, /* F57 */ MODKEY, "\033[20;3~", 0, 0 },
- { XK_F10, XK_NO_MOD, "\033[21~", 0, 0 },
- { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0 },
- { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0 },
- { XK_F10, /* F46 */ MODKEY2, "\033[21;6~", 0, 0 },
- { XK_F10, /* F58 */ MODKEY, "\033[21;3~", 0, 0 },
- { XK_F11, XK_NO_MOD, "\033[23~", 0, 0 },
- { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0 },
- { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0 },
- { XK_F11, /* F47 */ MODKEY2, "\033[23;6~", 0, 0 },
- { XK_F11, /* F59 */ MODKEY, "\033[23;3~", 0, 0 },
- { XK_F12, XK_NO_MOD, "\033[24~", 0, 0 },
- { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0 },
- { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0 },
- { XK_F12, /* F48 */ MODKEY2, "\033[24;6~", 0, 0 },
- { XK_F12, /* F60 */ MODKEY, "\033[24;3~", 0, 0 },
- { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0 },
- { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0 },
- { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0 },
- { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0 },
- { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0 },
- { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0 },
- { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0 },
- { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0 },
- { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0 },
- { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0 },
- { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0 },
- { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0 },
- { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0 },
- { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0 },
- { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0 },
- { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0 },
- { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0 },
- { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0 },
- { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0 },
- { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0 },
- { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0 },
- { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0 },
- { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0 },
+ /* keysym mask string appkey appcursor */
+ { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_KP_End, ControlMask, "\033[J", -1, 0},
+ { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_KP_End, ShiftMask, "\033[K", -1, 0},
+ { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
+ { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
+ { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
+ { XK_Up, ControlMask, "\033[1;5A", 0, 0},
+ { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
+ { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
+ { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
+ { XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_Down, ShiftMask, "\033[1;2B", 0, 0},
+ { XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
+ { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
+ { XK_Down, ControlMask, "\033[1;5B", 0, 0},
+ { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
+ { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
+ { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
+ { XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_Left, ShiftMask, "\033[1;2D", 0, 0},
+ { XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
+ { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
+ { XK_Left, ControlMask, "\033[1;5D", 0, 0},
+ { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
+ { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
+ { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
+ { XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_Right, ShiftMask, "\033[1;2C", 0, 0},
+ { XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
+ { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
+ { XK_Right, ControlMask, "\033[1;5C", 0, 0},
+ { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
+ { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
+ { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
+ { XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
+ { XK_Return, Mod1Mask, "\033\r", 0, 0},
+ { XK_Return, XK_NO_MOD, "\r", 0, 0},
+ { XK_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { XK_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_End, ControlMask, "\033[J", -1, 0},
+ { XK_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_End, ShiftMask, "\033[K", -1, 0},
+ { XK_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
+ { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_Next, ControlMask, "\033[6;5~", 0, 0},
+ { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
+ { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
+ { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
+ { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
+ { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
+ { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
+ { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
+ { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
+ { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
+ { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
+ { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
+ { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
+ { XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
+ { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
+ { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
+ { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
+ { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
+ { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
+ { XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
+ { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
+ { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
+ { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
+ { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
+ { XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
+ { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
+ { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
+ { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
+ { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
+ { XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
+ { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
+ { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
+ { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
+ { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
+ { XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
+ { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
+ { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
+ { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
+ { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
+ { XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
+ { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
+ { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
+ { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
+ { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
+ { XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
+ { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
+ { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
+ { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
+ { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
+ { XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
+ { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
+ { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
+ { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
+ { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
+ { XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
+ { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
+ { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
+ { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
+ { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
+ { XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
+ { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
+ { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
+ { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
+ { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
+ { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
+ { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
+ { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
+ { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
+ { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
+ { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
+ { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
+ { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
+ { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
+ { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
+ { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
+ { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
+ { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
+ { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
+ { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
+ { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
+ { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
+ { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
+ { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
+ { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
+ { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
+ { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
+ { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
// libtermkey compatible keyboard input
- { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1 },
- { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1 },
- { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0 },
- { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0 },
- { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0 },
- { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0 },
- { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0 },
- { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0 },
- { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0 },
- { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0 },
- { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1 },
- { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1 },
- { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0 },
- { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0 },
- { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0 },
- { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0 },
- { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0 },
- { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0 },
- { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0 },
- { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0 },
- { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1 },
- { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1 },
- { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0 },
- { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0 },
- { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0 },
- { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0 },
- { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0 },
- { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0 },
- { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0 },
- { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0 },
- { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1 },
- { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1 },
- { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0 },
- { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0 },
- { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0 },
- { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0 },
- { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0 },
- { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0 },
- { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0 },
- { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0 },
- { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1 },
- { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1 },
- { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0 },
- { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0 },
- { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0 },
- { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0 },
- { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0 },
- { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0 },
- { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0 },
- { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0 },
- { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0 },
- { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0 },
- { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0 },
- { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0 },
- { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0 },
- { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0 },
- { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0 },
- { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0 },
- { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0 },
- { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0 },
- { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0 },
- { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0 },
- { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0 },
- { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0 },
- { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0 },
- { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0 },
- { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0 },
- { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0 },
- { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0 },
- { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0 },
- { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0 },
- { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0 },
- { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0 },
- { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0 },
- { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0 },
- { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0 },
- { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0 },
- { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0 },
- { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0 },
- { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0 },
- { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0 },
- { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0 },
- { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0 },
- { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0 },
- { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0 },
- { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0 },
- { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0 },
- { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0 },
- { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0 },
- { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0 },
- { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0 },
- { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0 },
- { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0 },
- { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0 },
- { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0 },
- { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0 },
- { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0 },
- { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0 },
- { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0 },
- { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0 },
- { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0 },
- { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0 },
- { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0 },
- { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0 },
- { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0 },
- { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0 },
- { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0 },
- { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0 },
- { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0 },
- { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0 },
- { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0 },
- { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0 },
- { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0 },
- { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0 },
- { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0 },
- { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0 },
- { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0 },
- { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0 },
- { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0 },
- { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0 },
- { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0 },
- { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0 },
- { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0 },
- { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0 },
- { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0 },
- { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0 },
- { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0 },
- { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0 },
- { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0 },
- { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0 },
- { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0 },
- { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0 },
- { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0 },
- { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0 },
- { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0 },
- { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0 },
- { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0 },
- { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0 },
- { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0 },
- { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0 },
- { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0 },
- { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0 },
- { XK_KP_0, ControlMask, "\033[176;5u", 0, 0 },
- { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0 },
- { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0 },
- { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0 },
- { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0 },
- { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0 },
- { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0 },
- { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0 },
- { XK_KP_0, ControlMask, "\033[177;5u", 0, 0 },
- { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0 },
- { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0 },
- { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0 },
- { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0 },
- { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0 },
- { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0 },
- { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0 },
- { XK_KP_2, ControlMask, "\033[178;5u", 0, 0 },
- { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0 },
- { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0 },
- { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0 },
- { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0 },
- { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0 },
- { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0 },
- { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0 },
- { XK_KP_3, ControlMask, "\033[179;5u", 0, 0 },
- { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0 },
- { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0 },
- { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0 },
- { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0 },
- { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0 },
- { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0 },
- { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0 },
- { XK_KP_4, ControlMask, "\033[180;5u", 0, 0 },
- { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0 },
- { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0 },
- { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0 },
- { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0 },
- { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0 },
- { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0 },
- { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0 },
- { XK_KP_5, ControlMask, "\033[181;5u", 0, 0 },
- { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0 },
- { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0 },
- { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0 },
- { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0 },
- { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0 },
- { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0 },
- { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0 },
- { XK_KP_6, ControlMask, "\033[182;5u", 0, 0 },
- { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0 },
- { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0 },
- { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0 },
- { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0 },
- { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0 },
- { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0 },
- { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0 },
- { XK_KP_7, ControlMask, "\033[183;5u", 0, 0 },
- { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0 },
- { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0 },
- { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0 },
- { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0 },
- { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0 },
- { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0 },
- { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0 },
- { XK_KP_8, ControlMask, "\033[184;5u", 0, 0 },
- { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0 },
- { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0 },
- { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0 },
- { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0 },
- { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0 },
- { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0 },
- { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0 },
- { XK_KP_9, ControlMask, "\033[185;5u", 0, 0 },
- { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0 },
- { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0 },
- { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0 },
- { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0 },
- { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0 },
- { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0 },
- { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0 },
- { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0 },
- { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0 },
- { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0 },
- { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0 },
- { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0 },
- { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0 },
- { XK_Tab, ControlMask, "\033[9;5u", 0, 0 },
- { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0 },
- { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0 },
- { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0 },
- { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0 },
- { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0 },
- { XK_Return, ControlMask, "\033[13;5u", 0, 0 },
- { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0 },
- { XK_Return, Mod1Mask, "\033[13;3u", 0, 0 },
- { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0 },
- { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0 },
- { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0 },
- { XK_Return, ShiftMask, "\033[13;2u", 0, 0 },
- { XK_Pause, ControlMask, "\033[18;5u", 0, 0 },
- { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0 },
- { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0 },
- { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0 },
- { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0 },
- { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0 },
- { XK_Pause, ShiftMask, "\033[18;2u", 0, 0 },
- { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0 },
- { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0 },
- { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0 },
- { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0 },
- { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0 },
- { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0 },
- { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0 },
- { XK_Escape, ControlMask, "\033[27;5u", 0, 0 },
- { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0 },
- { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0 },
- { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0 },
- { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0 },
- { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0 },
- { XK_Escape, ShiftMask, "\033[27;2u", 0, 0 },
- { XK_Home, XK_NO_MOD, "\033[H", 0, -1 },
- { XK_Home, XK_NO_MOD, "\033[1~", 0, +1 },
- { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0 },
- { XK_Home, Mod1Mask, "\033[80;3u", 0, 0 },
- { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0 },
- { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0 },
- { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0 },
- { XK_End, XK_NO_MOD, "\033[4~", 0, 0 },
- { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0 },
- { XK_End, Mod1Mask, "\033[87;3u", 0, 0 },
- { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0 },
- { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0 },
- { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0 },
- { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0 },
- { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0 },
- { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0 },
- { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0 },
- { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0 },
- { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0 },
- { XK_Next, XK_NO_MOD, "\033[6~", 0, 0 },
- { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0 },
- { XK_Next, Mod1Mask, "\033[86;3u", 0, 0 },
- { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0 },
- { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0 },
- { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0 },
- { XK_Print, ControlMask, "\033[97;5u", 0, 0 },
- { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0 },
- { XK_Print, Mod1Mask, "\033[97;3u", 0, 0 },
- { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0 },
- { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0 },
- { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0 },
- { XK_Print, ShiftMask, "\033[97;2u", 0, 0 },
- { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0 },
- { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0 },
- { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0 },
- { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0 },
- { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0 },
- { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0 },
- { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0 },
- { XK_Menu, ControlMask, "\033[103;5u", 0, 0 },
- { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0 },
- { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0 },
- { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0 },
- { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0 },
- { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0 },
- { XK_Menu, ShiftMask, "\033[103;2u", 0, 0 },
- { XK_Delete, XK_NO_MOD, "\033[P", -1, 0 },
- { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0 },
- { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0 },
- { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0 },
- { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0 },
- { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0 },
- { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0 },
- { XK_i, ControlMask, "\033[105;5u", 0, 0 },
- { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0 },
- /* { XK_m, ControlMask, "\033[109;5u", 0, 0 }, */
- { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0 },
- { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0 },
- /* { XK_space, Mod1Mask, "\033[32;3u", 0, 0 }, */
- { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0 },
- { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0 },
- { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0 },
- { XK_space, ShiftMask, "\033[32;2u", 0, 0 },
- { XK_0, ControlMask, "\033[48;5u", 0, 0 },
- { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0 },
- { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0 },
- { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0 },
- { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0 },
- { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0 },
- { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0 },
- { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0 },
- { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0 },
- { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0 },
- { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0 },
- { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0 },
- { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0 },
- { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0 },
- { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0 },
- { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0 },
- { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0 },
- { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0 },
- { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0 },
- { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0 },
- { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0 },
- { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0 },
- { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0 },
- { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0 },
- { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0 },
- { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0 },
- { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0 },
- { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0 },
- { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0 },
- { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0 },
- { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0 },
- { XK_1, ControlMask, "\033[49;5u", 0, 0 },
- { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0 },
- { XK_2, ControlMask, "\033[50;5u", 0, 0 },
- { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0 },
- { XK_3, ControlMask, "\033[51;5u", 0, 0 },
- { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0 },
- { XK_4, ControlMask, "\033[52;5u", 0, 0 },
- { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0 },
- { XK_5, ControlMask, "\033[53;5u", 0, 0 },
- { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0 },
- { XK_6, ControlMask, "\033[54;5u", 0, 0 },
- { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0 },
- { XK_7, ControlMask, "\033[55;5u", 0, 0 },
- { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0 },
- { XK_8, ControlMask, "\033[56;5u", 0, 0 },
- { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0 },
- { XK_9, ControlMask, "\033[57;5u", 0, 0 },
- { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0 },
- { XK_ampersand, ControlMask, "\033[38;5u", 0, 0 },
- { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0 },
- { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0 },
- { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0 },
- { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0 },
- { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0 },
- { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0 },
- { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0 },
- { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0 },
- { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0 },
- { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0 },
- { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0 },
- { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0 },
- { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0 },
- { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0 },
- { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0 },
- { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0 },
- { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0 },
- { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0 },
- { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0 },
- { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0 },
- { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0 },
- { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0 },
- { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0 },
- { XK_asterisk, ControlMask, "\033[42;5u", 0, 0 },
- { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0 },
- { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0 },
- { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0 },
- { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0 },
- { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0 },
- { XK_at, ControlMask, "\033[64;5u", 0, 0 },
- { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0 },
- { XK_at, Mod1Mask, "\033[64;3u", 0, 0 },
- { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0 },
- { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0 },
- { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0 },
- { XK_backslash, ControlMask, "\033[92;5u", 0, 0 },
- { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0 },
- { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0 },
- { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0 },
- { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0 },
- { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0 },
- { XK_bar, ControlMask, "\033[124;5u", 0, 0 },
- { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0 },
- { XK_bar, Mod1Mask, "\033[124;3u", 0, 0 },
- { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0 },
- { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0 },
- { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0 },
- { XK_braceleft, ControlMask, "\033[123;5u", 0, 0 },
- { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0 },
- { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0 },
- { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0 },
- { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0 },
- { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0 },
- { XK_braceright, ControlMask, "\033[125;5u", 0, 0 },
- { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0 },
- { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0 },
- { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0 },
- { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0 },
- { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0 },
- { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0 },
- { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0 },
- { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0 },
- { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0 },
- { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0 },
- { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0 },
- /* { XK_bracketright, ControlMask, "\033[93;5u", 0, 0 }, */
- { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0 },
- { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0 },
- { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0 },
- { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0 },
- { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0 },
- { XK_colon, ControlMask, "\033[58;5u", 0, 0 },
- { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0 },
- { XK_colon, Mod1Mask, "\033[58;3u", 0, 0 },
- { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0 },
- { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0 },
- { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0 },
- { XK_comma, ControlMask, "\033[44;5u", 0, 0 },
- { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0 },
- { XK_comma, Mod1Mask, "\033[44;3u", 0, 0 },
- { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0 },
- { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0 },
- { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0 },
- { XK_dollar, ControlMask, "\033[36;5u", 0, 0 },
- { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0 },
- { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0 },
- { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0 },
- { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0 },
- { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0 },
- { XK_equal, ControlMask, "\033[61;5u", 0, 0 },
- { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0 },
- { XK_equal, Mod1Mask, "\033[61;3u", 0, 0 },
- { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0 },
- { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0 },
- { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0 },
- { XK_exclam, ControlMask, "\033[33;5u", 0, 0 },
- { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0 },
- { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0 },
- { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0 },
- { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0 },
- { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0 },
- { XK_grave, ControlMask, "\033[96;5u", 0, 0 },
- { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0 },
- { XK_grave, Mod1Mask, "\033[96;3u", 0, 0 },
- { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0 },
- { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0 },
- { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0 },
- { XK_greater, ControlMask, "\033[62;5u", 0, 0 },
- { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0 },
- { XK_greater, Mod1Mask, "\033[62;3u", 0, 0 },
- { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0 },
- { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0 },
- { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0 },
- { XK_less, ControlMask, "\033[60;5u", 0, 0 },
- { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0 },
- { XK_less, Mod1Mask, "\033[60;3u", 0, 0 },
- { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0 },
- { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0 },
- { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0 },
- { XK_minus, ControlMask, "\033[45;5u", 0, 0 },
- { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0 },
- { XK_minus, Mod1Mask, "\033[45;3u", 0, 0 },
- { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0 },
- { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0 },
- { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0 },
- { XK_numbersign, ControlMask, "\033[35;5u", 0, 0 },
- { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0 },
- { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0 },
- { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0 },
- { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0 },
- { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0 },
- { XK_parenleft, ControlMask, "\033[40;5u", 0, 0 },
- { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0 },
- { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0 },
- { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0 },
- { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0 },
- { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0 },
- { XK_parenright, ControlMask, "\033[41;5u", 0, 0 },
- { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0 },
- { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0 },
- { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0 },
- { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0 },
- { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0 },
- { XK_percent, ControlMask, "\033[37;5u", 0, 0 },
- { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0 },
- { XK_percent, Mod1Mask, "\033[37;3u", 0, 0 },
- { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0 },
- { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0 },
- { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0 },
- { XK_period, ControlMask, "\033[46;5u", 0, 0 },
- { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0 },
- { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0 },
- { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0 },
- { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0 },
- { XK_plus, ControlMask, "\033[43;5u", 0, 0 },
- { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0 },
- { XK_plus, Mod1Mask, "\033[43;3u", 0, 0 },
- { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0 },
- { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0 },
- { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0 },
- { XK_question, ControlMask, "\033[63;5u", 0, 0 },
- { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0 },
- { XK_question, Mod1Mask, "\033[63;3u", 0, 0 },
- { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0 },
- { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0 },
- { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0 },
- { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0 },
- { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0 },
- { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0 },
- { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0 },
- { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0 },
- { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0 },
- { XK_semicolon, ControlMask, "\033[59;5u", 0, 0 },
- { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0 },
- { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0 },
- { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0 },
- { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0 },
- { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0 },
- { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0 },
- { XK_slash, Mod1Mask, "\033[47;3u", 0, 0 },
- { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0 },
- { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0 },
- { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0 },
- { XK_underscore, ControlMask, "\033[95;5u", 0, 0 },
- { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0 },
- { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0 },
- { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0 },
- { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0 },
- { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0 },
+ { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1},
+ { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1},
+ { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0},
+ { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0},
+ { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0},
+ { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0},
+ { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0},
+ { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1},
+ { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1},
+ { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0},
+ { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0},
+ { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0},
+ { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0},
+ { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0},
+ { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1},
+ { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1},
+ { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0},
+ { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0},
+ { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0},
+ { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0},
+ { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0},
+ { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1},
+ { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1},
+ { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0},
+ { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0},
+ { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0},
+ { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0},
+ { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0},
+ { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1},
+ { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1},
+ { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0},
+ { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0},
+ { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0},
+ { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0},
+ { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0},
+ { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0},
+ { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0},
+ { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0},
+ { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0},
+ { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0},
+ { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0},
+ { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0},
+ { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0},
+ { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0},
+ { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0},
+ { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0},
+ { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0},
+ { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0},
+ { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0},
+ { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0},
+ { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0},
+ { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0},
+ { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0},
+ { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0},
+ { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0},
+ { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0},
+ { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0},
+ { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0},
+ { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0},
+ { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0},
+ { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0},
+ { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0},
+ { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0},
+ { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0},
+ { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0},
+ { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0},
+ { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0},
+ { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0},
+ { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0},
+ { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0},
+ { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0},
+ { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0},
+ { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0},
+ { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0},
+ { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0},
+ { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0},
+ { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0},
+ { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0},
+ { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0},
+ { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0},
+ { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0},
+ { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0},
+ { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0},
+ { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0},
+ { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0},
+ { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0},
+ { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0},
+ { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0},
+ { XK_KP_0, ControlMask, "\033[176;5u", 0, 0},
+ { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0},
+ { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0},
+ { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0},
+ { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0},
+ { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0},
+ { XK_KP_0, ControlMask, "\033[177;5u", 0, 0},
+ { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0},
+ { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0},
+ { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0},
+ { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0},
+ { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0},
+ { XK_KP_2, ControlMask, "\033[178;5u", 0, 0},
+ { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0},
+ { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0},
+ { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0},
+ { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0},
+ { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0},
+ { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0},
+ { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0},
+ { XK_KP_3, ControlMask, "\033[179;5u", 0, 0},
+ { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0},
+ { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0},
+ { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0},
+ { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0},
+ { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0},
+ { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0},
+ { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0},
+ { XK_KP_4, ControlMask, "\033[180;5u", 0, 0},
+ { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0},
+ { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0},
+ { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0},
+ { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0},
+ { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0},
+ { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0},
+ { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0},
+ { XK_KP_5, ControlMask, "\033[181;5u", 0, 0},
+ { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0},
+ { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0},
+ { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0},
+ { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0},
+ { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0},
+ { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0},
+ { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0},
+ { XK_KP_6, ControlMask, "\033[182;5u", 0, 0},
+ { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0},
+ { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0},
+ { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0},
+ { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0},
+ { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0},
+ { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0},
+ { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0},
+ { XK_KP_7, ControlMask, "\033[183;5u", 0, 0},
+ { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0},
+ { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0},
+ { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0},
+ { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0},
+ { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0},
+ { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0},
+ { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0},
+ { XK_KP_8, ControlMask, "\033[184;5u", 0, 0},
+ { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0},
+ { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0},
+ { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0},
+ { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0},
+ { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0},
+ { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0},
+ { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0},
+ { XK_KP_9, ControlMask, "\033[185;5u", 0, 0},
+ { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0},
+ { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0},
+ { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0},
+ { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0},
+ { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0},
+ { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0},
+ { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0},
+ { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0},
+ { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0},
+ { XK_Tab, ControlMask, "\033[9;5u", 0, 0},
+ { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0},
+ { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0},
+ { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0},
+ { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0},
+ { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0},
+ { XK_Return, ControlMask, "\033[13;5u", 0, 0},
+ { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0},
+ { XK_Return, Mod1Mask, "\033[13;3u", 0, 0},
+ { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0},
+ { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0},
+ { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0},
+ { XK_Return, ShiftMask, "\033[13;2u", 0, 0},
+ { XK_Pause, ControlMask, "\033[18;5u", 0, 0},
+ { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0},
+ { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0},
+ { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0},
+ { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0},
+ { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0},
+ { XK_Pause, ShiftMask, "\033[18;2u", 0, 0},
+ { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0},
+ { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0},
+ { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0},
+ { XK_Escape, ControlMask, "\033[27;5u", 0, 0},
+ { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0},
+ { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0},
+ { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0},
+ { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0},
+ { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0},
+ { XK_Escape, ShiftMask, "\033[27;2u", 0, 0},
+ { XK_Home, XK_NO_MOD, "\033[H", 0, -1},
+ { XK_Home, XK_NO_MOD, "\033[1~", 0, +1},
+ { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
+ { XK_Home, Mod1Mask, "\033[80;3u", 0, 0},
+ { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0},
+ { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0},
+ { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0},
+ { XK_End, XK_NO_MOD, "\033[4~", 0, 0},
+ { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
+ { XK_End, Mod1Mask, "\033[87;3u", 0, 0},
+ { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0},
+ { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0},
+ { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0},
+ { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0},
+ { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
+ { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0},
+ { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0},
+ { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0},
+ { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0},
+ { XK_Next, XK_NO_MOD, "\033[6~", 0, 0},
+ { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
+ { XK_Next, Mod1Mask, "\033[86;3u", 0, 0},
+ { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0},
+ { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0},
+ { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0},
+ { XK_Print, ControlMask, "\033[97;5u", 0, 0},
+ { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0},
+ { XK_Print, Mod1Mask, "\033[97;3u", 0, 0},
+ { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0},
+ { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0},
+ { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0},
+ { XK_Print, ShiftMask, "\033[97;2u", 0, 0},
+ { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0},
+ { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0},
+ { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0},
+ { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0},
+ { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0},
+ { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0},
+ { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0},
+ { XK_Menu, ControlMask, "\033[103;5u", 0, 0},
+ { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0},
+ { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0},
+ { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0},
+ { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0},
+ { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0},
+ { XK_Menu, ShiftMask, "\033[103;2u", 0, 0},
+ { XK_Delete, XK_NO_MOD, "\033[P", -1, 0},
+ { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0},
+ { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0},
+ { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0},
+ { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0},
+ { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0},
+ { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0},
+ { XK_i, ControlMask, "\033[105;5u", 0, 0},
+ { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0},
+ { XK_m, ControlMask, "\033[109;5u", 0, 0},
+ { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0},
+ { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0},
+ { XK_space, Mod1Mask, "\033[32;3u", 0, 0},
+ { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0},
+ { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0},
+ { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0},
+ { XK_space, ShiftMask, "\033[32;2u", 0, 0},
+ { XK_0, ControlMask, "\033[48;5u", 0, 0},
+ { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0},
+ { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0},
+ { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0},
+ { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0},
+ { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0},
+ { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0},
+ { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0},
+ { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0},
+ { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0},
+ { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0},
+ { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0},
+ { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0},
+ { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0},
+ { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0},
+ { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0},
+ { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0},
+ { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0},
+ { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
+ { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0},
+ { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0},
+ { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0},
+ { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0},
+ { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
+ { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
+ { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
+ { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0},
+ { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0},
+ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0},
+ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0},
+ { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0},
+ { XK_1, ControlMask, "\033[49;5u", 0, 0},
+ { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0},
+ { XK_2, ControlMask, "\033[50;5u", 0, 0},
+ { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0},
+ { XK_3, ControlMask, "\033[51;5u", 0, 0},
+ { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0},
+ { XK_4, ControlMask, "\033[52;5u", 0, 0},
+ { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0},
+ { XK_5, ControlMask, "\033[53;5u", 0, 0},
+ { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0},
+ { XK_6, ControlMask, "\033[54;5u", 0, 0},
+ { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0},
+ { XK_7, ControlMask, "\033[55;5u", 0, 0},
+ { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0},
+ { XK_8, ControlMask, "\033[56;5u", 0, 0},
+ { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0},
+ { XK_9, ControlMask, "\033[57;5u", 0, 0},
+ { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0},
+ { XK_ampersand, ControlMask, "\033[38;5u", 0, 0},
+ { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0},
+ { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0},
+ { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0},
+ { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0},
+ { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0},
+ { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0},
+ { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0},
+ { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0},
+ { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0},
+ { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0},
+ { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0},
+ { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0},
+ { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0},
+ { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0},
+ { XK_asterisk, ControlMask, "\033[42;5u", 0, 0},
+ { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0},
+ { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0},
+ { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0},
+ { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0},
+ { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0},
+ { XK_at, ControlMask, "\033[64;5u", 0, 0},
+ { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0},
+ { XK_at, Mod1Mask, "\033[64;3u", 0, 0},
+ { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0},
+ { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0},
+ { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0},
+ { XK_backslash, ControlMask, "\033[92;5u", 0, 0},
+ { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0},
+ { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0},
+ { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0},
+ { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0},
+ { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0},
+ { XK_bar, ControlMask, "\033[124;5u", 0, 0},
+ { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0},
+ { XK_bar, Mod1Mask, "\033[124;3u", 0, 0},
+ { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0},
+ { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0},
+ { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0},
+ { XK_braceleft, ControlMask, "\033[123;5u", 0, 0},
+ { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0},
+ { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0},
+ { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0},
+ { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0},
+ { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0},
+ { XK_braceright, ControlMask, "\033[125;5u", 0, 0},
+ { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0},
+ { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0},
+ { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0},
+ { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0},
+ { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0},
+ { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0},
+ { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0},
+ { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0},
+ { XK_bracketright, ControlMask, "\033[93;5u", 0, 0},
+ { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0},
+ { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0},
+ { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0},
+ { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0},
+ { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0},
+ { XK_colon, ControlMask, "\033[58;5u", 0, 0},
+ { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0},
+ { XK_colon, Mod1Mask, "\033[58;3u", 0, 0},
+ { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0},
+ { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0},
+ { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0},
+ { XK_comma, ControlMask, "\033[44;5u", 0, 0},
+ { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0},
+ { XK_comma, Mod1Mask, "\033[44;3u", 0, 0},
+ { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0},
+ { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0},
+ { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0},
+ { XK_dollar, ControlMask, "\033[36;5u", 0, 0},
+ { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0},
+ { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0},
+ { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0},
+ { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0},
+ { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0},
+ { XK_equal, ControlMask, "\033[61;5u", 0, 0},
+ { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0},
+ { XK_equal, Mod1Mask, "\033[61;3u", 0, 0},
+ { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0},
+ { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0},
+ { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0},
+ { XK_exclam, ControlMask, "\033[33;5u", 0, 0},
+ { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0},
+ { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0},
+ { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0},
+ { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0},
+ { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0},
+ { XK_grave, ControlMask, "\033[96;5u", 0, 0},
+ { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0},
+ { XK_grave, Mod1Mask, "\033[96;3u", 0, 0},
+ { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0},
+ { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0},
+ { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0},
+ { XK_greater, ControlMask, "\033[62;5u", 0, 0},
+ { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0},
+ { XK_greater, Mod1Mask, "\033[62;3u", 0, 0},
+ { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0},
+ { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0},
+ { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0},
+ { XK_less, ControlMask, "\033[60;5u", 0, 0},
+ { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0},
+ { XK_less, Mod1Mask, "\033[60;3u", 0, 0},
+ { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0},
+ { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0},
+ { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0},
+ { XK_minus, ControlMask, "\033[45;5u", 0, 0},
+ { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0},
+ { XK_minus, Mod1Mask, "\033[45;3u", 0, 0},
+ { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0},
+ { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0},
+ { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0},
+ { XK_numbersign, ControlMask, "\033[35;5u", 0, 0},
+ { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0},
+ { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0},
+ { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0},
+ { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0},
+ { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0},
+ { XK_parenleft, ControlMask, "\033[40;5u", 0, 0},
+ { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0},
+ { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0},
+ { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0},
+ { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0},
+ { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0},
+ { XK_parenright, ControlMask, "\033[41;5u", 0, 0},
+ { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0},
+ { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0},
+ { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0},
+ { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0},
+ { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0},
+ { XK_percent, ControlMask, "\033[37;5u", 0, 0},
+ { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0},
+ { XK_percent, Mod1Mask, "\033[37;3u", 0, 0},
+ { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0},
+ { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0},
+ { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0},
+ { XK_period, ControlMask, "\033[46;5u", 0, 0},
+ { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0},
+ { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0},
+ { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0},
+ { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0},
+ { XK_plus, ControlMask, "\033[43;5u", 0, 0},
+ { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0},
+ { XK_plus, Mod1Mask, "\033[43;3u", 0, 0},
+ { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0},
+ { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0},
+ { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0},
+ { XK_question, ControlMask, "\033[63;5u", 0, 0},
+ { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0},
+ { XK_question, Mod1Mask, "\033[63;3u", 0, 0},
+ { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0},
+ { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0},
+ { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0},
+ { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0},
+ { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0},
+ { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0},
+ { XK_semicolon, ControlMask, "\033[59;5u", 0, 0},
+ { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0},
+ { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0},
+ { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0},
+ { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0},
+ { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0},
+ { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0},
+ { XK_slash, Mod1Mask, "\033[47;3u", 0, 0},
+ { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0},
+ { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0},
+ { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0},
+ { XK_underscore, ControlMask, "\033[95;5u", 0, 0},
+ { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0},
+ { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0},
+ { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0},
+ { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0},
+ { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0},
};
/*
@@ -1167,7 +1221,7 @@ static Key key[] = {
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
- [SEL_RECTANGULAR] = MODKEY,
+ [SEL_RECTANGULAR] = Mod1Mask,
};
/*
@@ -1175,7 +1229,18 @@ static uint selmasks[] = {
* of single wide characters.
*/
static char ascii_printable[] =
- " !\"#$%&'()*+,-./0123456789:;<=>?"
- "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
- "`abcdefghijklmnopqrstuvwxyz{|}~";
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+
+/*
+ * Open urls starting with urlprefixes, contatining urlchars
+ * by passing as ARG1 to urlhandler.
+ */
+char* urlhandler = "xdg-open";
+char urlchars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+char* urlprefixes[] = {"http://", "https://", NULL};
diff --git a/st/config.mk b/st/config.mk
index ef6de39..069a6c2 100644
--- a/st/config.mk
+++ b/st/config.mk
@@ -1,5 +1,5 @@
# st version
-VERSION = 0.8.5
+VERSION = 0.9.2
# Customize below to fit your system
@@ -15,12 +15,10 @@ PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
- `$(PKG_CONFIG) --cflags freetype2` \
- `$(PKG_CONFIG) --cflags harfbuzz`
+ `$(PKG_CONFIG) --cflags freetype2`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
`$(PKG_CONFIG) --libs fontconfig` \
- `$(PKG_CONFIG) --libs freetype2` \
- `$(PKG_CONFIG) --libs harfbuzz`
+ `$(PKG_CONFIG) --libs freetype2`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
@@ -32,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `$(PKG_CONFIG) --libs fontconfig` \
# `$(PKG_CONFIG) --libs freetype2`
+#MANPREFIX = ${PREFIX}/man
# compiler and linker
# CC = c99
diff --git a/st/externalpipe_buffer.sh b/st/externalpipe_buffer.sh
new file mode 100644
index 0000000..67eb13c
--- /dev/null
+++ b/st/externalpipe_buffer.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env sh
+# externalpipe_buffer.sh: use with surf/st externalpipe-signal patches
+# Input Usage: echo st or surf content from externalpipe | ./externalpipe_buffer.sh {st,surf}_strings_read
+# Menus Usage: ./externalpipe_buffer.sh dmenu_{copy, type}
+BUFFER_FILE=/tmp/content_buffer
+function st_strings_read() {
+ INPUT="$(cat)"
+ echo "$(
+ echo "$INPUT" | grep -Eo '\S+' | tr -d '[:blank:]'
+ echo "$INPUT" | grep -oP '"[^"]+"' | tr -d '"'
+ echo "$INPUT" | sed 's/^ *[0-9]\+.//g' | awk '{$1=$1};1'
+ )" | uniq | grep . | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- \
+ >> $BUFFER_FILE &
+}
+function surf_strings_read() {
+ awk '{printf "%sNEWLINE_REPLACE", $0} END {printf "\n"}' |
+ xmllint --html --xpath "//*" - |
+ awk '{ gsub("<[^>]*>", ""); print($0); }' |
+ sed 's/NEWLINE_REPLACE/↵/g' |
+ awk '{ gsub("<[^>]*>",""); print $0 }' |
+ sed 's/&lt;/</g' |
+ sed 's/&gt;/>/g' |
+ uniq | grep . | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- \
+ >> $BUFFER_FILE &
+}
+function trigger_sigusr1() {
+ USE_FIFO=F # Recomended as T but only if using dmenu-stdin patch w/ FIFO
+ rm -f $BUFFER_FILE
+ if [ $USE_FIFO == T ]; then mkfifo $BUFFER_FILE; else touch $BUFFER_FILE; fi
+ pkill -USR1 "surf" &
+ pkill -USR1 "^st$" &
+ if [ $USE_FIFO != T ]; then sleep 0.8; fi
+}
+function dmenu_copy() {
+ trigger_sigusr1
+ cat $BUFFER_FILE | dmenu -l 10 -i -w $(xdotool getactivewindow) -p 'Screen Copy' | sed 's/↵/\n/g' | xclip -i
+}
+function dmenu_type() {
+ trigger_sigusr1
+ cat $BUFFER_FILE | dmenu -l 10 -i -w $(xdotool getactivewindow) -p 'Screen Type' | sed 's/↵/\n/g' | xargs -IC xdotool type --delay 0 "C"
+}
+function pipe_combine() {
+ trigger_sigusr1
+ cat - $BUFFER_FILE
+}
+
+$1
diff --git a/st/hb.c b/st/hb.c
deleted file mode 100644
index 8000afa..0000000
--- a/st/hb.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-#include <X11/Xft/Xft.h>
-#include <X11/cursorfont.h>
-#include <hb.h>
-#include <hb-ft.h>
-
-#include "st.h"
-
-#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
-
-/*
- * Replace 0 with a list of font features, wrapped in FEATURE macro, e.g.
- * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
- *
- * Uncomment either one of the 2 lines below. Uncomment the prior to disable (any) font features. Uncomment the
- * latter to enable the (selected) font features.
- */
-
-hb_feature_t features[] = { 0 };
-//hb_feature_t features[] = { FEATURE('s','s','0','1'), FEATURE('s','s','0','2'), FEATURE('s','s','0','3'), FEATURE('s','s','0','5'), FEATURE('s','s','0','6'), FEATURE('s','s','0','7'), FEATURE('s','s','0','8'), FEATURE('z','e','r','o') };
-
-void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
-hb_font_t *hbfindfont(XftFont *match);
-
-typedef struct {
- XftFont *match;
- hb_font_t *font;
-} HbFontMatch;
-
-static int hbfontslen = 0;
-static HbFontMatch *hbfontcache = NULL;
-
-void
-hbunloadfonts()
-{
- for (int i = 0; i < hbfontslen; i++) {
- hb_font_destroy(hbfontcache[i].font);
- XftUnlockFace(hbfontcache[i].match);
- }
-
- if (hbfontcache != NULL) {
- free(hbfontcache);
- hbfontcache = NULL;
- }
- hbfontslen = 0;
-}
-
-hb_font_t *
-hbfindfont(XftFont *match)
-{
- for (int i = 0; i < hbfontslen; i++) {
- if (hbfontcache[i].match == match)
- return hbfontcache[i].font;
- }
-
- /* Font not found in cache, caching it now. */
- hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
- FT_Face face = XftLockFace(match);
- hb_font_t *font = hb_ft_font_create(face, NULL);
- if (font == NULL)
- die("Failed to load Harfbuzz font.");
-
- hbfontcache[hbfontslen].match = match;
- hbfontcache[hbfontslen].font = font;
- hbfontslen += 1;
-
- return font;
-}
-
-void
-hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
-{
- int start = 0, length = 1, gstart = 0;
- hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(hb_codepoint_t));
-
- for (int idx = 1, specidx = 1; idx < len; idx++) {
- if (glyphs[idx].mode & ATTR_WDUMMY) {
- length += 1;
- continue;
- }
-
- if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
- hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
-
- /* Reset the sequence. */
- length = 1;
- start = specidx;
- gstart = idx;
- } else {
- length += 1;
- }
-
- specidx++;
- }
-
- /* EOL. */
- hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
-
- /* Apply the transformation to glyph specs. */
- for (int i = 0, specidx = 0; i < len; i++) {
- if (glyphs[i].mode & ATTR_WDUMMY)
- continue;
- if (glyphs[i].mode & ATTR_BOXDRAW) {
- specidx++;
- continue;
- }
-
- if (codepoints[i] != specs[specidx].glyph)
- ((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
-
- specs[specidx++].glyph = codepoints[i];
- }
-
- free(codepoints);
-}
-
-void
-hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
-{
- hb_font_t *font = hbfindfont(xfont);
- if (font == NULL)
- return;
-
- Rune rune;
- ushort mode = USHRT_MAX;
- hb_buffer_t *buffer = hb_buffer_create();
- hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
-
- /* Fill buffer with codepoints. */
- for (int i = start; i < (start+length); i++) {
- rune = string[i].u;
- mode = string[i].mode;
- if (mode & ATTR_WDUMMY)
- rune = 0x0020;
- hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
- }
-
- /* Shape the segment. */
- hb_shape(font, buffer, features, sizeof(features));
-
- /* Get new glyph info. */
- hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
-
- /* Write new codepoints. */
- for (int i = 0; i < length; i++) {
- hb_codepoint_t gid = info[i].codepoint;
- codepoints[start+i] = gid;
- }
-
- /* Cleanup. */
- hb_buffer_destroy(buffer);
-}
diff --git a/st/hb.h b/st/hb.h
deleted file mode 100644
index b3e02d0..0000000
--- a/st/hb.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <X11/Xft/Xft.h>
-#include <hb.h>
-#include <hb-ft.h>
-
-void hbunloadfonts();
-void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
-
diff --git a/st/patches/st-anygeometry-0.8.1.diff b/st/patches/st-anygeometry-0.8.1.diff
new file mode 100644
index 0000000..b04d36c
--- /dev/null
+++ b/st/patches/st-anygeometry-0.8.1.diff
@@ -0,0 +1,123 @@
+From 6a5a862569912e34febe2dbd5244062013840204 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jos=C3=A9=20Miguel=20S=C3=A1nchez=20Garc=C3=ADa?=
+ <soy.jmi2k@gmail.com>
+Date: Thu, 13 Aug 2020 11:02:01 +0000
+Subject: [PATCH] add -G to set pixel-based geometry
+
+---
+ config.def.h | 13 +++++++++++++
+ x.c | 36 ++++++++++++++++++++++++++++++++----
+ 2 files changed, 45 insertions(+), 4 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..bea316a 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -141,6 +141,12 @@ static unsigned int defaultrcs = 257;
+ */
+ static unsigned int cursorshape = 2;
+
++/*
++ * Whether to use pixel geometry or cell geometry
++ */
++
++static Geometry geometry = CellGeometry;
++
+ /*
+ * Default columns and rows numbers
+ */
+@@ -148,6 +154,13 @@ static unsigned int cursorshape = 2;
+ static unsigned int cols = 80;
+ static unsigned int rows = 24;
+
++/*
++ * Default width and height (including borders!)
++ */
++
++static unsigned int width = 564;
++static unsigned int height = 364;
++
+ /*
+ * Default colour and shape of the mouse cursor
+ */
+diff --git a/x.c b/x.c
+index 210f184..29e35d0 100644
+--- a/x.c
++++ b/x.c
+@@ -45,6 +45,11 @@ typedef struct {
+ signed char appcursor; /* application cursor */
+ } Key;
+
++typedef enum {
++ PixelGeometry,
++ CellGeometry
++} Geometry;
++
+ /* X modifiers */
+ #define XK_ANY_MOD UINT_MAX
+ #define XK_NO_MOD 0
+@@ -1096,7 +1101,7 @@ xicdestroy(XIC xim, XPointer client, XPointer call)
+ }
+
+ void
+-xinit(int cols, int rows)
++xinit(int w, int h)
+ {
+ XGCValues gcvalues;
+ Cursor cursor;
+@@ -1121,8 +1126,16 @@ xinit(int cols, int rows)
+ xloadcols();
+
+ /* adjust fixed window geometry */
+- win.w = 2 * borderpx + cols * win.cw;
+- win.h = 2 * borderpx + rows * win.ch;
++ switch (geometry) {
++ case CellGeometry:
++ win.w = 2 * borderpx + w * win.cw;
++ win.h = 2 * borderpx + h * win.ch;
++ break;
++ case PixelGeometry:
++ win.w = w;
++ win.h = h;
++ break;
++ }
+ if (xw.gm & XNegative)
+ xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
+ if (xw.gm & YNegative)
+@@ -2001,6 +2014,12 @@ main(int argc, char *argv[])
+ case 'g':
+ xw.gm = XParseGeometry(EARGF(usage()),
+ &xw.l, &xw.t, &cols, &rows);
++ geometry = CellGeometry;
++ break;
++ case 'G':
++ xw.gm = XParseGeometry(EARGF(usage()),
++ &xw.l, &xw.t, &width, &height);
++ geometry = PixelGeometry;
+ break;
+ case 'i':
+ xw.isfixed = 1;
+@@ -2037,10 +2056,19 @@ run:
+
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
++ switch (geometry) {
++ case CellGeometry:
++ xinit(cols, rows);
++ break;
++ case PixelGeometry:
++ xinit(width, height);
++ cols = (win.w - 2 * borderpx) / win.cw;
++ rows = (win.h - 2 * borderpx) / win.ch;
++ break;
++ }
+ cols = MAX(cols, 1);
+ rows = MAX(rows, 1);
+ tnew(cols, rows);
+- xinit(cols, rows);
+ xsetenv();
+ selinit();
+ run();
+--
+2.28.0
+
diff --git a/st/patches/st-anysize-20220718-baa9357.diff b/st/patches/st-anysize-20220718-baa9357.diff
new file mode 100644
index 0000000..773cb09
--- /dev/null
+++ b/st/patches/st-anysize-20220718-baa9357.diff
@@ -0,0 +1,163 @@
+# From 8dcdc4b21a73268e167d98aa30f24315c7f3b7ff Mon Sep 17 00:00:00 2001
+# From: Bakkeby <bakkeby@gmail.com>
+# Date: Mon, 18 Jul 2022 16:52:03 +0200
+# Subject: [PATCH] Adding anysize patch
+#
+# ---
+# x.c | 56 ++++++++++++++++++++++++++++++--------------------------
+# 1 file changed, 30 insertions(+), 26 deletions(-)
+
+diff --git a/x.c b/x.c
+index 2a3bd38..f534347 100644
+--- a/x.c
++++ b/x.c
+@@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
+ typedef struct {
+ int tw, th; /* tty width and height */
+ int w, h; /* window width and height */
++ int hborderpx, vborderpx;
+ int ch; /* char height */
+ int cw; /* char width */
+ int mode; /* window state/mode flags */
+@@ -331,7 +332,7 @@ ttysend(const Arg *arg)
+ int
+ evcol(XEvent *e)
+ {
+- int x = e->xbutton.x - borderpx;
++ int x = e->xbutton.x - win.hborderpx;
+ LIMIT(x, 0, win.tw - 1);
+ return x / win.cw;
+ }
+@@ -339,7 +340,7 @@ evcol(XEvent *e)
+ int
+ evrow(XEvent *e)
+ {
+- int y = e->xbutton.y - borderpx;
++ int y = e->xbutton.y - win.vborderpx;
+ LIMIT(y, 0, win.th - 1);
+ return y / win.ch;
+ }
+@@ -739,6 +740,9 @@ cresize(int width, int height)
+ col = MAX(1, col);
+ row = MAX(1, row);
+
++ win.hborderpx = (win.w - col * win.cw) / 2;
++ win.vborderpx = (win.h - row * win.ch) / 2;
++
+ tresize(col, row);
+ xresize(col, row);
+ ttyresize(win.tw, win.th);
+@@ -869,8 +873,8 @@ xhints(void)
+ sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
+ sizeh->height = win.h;
+ sizeh->width = win.w;
+- sizeh->height_inc = win.ch;
+- sizeh->width_inc = win.cw;
++ sizeh->height_inc = 1;
++ sizeh->width_inc = 1;
+ sizeh->base_height = 2 * borderpx;
+ sizeh->base_width = 2 * borderpx;
+ sizeh->min_height = win.ch + 2 * borderpx;
+@@ -1152,8 +1156,8 @@ xinit(int cols, int rows)
+ xloadcols();
+
+ /* adjust fixed window geometry */
+- win.w = 2 * borderpx + cols * win.cw;
+- win.h = 2 * borderpx + rows * win.ch;
++ win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
++ win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
+ if (xw.gm & XNegative)
+ xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
+ if (xw.gm & YNegative)
+@@ -1242,7 +1246,7 @@ xinit(int cols, int rows)
+ int
+ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
+ {
+- float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
++ float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
+ ushort mode, prevmode = USHRT_MAX;
+ Font *font = &dc.font;
+ int frcflags = FRC_NORMAL;
+@@ -1375,7 +1379,7 @@ void
+ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
+ {
+ int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
+- int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
++ int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
+ width = charlen * win.cw;
+ Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
+ XRenderColor colfg, colbg;
+@@ -1465,17 +1469,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+
+ /* Intelligent cleaning up of the borders. */
+ if (x == 0) {
+- xclear(0, (y == 0)? 0 : winy, borderpx,
++ xclear(0, (y == 0)? 0 : winy, win.hborderpx,
+ winy + win.ch +
+- ((winy + win.ch >= borderpx + win.th)? win.h : 0));
++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
+ }
+- if (winx + width >= borderpx + win.tw) {
++ if (winx + width >= win.hborderpx + win.tw) {
+ xclear(winx + width, (y == 0)? 0 : winy, win.w,
+- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
+ }
+ if (y == 0)
+- xclear(winx, 0, winx + width, borderpx);
+- if (winy + win.ch >= borderpx + win.th)
++ xclear(winx, 0, winx + width, win.vborderpx);
++ if (winy + win.ch >= win.vborderpx + win.th)
+ xclear(winx, winy + win.ch, winx + width, win.h);
+
+ /* Clean up the region we want to draw to. */
+@@ -1569,35 +1573,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+ case 3: /* Blinking Underline */
+ case 4: /* Steady Underline */
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + cx * win.cw,
+- borderpx + (cy + 1) * win.ch - \
++ win.hborderpx + cx * win.cw,
++ win.vborderpx + (cy + 1) * win.ch - \
+ cursorthickness,
+ win.cw, cursorthickness);
+ break;
+ case 5: /* Blinking bar */
+ case 6: /* Steady bar */
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + cx * win.cw,
+- borderpx + cy * win.ch,
++ win.hborderpx + cx * win.cw,
++ win.vborderpx + cy * win.ch,
+ cursorthickness, win.ch);
+ break;
+ }
+ } else {
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + cx * win.cw,
+- borderpx + cy * win.ch,
++ win.hborderpx + cx * win.cw,
++ win.vborderpx + cy * win.ch,
+ win.cw - 1, 1);
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + cx * win.cw,
+- borderpx + cy * win.ch,
++ win.hborderpx + cx * win.cw,
++ win.vborderpx + cy * win.ch,
+ 1, win.ch - 1);
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + (cx + 1) * win.cw - 1,
+- borderpx + cy * win.ch,
++ win.hborderpx + (cx + 1) * win.cw - 1,
++ win.vborderpx + cy * win.ch,
+ 1, win.ch - 1);
+ XftDrawRect(xw.draw, &drawcol,
+- borderpx + cx * win.cw,
+- borderpx + (cy + 1) * win.ch - 1,
++ win.hborderpx + cx * win.cw,
++ win.vborderpx + (cy + 1) * win.ch - 1,
+ win.cw, 1);
+ }
+ }
+--
+2.37.1
diff --git a/st/patches/st-autocomplete-20240703-6508693.diff b/st/patches/st-autocomplete-20240703-6508693.diff
new file mode 100644
index 0000000..89c0ee2
--- /dev/null
+++ b/st/patches/st-autocomplete-20240703-6508693.diff
@@ -0,0 +1,702 @@
+From 650869359d3568dd2a000d474054e835a9c7ac74 Mon Sep 17 00:00:00 2001
+From: elbachir-one <bachiralfa@gmail.com>
+Date: Wed, 3 Jul 2024 22:44:40 +0100
+Subject: [PATCH] The use of mkstemp'
+
+---
+ Makefile | 3 +
+ autocomplete.h | 16 +++
+ config.def.h | 12 ++
+ st-autocomplete | 310 ++++++++++++++++++++++++++++++++++++++++++++++++
+ st.c | 227 +++++++++++++++++++++++++++++++++++
+ st.h | 2 +
+ x.c | 9 ++
+ 7 files changed, 579 insertions(+)
+ create mode 100644 autocomplete.h
+ create mode 100644 st-autocomplete
+
+diff --git a/Makefile b/Makefile
+index 93fed02..9aff9e0 100644
+--- a/Makefile
++++ b/Makefile
+@@ -38,6 +38,8 @@ install: st
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f st $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/st
++ cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin
++ chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete
+ mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+ sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
+ chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
+@@ -46,6 +48,7 @@ install: st
+
+ uninstall:
+ rm -f $(DESTDIR)$(PREFIX)/bin/st
++ rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete
+ rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
+
+ .PHONY: all clean dist install uninstall
+diff --git a/autocomplete.h b/autocomplete.h
+new file mode 100644
+index 0000000..fc88447
+--- /dev/null
++++ b/autocomplete.h
+@@ -0,0 +1,16 @@
++# ifndef __ST_AUTOCOMPLETE_H
++# define __ST_AUTOCOMPLETE_H
++
++enum {
++ ACMPL_DEACTIVATE,
++ ACMPL_WORD,
++ ACMPL_WWORD,
++ ACMPL_FUZZY_WORD,
++ ACMPL_FUZZY_WWORD,
++ ACMPL_FUZZY,
++ ACMPL_SUFFIX,
++ ACMPL_SURROUND,
++ ACMPL_UNDO,
++};
++
++# endif // __ST_AUTOCOMPLETE_H
+diff --git a/config.def.h b/config.def.h
+index 2cd740a..b74e03e 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -170,6 +170,8 @@ static unsigned int defaultattr = 11;
+ */
+ static uint forcemousemod = ShiftMask;
+
++#include "autocomplete.h"
++
+ /*
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+@@ -187,6 +189,8 @@ static MouseShortcut mshortcuts[] = {
+ #define MODKEY Mod1Mask
+ #define TERMMOD (ControlMask|ShiftMask)
+
++#define ACMPL_MOD ControlMask|Mod1Mask
++
+ static Shortcut shortcuts[] = {
+ /* mask keysym function argument */
+ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
+@@ -201,6 +205,14 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { ACMPL_MOD, XK_slash, autocomplete, { .i = ACMPL_WORD } },
++ { ACMPL_MOD, XK_period, autocomplete, { .i = ACMPL_FUZZY_WORD } },
++ { ACMPL_MOD, XK_comma, autocomplete, { .i = ACMPL_FUZZY } },
++ { ACMPL_MOD, XK_apostrophe, autocomplete, { .i = ACMPL_SUFFIX } },
++ { ACMPL_MOD, XK_semicolon, autocomplete, { .i = ACMPL_SURROUND } },
++ { ACMPL_MOD, XK_bracketright,autocomplete, { .i = ACMPL_WWORD } },
++ { ACMPL_MOD, XK_bracketleft, autocomplete, { .i = ACMPL_FUZZY_WWORD } },
++ { ACMPL_MOD, XK_equal, autocomplete, { .i = ACMPL_UNDO } },
+ };
+
+ /*
+diff --git a/st-autocomplete b/st-autocomplete
+new file mode 100644
+index 0000000..0fad536
+--- /dev/null
++++ b/st-autocomplete
+@@ -0,0 +1,310 @@
++#!/usr/bin/perl
++#########################################################################
++# Copyright (C) 2012-2017 Wojciech Siewierski #
++# #
++# This program is free software: you can redistribute it and/or modify #
++# it under the terms of the GNU General Public License as published by #
++# the Free Software Foundation, either version 3 of the License, or #
++# (at your option) any later version. #
++# #
++# This program is distributed in the hope that it will be useful, #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
++# GNU General Public License for more details. #
++# #
++# You should have received a copy of the GNU General Public License #
++# along with this program. If not, see <http://www.gnu.org/licenses/>. #
++#########################################################################
++
++my ($cmd, $cursor_row, $cursor_column) = @ARGV;
++
++my $lines = [];
++my $lines1 = [];
++
++my $last_line = -1;
++my $lines_before_cursor = 0;
++
++while (<stdin>)
++{
++ $last_line++;
++
++ s/[^[:print:]]/?/g;
++
++ if ($last_line < $cursor_row)
++ {
++ unshift @{$lines1}, $_;
++ $lines_before_cursor++;
++ }
++ else
++ {
++ unshift @{$lines}, $_;
++ }
++}
++
++foreach (@{$lines1})
++{
++ unshift @{$lines}, $_;
++}
++
++my $cursor_row_in = $cursor_row;
++
++$cursor_row = $last_line;
++
++
++$self = {};
++
++# A reference to a function that transforms the completed word
++# into a regex matching the completions. Usually generated by
++# generate_matcher().
++#
++# For example
++# $fun = generate_matcher(".*");
++# $fun->("foo");
++# would return "f.*o.*o"
++#
++# In other words, indirectly decides which characters can
++# appear in the completion.
++my $matcher;
++
++# A regular expression matching a character before each match.
++# For example, it you want to match the text after a
++# whitespace, set it to "\s".
++my $char_class_before;
++
++# A regular expression matching every character in the entered
++# text that will be used to find matching completions. Usually
++# "\w" or similar.
++my $char_class_to_complete;
++
++# A regular expression matching every allowed last character
++# of the completion (uses greedy matching).
++my $char_class_at_end;
++
++if ($cmd eq 'word-complete') {
++ # Basic word completion. Completes the current word
++ # without any special matching.
++ $char_class_before = '[^-\w]';
++ $matcher = sub { quotemeta shift }; # identity
++ $char_class_at_end = '[-\w]';
++ $char_class_to_complete = '[-\w]';
++} elsif ($cmd eq 'WORD-complete') {
++ # The same as above but in the Vim meaning of a "WORD" --
++ # whitespace delimited.
++ $char_class_before = '\s';
++ $matcher = sub { quotemeta shift };
++ $char_class_at_end = '\S';
++ $char_class_to_complete = '\S';
++} elsif ($cmd eq 'fuzzy-word-complete' ||
++ $cmd eq 'skeleton-word-complete') {
++ # Fuzzy completion of the current word.
++ $char_class_before = '[^-\w]';
++ $matcher = generate_matcher('[-\w]*');
++ $char_class_at_end = '[-\w]';
++ $char_class_to_complete = '[-\w]';
++} elsif ($cmd eq 'fuzzy-WORD-complete') {
++ # Fuzzy completion of the current WORD.
++ $char_class_before = '\s';
++ $matcher = generate_matcher('\S*');
++ $char_class_at_end = '\S';
++ $char_class_to_complete = '\S';
++} elsif ($cmd eq 'fuzzy-complete' ||
++ $cmd eq 'skeleton-complete') {
++ # Fuzzy completion of an arbitrary text.
++ $char_class_before = '\W';
++ $matcher = generate_matcher('.*?');
++ $char_class_at_end = '\w';
++ $char_class_to_complete = '\S';
++} elsif ($cmd eq 'suffix-complete') {
++ # Fuzzy completion of an completing suffixes, like
++ # completing test=hello from /blah/hello.
++ $char_class_before = '\S';
++ $matcher = generate_matcher('\S*');
++ $char_class_at_end = '\S';
++ $char_class_to_complete = '\S';
++} elsif ($cmd eq 'surround-complete') {
++ # Completing contents of quotes and braces.
++
++ # Here we are using three named groups: s, b, p for quotes, braces
++ # and parenthesis.
++ $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
++
++ $matcher = generate_matcher('.*?');
++
++ # Here we match text till enclosing pair, using perl conditionals in
++ # regexps (?(condition)yes-expression|no-expression).
++ # \0 is used to hack concatenation with '*' later in the code.
++ $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0';
++ $char_class_to_complete = '\S';
++}
++
++
++# use the last used word or read the word behind the cursor
++my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column,
++ $char_class_to_complete);
++
++print stdout "$word_to_complete\n";
++
++if ($word_to_complete) {
++ while (1) {
++ # ignore the completed word itself
++ $self->{already_completed}{$word_to_complete} = 1;
++
++ # continue the last search or start from the current row
++ my $completion = find_match($self,
++ $word_to_complete,
++ $self->{next_row} // $cursor_row,
++ $matcher->($word_to_complete),
++ $char_class_before,
++ $char_class_at_end);
++ if ($completion) {
++ print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n";
++ }
++ else {
++ last;
++ }
++ }
++}
++
++######################################################################
++
++sub highlight_match {
++ my ($self, $linenum, $completion) = @_;
++
++ # clear_highlight($self);
++
++ my $line = @{$lines}[$linenum];
++ my $re = quotemeta $completion;
++
++ $line =~ /$re/;
++
++ my $beg = $-[0];
++ my $end = $+[0];
++
++ if ($linenum >= $lines_before_cursor)
++ {
++ $lline = $last_line - $lines_before_cursor;
++ $linenum -= $lines_before_cursor;
++ $linenum = $lline - $linenum;
++ $linenum += $lines_before_cursor;
++ }
++
++
++ $self->{highlight} = [$linenum, $beg, $end];
++}
++
++######################################################################
++
++sub read_word_at_coord {
++ my ($self, $row, $col, $char_class) = @_;
++
++ $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the cursor...
++ s/.*?($char_class*)$/$1/; # ...and read the last word from it
++ return $_;
++}
++
++######################################################################
++
++# Returns a function that takes a string and returns that string with
++# this function's argument inserted between its every two characters.
++# The resulting string is used as a regular expression matching the
++# completion candidates.
++sub generate_matcher {
++ my $regex_between = shift;
++
++ sub {
++ $_ = shift;
++
++ # sorry for this lispy code, I couldn't resist ;)
++ (join "$regex_between",
++ (map quotemeta,
++ (split //)))
++ }
++}
++
++######################################################################
++
++# Checks whether the completion found by find_match() was already
++# found and if it was, calls find_match() again to find the next
++# completion.
++#
++# Takes all the arguments that find_match() would take, to make a
++# mutually recursive call.
++sub skip_duplicates {
++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_;
++ my $completion;
++
++ if ($current_row <= $lines_before_cursor)
++ {
++ $completion = shift @{$self->{matches_in_row}}; # get the leftmost one
++ }
++ else
++ {
++ $completion = pop @{$self->{matches_in_row}}; # get the leftmost one
++ }
++
++ # check for duplicates
++ if (exists $self->{already_completed}{$completion}) {
++ # skip this completion
++ return find_match(@_);
++ } else {
++ $self->{already_completed}{$completion} = 1;
++
++ highlight_match($self,
++ $self->{next_row}+1,
++ $completion);
++
++ return $completion;
++ }
++}
++
++######################################################################
++
++# Finds the next matching completion in the row current row or above
++# while skipping duplicates using skip_duplicates().
++sub find_match {
++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_;
++ $self->{matches_in_row} //= [];
++
++ # cycle through all the matches in the current row if not starting a new search
++ if (@{$self->{matches_in_row}}) {
++ return skip_duplicates($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end);
++ }
++
++
++ my $i;
++ # search through all the rows starting with current one or one above the last checked
++ for ($i = $current_row; $i >= 0; --$i) {
++ my $line = @{$lines}[$i]; # get the line of text from the row
++
++ # if ($i == $cursor_row) {
++ # $line = substr $line, 0, $cursor_column;
++ # }
++
++ $_ = $line;
++
++ # find all the matches in the current line
++ my $match;
++ push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
++ (.*${char_class_before})
++ (?<match>
++ ${regexp}
++ ${char_class_at_end}*
++ )
++ /ix;
++ # corner case: match at the very beginning of line
++ push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
++
++ if (@{$self->{matches_in_row}}) {
++ # remember which row should be searched next
++ $self->{next_row} = --$i;
++
++ # arguments needed for find_match() mutual recursion
++ return skip_duplicates($self, $word_to_match, $i, $regexp, $char_class_before, $char_class_at_end);
++ }
++ }
++
++ # # no more possible completions, revert to the original word
++ # undo_completion($self) if $i < 0;
++
++ return undef;
++}
+diff --git a/st.c b/st.c
+index 57c6e96..9ff8d00 100644
+--- a/st.c
++++ b/st.c
+@@ -17,6 +17,7 @@
+ #include <unistd.h>
+ #include <wchar.h>
+
++#include "autocomplete.h"
+ #include "st.h"
+ #include "win.h"
+
+@@ -2557,6 +2558,8 @@ tresize(int col, int row)
+ return;
+ }
+
++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
++
+ /*
+ * slide screen to keep cursor where we expect it -
+ * tscrollup would work here, but we can optimize to
+@@ -2676,3 +2679,227 @@ redraw(void)
+ tfulldirt();
+ draw();
+ }
++
++void autocomplete (const Arg *arg) {
++ static _Bool active = 0;
++ int acmpl_cmdindex = arg->i;
++ static int acmpl_cmdindex_prev;
++
++ if (active == 0)
++ acmpl_cmdindex_prev = acmpl_cmdindex;
++
++ static const char * const acmpl_cmd[] = {
++ [ACMPL_DEACTIVATE] = "__DEACTIVATE__",
++ [ACMPL_WORD] = "word-complete",
++ [ACMPL_WWORD] = "WORD-complete",
++ [ACMPL_FUZZY_WORD] = "fuzzy-word-complete",
++ [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete",
++ [ACMPL_FUZZY] = "fuzzy-complete",
++ [ACMPL_SUFFIX] = "suffix-complete",
++ [ACMPL_SURROUND] = "surround-complete",
++ [ACMPL_UNDO] = "__UNDO__",
++ };
++
++ static FILE *acmpl_exec = NULL;
++ static int acmpl_status;
++ static char *stbuffile;
++ static char *target = NULL;
++ static size_t targetlen;
++ static char *completion = NULL;
++ static size_t complen_prev = 0;
++ static int cx, cy;
++
++ if (acmpl_cmdindex == ACMPL_DEACTIVATE) {
++ if (active) {
++ active = 0;
++ pclose(acmpl_exec);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++
++ if (complen_prev) {
++ selclear();
++ complen_prev = 0;
++ }
++ }
++ return;
++ }
++
++ if (acmpl_cmdindex == ACMPL_UNDO) {
++ if (active) {
++ active = 0;
++ pclose(acmpl_exec);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++
++ if (complen_prev) {
++ selclear();
++ for (size_t i = 0; i < complen_prev; i++)
++ ttywrite((char[]) {'\b'}, 1, 1);
++ complen_prev = 0;
++ ttywrite(target, targetlen, 0);
++ }
++ }
++ return;
++ }
++
++ if (acmpl_cmdindex != acmpl_cmdindex_prev) {
++ if (active) {
++ acmpl_cmdindex_prev = acmpl_cmdindex;
++ goto acmpl_begin;
++ }
++ }
++
++ if (active == 0) {
++ acmpl_cmdindex_prev = acmpl_cmdindex;
++ cx = term.c.x;
++ cy = term.c.y;
++
++ char filename[] = "/tmp/st-autocomplete-XXXXXX";
++ int fd = mkstemp(filename);
++
++ if (fd == -1) {
++ perror("mkstemp");
++ return;
++ }
++
++ stbuffile = strdup(filename);
++
++ FILE *stbuf = fdopen(fd, "w");
++ if (!stbuf) {
++ perror("fdopen");
++ close(fd);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++
++ char *stbufline = malloc(term.col + 2);
++ if (!stbufline) {
++ perror("malloc");
++ fclose(stbuf);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++
++ int cxp = 0;
++ for (size_t y = 0; y < term.row; y++) {
++ if (y == term.c.y) cx += cxp * term.col;
++
++ size_t x = 0;
++ for (; x < term.col; x++)
++ utf8encode(term.line[y][x].u, stbufline + x);
++ if (term.line[y][x - 1].mode & ATTR_WRAP) {
++ x--;
++ if (y <= term.c.y) cy--;
++ cxp++;
++ } else {
++ stbufline[x] = '\n';
++ cxp = 0;
++ }
++ stbufline[x + 1] = 0;
++ fputs(stbufline, stbuf);
++ }
++
++ free(stbufline);
++ fclose(stbuf);
++
++acmpl_begin:
++ target = malloc(term.col + 1);
++ completion = malloc(term.col + 1);
++ if (!target || !completion) {
++ perror("malloc");
++ free(target);
++ free(completion);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++
++ char acmpl[1500];
++ snprintf(acmpl, sizeof(acmpl),
++ "cat %s | st-autocomplete %s %d %d",
++ stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx);
++
++ acmpl_exec = popen(acmpl, "r");
++ if (!acmpl_exec) {
++ perror("popen");
++ free(target);
++ free(completion);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++
++ if (fscanf(acmpl_exec, "%s\n", target) != 1) {
++ perror("fscanf");
++ pclose(acmpl_exec);
++ free(target);
++ free(completion);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++ targetlen = strlen(target);
++ }
++
++ unsigned line, beg, end;
++
++ acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end);
++ if (acmpl_status == EOF) {
++ if (active == 0) {
++ pclose(acmpl_exec);
++ free(target);
++ free(completion);
++ unlink(stbuffile);
++ free(stbuffile);
++ stbuffile = NULL;
++ return;
++ }
++ active = 0;
++ pclose(acmpl_exec);
++ ttywrite(target, targetlen, 0);
++ goto acmpl_begin;
++ }
++
++ active = 1;
++
++ if (complen_prev == 0) {
++ for (size_t i = 0; i < targetlen; i++)
++ ttywrite((char[]) {'\b'}, 1, 1);
++ } else {
++ selclear();
++ for (size_t i = 0; i < complen_prev; i++)
++ ttywrite((char[]) {'\b'}, 1, 1);
++ complen_prev = 0;
++ }
++
++ complen_prev = strlen(completion);
++ ttywrite(completion, complen_prev, 0);
++
++ if (line == cy && beg > cx) {
++ beg += complen_prev - targetlen;
++ end += complen_prev - targetlen;
++ }
++
++ end--;
++
++ int wl = 0;
++ int tl = line;
++ for (int l = 0; l < tl; l++)
++ if (term.line[l][term.col - 1].mode & ATTR_WRAP) {
++ wl++;
++ tl++;
++ }
++
++ selstart(beg % term.col, line + wl + beg / term.col, 0);
++ selextend(end % term.col, line + wl + end / term.col, 1, 0);
++ xsetsel(getsel());
++}
+diff --git a/st.h b/st.h
+index fd3b0d8..113ebad 100644
+--- a/st.h
++++ b/st.h
+@@ -77,6 +77,8 @@ typedef union {
+ const char *s;
+ } Arg;
+
++void autocomplete (const Arg *);
++
+ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+diff --git a/x.c b/x.c
+index bd23686..c647721 100644
+--- a/x.c
++++ b/x.c
+@@ -1859,11 +1859,20 @@ kpress(XEvent *ev)
+ /* 1. shortcuts */
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, e->state)) {
++ if (bp -> func != autocomplete)
++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
+ bp->func(&(bp->arg));
+ return;
+ }
+ }
+
++ if (!(
++ len == 0 &&
++ e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way
++ | ACMPL_MOD == ACMPL_MOD
++ ))
++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
++
+ /* 2. custom keys from config.h */
+ if ((customkey = kmap(ksym, e->state))) {
+ ttywrite(customkey, strlen(customkey), 1);
+--
+2.45.2
diff --git a/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff
new file mode 100644
index 0000000..337abf1
--- /dev/null
+++ b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff
@@ -0,0 +1,153 @@
+From feec0e2239d81373bd2ffcc28bdcf331328391f6 Mon Sep 17 00:00:00 2001
+From: Steven Ward <planet36@gmail.com>
+Date: Sat, 19 Aug 2023 08:05:36 -0500
+Subject: [PATCH] Add different cursor styles
+
+---
+ config.def.h | 19 +++++++++++++------
+ x.c | 47 +++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 48 insertions(+), 18 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..b33a2ac 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -135,13 +135,20 @@ unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
+
+ /*
+- * Default shape of cursor
+- * 2: Block ("█")
+- * 4: Underline ("_")
+- * 6: Bar ("|")
+- * 7: Snowman ("☃")
++ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
++ * Default style of cursor
++ * 0: blinking block
++ * 1: blinking block (default)
++ * 2: steady block ("█")
++ * 3: blinking underline
++ * 4: steady underline ("_")
++ * 5: blinking bar
++ * 6: steady bar ("|")
++ * 7: blinking st cursor
++ * 8: steady st cursor
+ */
+-static unsigned int cursorshape = 2;
++static unsigned int cursorstyle = 1;
++static Rune stcursor = 0x2603; /* snowman ("☃") */
+
+ /*
+ * Default columns and rows numbers
+diff --git a/x.c b/x.c
+index aa09997..b33a963 100644
+--- a/x.c
++++ b/x.c
+@@ -253,6 +253,7 @@ static char *opt_name = NULL;
+ static char *opt_title = NULL;
+
+ static uint buttons; /* bit field of pressed buttons */
++static int cursorblinks = 0;
+
+ void
+ clipcopy(const Arg *dummy)
+@@ -1558,29 +1559,44 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+ /* draw the new one */
+ if (IS_SET(MODE_FOCUSED)) {
+ switch (win.cursor) {
+- case 7: /* st extension */
+- g.u = 0x2603; /* snowman (U+2603) */
++ default:
++ case 0: /* blinking block */
++ case 1: /* blinking block (default) */
++ if (IS_SET(MODE_BLINK))
++ break;
+ /* FALLTHROUGH */
+- case 0: /* Blinking Block */
+- case 1: /* Blinking Block (Default) */
+- case 2: /* Steady Block */
++ case 2: /* steady block */
+ xdrawglyph(g, cx, cy);
+ break;
+- case 3: /* Blinking Underline */
+- case 4: /* Steady Underline */
++ case 3: /* blinking underline */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 4: /* steady underline */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + (cy + 1) * win.ch - \
+ cursorthickness,
+ win.cw, cursorthickness);
+ break;
+- case 5: /* Blinking bar */
+- case 6: /* Steady bar */
++ case 5: /* blinking bar */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 6: /* steady bar */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + cy * win.ch,
+ cursorthickness, win.ch);
+ break;
++ case 7: /* blinking st cursor */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 8: /* steady st cursor */
++ g.u = stcursor;
++ xdrawglyph(g, cx, cy);
++ break;
+ }
+ } else {
+ XftDrawRect(xw.draw, &drawcol,
+@@ -1737,9 +1753,12 @@ xsetmode(int set, unsigned int flags)
+ int
+ xsetcursor(int cursor)
+ {
+- if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
++ if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */
+ return 1;
+ win.cursor = cursor;
++ cursorblinks = win.cursor == 0 || win.cursor == 1 ||
++ win.cursor == 3 || win.cursor == 5 ||
++ win.cursor == 7;
+ return 0;
+ }
+
+@@ -1986,6 +2005,10 @@ run(void)
+ if (FD_ISSET(ttyfd, &rfd) || xev) {
+ if (!drawing) {
+ trigger = now;
++ if (IS_SET(MODE_BLINK)) {
++ win.mode ^= MODE_BLINK;
++ }
++ lastblink = now;
+ drawing = 1;
+ }
+ timeout = (maxlatency - TIMEDIFF(now, trigger)) \
+@@ -1996,7 +2019,7 @@ run(void)
+
+ /* idle detected or maxlatency exhausted -> draw */
+ timeout = -1;
+- if (blinktimeout && tattrset(ATTR_BLINK)) {
++ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) {
+ timeout = blinktimeout - TIMEDIFF(now, lastblink);
+ if (timeout <= 0) {
+ if (-timeout > blinktimeout) /* start visible */
+@@ -2032,7 +2055,7 @@ main(int argc, char *argv[])
+ {
+ xw.l = xw.t = 0;
+ xw.isfixed = False;
+- xsetcursor(cursorshape);
++ xsetcursor(cursorstyle);
+
+ ARGBEGIN {
+ case 'a':
+--
+2.41.0
+
diff --git a/st/patches/st-borderpx-option-20241008-e015463.diff b/st/patches/st-borderpx-option-20241008-e015463.diff
new file mode 100644
index 0000000..8dce419
--- /dev/null
+++ b/st/patches/st-borderpx-option-20241008-e015463.diff
@@ -0,0 +1,74 @@
+From e01546322047ad4d0c5b613dc83f1425c360839a Mon Sep 17 00:00:00 2001
+From: cedilla <cedilla@dimension.sh>
+Date: Tue, 8 Oct 2024 16:25:03 +0200
+Subject: [PATCH] Allow to set border value using for example -b 18
+
+---
+ st.1 | 8 ++++++++
+ x.c | 7 +++++--
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/st.1 b/st.1
+index 39120b4..9ad3783 100644
+--- a/st.1
++++ b/st.1
+@@ -4,6 +4,8 @@ st \- simple terminal
+ .SH SYNOPSIS
+ .B st
+ .RB [ \-aiv ]
++.RB [ \-b
++.IR borderpx ]
+ .RB [ \-c
+ .IR class ]
+ .RB [ \-f
+@@ -28,6 +30,8 @@ st \- simple terminal
+ .PP
+ .B st
+ .RB [ \-aiv ]
++.RB [ \-b
++.IR borderpx ]
+ .RB [ \-c
+ .IR class ]
+ .RB [ \-f
+@@ -55,6 +59,10 @@ is a simple terminal emulator.
+ .B \-a
+ disable alternate screens in terminal
+ .TP
++.BI \-b " borderpx"
++set border size to
++.I borderpx
++.TP
+ .BI \-c " class"
+ defines the window class (default $TERM).
+ .TP
+diff --git a/x.c b/x.c
+index d73152b..bda127c 100644
+--- a/x.c
++++ b/x.c
+@@ -2026,11 +2026,11 @@ run(void)
+ void
+ usage(void)
+ {
+- die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
++ die("usage: %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]"
+ " [-n name] [-o file]\n"
+ " [-T title] [-t title] [-w windowid]"
+ " [[-e] command [args ...]]\n"
+- " %s [-aiv] [-c class] [-f font] [-g geometry]"
++ " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]"
+ " [-n name] [-o file]\n"
+ " [-T title] [-t title] [-w windowid] -l line"
+ " [stty_args ...]\n", argv0, argv0);
+@@ -2047,6 +2047,9 @@ main(int argc, char *argv[])
+ case 'a':
+ allowaltscreen = 0;
+ break;
++ case 'b':
++ borderpx = atoi(EARGF(usage()));
++ break;
+ case 'c':
+ opt_class = EARGF(usage());
+ break;
+--
+2.45.2
+
diff --git a/st/patches/st-boxdraw_v2-0.8.5.diff b/st/patches/st-boxdraw_v2-0.8.5.diff
new file mode 100644
index 0000000..b06aa3a
--- /dev/null
+++ b/st/patches/st-boxdraw_v2-0.8.5.diff
@@ -0,0 +1,582 @@
+From 46a1124957b8de5e7f827656b64bfc3baeaa097f Mon Sep 17 00:00:00 2001
+From: wael <40663@protonmail.com>
+Date: Mon, 11 Apr 2022 17:04:30 +0300
+Subject: [PATCH] [st][patch][boxdraw] update to 0.8.5
+
+---
+ Makefile | 3 +-
+ boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++
+ boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++
+ config.def.h | 12 +++
+ st.c | 3 +
+ st.h | 10 +++
+ x.c | 21 +++--
+ 7 files changed, 451 insertions(+), 6 deletions(-)
+ create mode 100644 boxdraw.c
+ create mode 100644 boxdraw_data.h
+
+diff --git a/Makefile b/Makefile
+index 470ac86..6dfa212 100644
+--- a/Makefile
++++ b/Makefile
+@@ -4,7 +4,7 @@
+
+ include config.mk
+
+-SRC = st.c x.c
++SRC = st.c x.c boxdraw.c
+ OBJ = $(SRC:.c=.o)
+
+ all: options st
+@@ -23,6 +23,7 @@ config.h:
+
+ st.o: config.h st.h win.h
+ x.o: arg.h config.h st.h win.h
++boxdraw.o: config.h st.h boxdraw_data.h
+
+ $(OBJ): config.h config.mk
+
+diff --git a/boxdraw.c b/boxdraw.c
+new file mode 100644
+index 0000000..28a92d0
+--- /dev/null
++++ b/boxdraw.c
+@@ -0,0 +1,194 @@
++/*
++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
++ * MIT/X Consortium License
++ */
++
++#include <X11/Xft/Xft.h>
++#include "st.h"
++#include "boxdraw_data.h"
++
++/* Rounded non-negative integers division of n / d */
++#define DIV(n, d) (((n) + (d) / 2) / (d))
++
++static Display *xdpy;
++static Colormap xcmap;
++static XftDraw *xd;
++static Visual *xvis;
++
++static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
++static void drawboxlines(int, int, int, int, XftColor *, ushort);
++
++/* public API */
++
++void
++boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
++{
++ xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
++}
++
++int
++isboxdraw(Rune u)
++{
++ Rune block = u & ~0xff;
++ return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
++ (boxdraw_braille && block == 0x2800);
++}
++
++/* the "index" is actually the entire shape data encoded as ushort */
++ushort
++boxdrawindex(const Glyph *g)
++{
++ if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
++ return BRL | (uint8_t)g->u;
++ if (boxdraw_bold && (g->mode & ATTR_BOLD))
++ return BDB | boxdata[(uint8_t)g->u];
++ return boxdata[(uint8_t)g->u];
++}
++
++void
++drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
++ const XftGlyphFontSpec *specs, int len)
++{
++ for ( ; len-- > 0; x += cw, specs++)
++ drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
++}
++
++/* implementation */
++
++void
++drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
++{
++ ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
++ if (bd & (BDL | BDA)) {
++ /* lines (light/double/heavy/arcs) */
++ drawboxlines(x, y, w, h, fg, bd);
++
++ } else if (cat == BBD) {
++ /* lower (8-X)/8 block */
++ int d = DIV((uint8_t)bd * h, 8);
++ XftDrawRect(xd, fg, x, y + d, w, h - d);
++
++ } else if (cat == BBU) {
++ /* upper X/8 block */
++ XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
++
++ } else if (cat == BBL) {
++ /* left X/8 block */
++ XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
++
++ } else if (cat == BBR) {
++ /* right (8-X)/8 block */
++ int d = DIV((uint8_t)bd * w, 8);
++ XftDrawRect(xd, fg, x + d, y, w - d, h);
++
++ } else if (cat == BBQ) {
++ /* Quadrants */
++ int w2 = DIV(w, 2), h2 = DIV(h, 2);
++ if (bd & TL)
++ XftDrawRect(xd, fg, x, y, w2, h2);
++ if (bd & TR)
++ XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
++ if (bd & BL)
++ XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
++ if (bd & BR)
++ XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
++
++ } else if (bd & BBS) {
++ /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
++ int d = (uint8_t)bd;
++ XftColor xfc;
++ XRenderColor xrc = { .alpha = 0xffff };
++
++ xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
++ xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
++ xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
++
++ XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
++ XftDrawRect(xd, &xfc, x, y, w, h);
++ XftColorFree(xdpy, xvis, xcmap, &xfc);
++
++ } else if (cat == BRL) {
++ /* braille, each data bit corresponds to one dot at 2x4 grid */
++ int w1 = DIV(w, 2);
++ int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
++
++ if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
++ if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
++ if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
++ if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
++ if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
++ if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
++ if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
++ if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
++
++ }
++}
++
++void
++drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
++{
++ /* s: stem thickness. width/8 roughly matches underscore thickness. */
++ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
++ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
++ int mwh = MIN(w, h);
++ int base_s = MAX(1, DIV(mwh, 8));
++ int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
++ int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
++ int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
++ /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
++ /* The base length (per direction till edge) includes this square. */
++
++ int light = bd & (LL | LU | LR | LD);
++ int double_ = bd & (DL | DU | DR | DD);
++
++ if (light) {
++ /* d: additional (negative) length to not-draw the center */
++ /* texel - at arcs and avoid drawing inside (some) doubles */
++ int arc = bd & BDA;
++ int multi_light = light & (light - 1);
++ int multi_double = double_ & (double_ - 1);
++ /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
++ int d = arc || (multi_double && !multi_light) ? -s : 0;
++
++ if (bd & LL)
++ XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
++ if (bd & LU)
++ XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
++ if (bd & LR)
++ XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
++ if (bd & LD)
++ XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
++ }
++
++ /* double lines - also align with light to form heavy when combined */
++ if (double_) {
++ /*
++ * going clockwise, for each double-ray: p is additional length
++ * to the single-ray nearer to the previous direction, and n to
++ * the next. p and n adjust from the base length to lengths
++ * which consider other doubles - shorter to avoid intersections
++ * (p, n), or longer to draw the far-corner texel (n).
++ */
++ int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
++ if (dl) {
++ int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
++ XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
++ XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
++ }
++ if (du) {
++ int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
++ XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
++ XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
++ }
++ if (dr) {
++ int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
++ XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
++ XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
++ }
++ if (dd) {
++ int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
++ XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
++ XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
++ }
++ }
++}
+diff --git a/boxdraw_data.h b/boxdraw_data.h
+new file mode 100644
+index 0000000..7890500
+--- /dev/null
++++ b/boxdraw_data.h
+@@ -0,0 +1,214 @@
++/*
++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
++ * MIT/X Consortium License
++ */
++
++/*
++ * U+25XX codepoints data
++ *
++ * References:
++ * http://www.unicode.org/charts/PDF/U2500.pdf
++ * http://www.unicode.org/charts/PDF/U2580.pdf
++ *
++ * Test page:
++ * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
++ */
++
++/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
++/* Categories (mutually exclusive except BDB): */
++/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
++#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
++#define BDA (1<<9) /* Box Draw Arc (light) */
++
++#define BBD (1<<10) /* Box Block Down (lower) X/8 */
++#define BBL (2<<10) /* Box Block Left X/8 */
++#define BBU (3<<10) /* Box Block Upper X/8 */
++#define BBR (4<<10) /* Box Block Right X/8 */
++#define BBQ (5<<10) /* Box Block Quadrants */
++#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
++
++#define BBS (1<<14) /* Box Block Shades */
++#define BDB (1<<15) /* Box Draw is Bold */
++
++/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
++/* Heavy is light+double (literally drawing light+double align to form heavy) */
++#define LL (1<<0)
++#define LU (1<<1)
++#define LR (1<<2)
++#define LD (1<<3)
++#define LH (LL+LR)
++#define LV (LU+LD)
++
++#define DL (1<<4)
++#define DU (1<<5)
++#define DR (1<<6)
++#define DD (1<<7)
++#define DH (DL+DR)
++#define DV (DU+DD)
++
++#define HL (LL+DL)
++#define HU (LU+DU)
++#define HR (LR+DR)
++#define HD (LD+DD)
++#define HH (HL+HR)
++#define HV (HU+HD)
++
++/* (BBQ) Quadrants Top/Bottom x Left/Right */
++#define TL (1<<0)
++#define TR (1<<1)
++#define BL (1<<2)
++#define BR (1<<3)
++
++/* Data for U+2500 - U+259F except dashes/diagonals */
++static const unsigned short boxdata[256] = {
++ /* light lines */
++ [0x00] = BDL + LH, /* light horizontal */
++ [0x02] = BDL + LV, /* light vertical */
++ [0x0c] = BDL + LD + LR, /* light down and right */
++ [0x10] = BDL + LD + LL, /* light down and left */
++ [0x14] = BDL + LU + LR, /* light up and right */
++ [0x18] = BDL + LU + LL, /* light up and left */
++ [0x1c] = BDL + LV + LR, /* light vertical and right */
++ [0x24] = BDL + LV + LL, /* light vertical and left */
++ [0x2c] = BDL + LH + LD, /* light horizontal and down */
++ [0x34] = BDL + LH + LU, /* light horizontal and up */
++ [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
++ [0x74] = BDL + LL, /* light left */
++ [0x75] = BDL + LU, /* light up */
++ [0x76] = BDL + LR, /* light right */
++ [0x77] = BDL + LD, /* light down */
++
++ /* heavy [+light] lines */
++ [0x01] = BDL + HH,
++ [0x03] = BDL + HV,
++ [0x0d] = BDL + HR + LD,
++ [0x0e] = BDL + HD + LR,
++ [0x0f] = BDL + HD + HR,
++ [0x11] = BDL + HL + LD,
++ [0x12] = BDL + HD + LL,
++ [0x13] = BDL + HD + HL,
++ [0x15] = BDL + HR + LU,
++ [0x16] = BDL + HU + LR,
++ [0x17] = BDL + HU + HR,
++ [0x19] = BDL + HL + LU,
++ [0x1a] = BDL + HU + LL,
++ [0x1b] = BDL + HU + HL,
++ [0x1d] = BDL + HR + LV,
++ [0x1e] = BDL + HU + LD + LR,
++ [0x1f] = BDL + HD + LR + LU,
++ [0x20] = BDL + HV + LR,
++ [0x21] = BDL + HU + HR + LD,
++ [0x22] = BDL + HD + HR + LU,
++ [0x23] = BDL + HV + HR,
++ [0x25] = BDL + HL + LV,
++ [0x26] = BDL + HU + LD + LL,
++ [0x27] = BDL + HD + LU + LL,
++ [0x28] = BDL + HV + LL,
++ [0x29] = BDL + HU + HL + LD,
++ [0x2a] = BDL + HD + HL + LU,
++ [0x2b] = BDL + HV + HL,
++ [0x2d] = BDL + HL + LD + LR,
++ [0x2e] = BDL + HR + LL + LD,
++ [0x2f] = BDL + HH + LD,
++ [0x30] = BDL + HD + LH,
++ [0x31] = BDL + HD + HL + LR,
++ [0x32] = BDL + HR + HD + LL,
++ [0x33] = BDL + HH + HD,
++ [0x35] = BDL + HL + LU + LR,
++ [0x36] = BDL + HR + LU + LL,
++ [0x37] = BDL + HH + LU,
++ [0x38] = BDL + HU + LH,
++ [0x39] = BDL + HU + HL + LR,
++ [0x3a] = BDL + HU + HR + LL,
++ [0x3b] = BDL + HH + HU,
++ [0x3d] = BDL + HL + LV + LR,
++ [0x3e] = BDL + HR + LV + LL,
++ [0x3f] = BDL + HH + LV,
++ [0x40] = BDL + HU + LH + LD,
++ [0x41] = BDL + HD + LH + LU,
++ [0x42] = BDL + HV + LH,
++ [0x43] = BDL + HU + HL + LD + LR,
++ [0x44] = BDL + HU + HR + LD + LL,
++ [0x45] = BDL + HD + HL + LU + LR,
++ [0x46] = BDL + HD + HR + LU + LL,
++ [0x47] = BDL + HH + HU + LD,
++ [0x48] = BDL + HH + HD + LU,
++ [0x49] = BDL + HV + HL + LR,
++ [0x4a] = BDL + HV + HR + LL,
++ [0x4b] = BDL + HV + HH,
++ [0x78] = BDL + HL,
++ [0x79] = BDL + HU,
++ [0x7a] = BDL + HR,
++ [0x7b] = BDL + HD,
++ [0x7c] = BDL + HR + LL,
++ [0x7d] = BDL + HD + LU,
++ [0x7e] = BDL + HL + LR,
++ [0x7f] = BDL + HU + LD,
++
++ /* double [+light] lines */
++ [0x50] = BDL + DH,
++ [0x51] = BDL + DV,
++ [0x52] = BDL + DR + LD,
++ [0x53] = BDL + DD + LR,
++ [0x54] = BDL + DR + DD,
++ [0x55] = BDL + DL + LD,
++ [0x56] = BDL + DD + LL,
++ [0x57] = BDL + DL + DD,
++ [0x58] = BDL + DR + LU,
++ [0x59] = BDL + DU + LR,
++ [0x5a] = BDL + DU + DR,
++ [0x5b] = BDL + DL + LU,
++ [0x5c] = BDL + DU + LL,
++ [0x5d] = BDL + DL + DU,
++ [0x5e] = BDL + DR + LV,
++ [0x5f] = BDL + DV + LR,
++ [0x60] = BDL + DV + DR,
++ [0x61] = BDL + DL + LV,
++ [0x62] = BDL + DV + LL,
++ [0x63] = BDL + DV + DL,
++ [0x64] = BDL + DH + LD,
++ [0x65] = BDL + DD + LH,
++ [0x66] = BDL + DD + DH,
++ [0x67] = BDL + DH + LU,
++ [0x68] = BDL + DU + LH,
++ [0x69] = BDL + DH + DU,
++ [0x6a] = BDL + DH + LV,
++ [0x6b] = BDL + DV + LH,
++ [0x6c] = BDL + DH + DV,
++
++ /* (light) arcs */
++ [0x6d] = BDA + LD + LR,
++ [0x6e] = BDA + LD + LL,
++ [0x6f] = BDA + LU + LL,
++ [0x70] = BDA + LU + LR,
++
++ /* Lower (Down) X/8 block (data is 8 - X) */
++ [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
++ [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
++
++ /* Left X/8 block (data is X) */
++ [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
++ [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
++
++ /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
++ [0x80] = BBU + 4, [0x94] = BBU + 1,
++ [0x90] = BBR + 4, [0x95] = BBR + 7,
++
++ /* Quadrants */
++ [0x96] = BBQ + BL,
++ [0x97] = BBQ + BR,
++ [0x98] = BBQ + TL,
++ [0x99] = BBQ + TL + BL + BR,
++ [0x9a] = BBQ + TL + BR,
++ [0x9b] = BBQ + TL + TR + BL,
++ [0x9c] = BBQ + TL + TR + BR,
++ [0x9d] = BBQ + TR,
++ [0x9e] = BBQ + BL + TR,
++ [0x9f] = BBQ + BL + TR + BR,
++
++ /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
++ [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
++
++ /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
++ /* U+2571 - U+2573: unsupported (diagonals) */
++};
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..7bb3ff7 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -67,6 +67,18 @@ static unsigned int blinktimeout = 800;
+ */
+ static unsigned int cursorthickness = 2;
+
++/*
++ * 1: render most of the lines/blocks characters without using the font for
++ * perfect alignment between cells (U2500 - U259F except dashes/diagonals).
++ * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
++ * 0: disable (render all U25XX glyphs normally from the font).
++ */
++const int boxdraw = 0;
++const int boxdraw_bold = 0;
++
++/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
++const int boxdraw_braille = 0;
++
+ /*
+ * bell volume. It must be a value between -100 and 100. Use 0 for disabling
+ * it
+diff --git a/st.c b/st.c
+index f43cfd3..baa2bed 100644
+--- a/st.c
++++ b/st.c
+@@ -1214,6 +1214,9 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
+ term.dirty[y] = 1;
+ term.line[y][x] = *attr;
+ term.line[y][x].u = u;
++
++ if (isboxdraw(u))
++ term.line[y][x].mode |= ATTR_BOXDRAW;
+ }
+
+ void
+diff --git a/st.h b/st.h
+index 519b9bd..07a7c66 100644
+--- a/st.h
++++ b/st.h
+@@ -33,6 +33,7 @@ enum glyph_attribute {
+ ATTR_WRAP = 1 << 8,
+ ATTR_WIDE = 1 << 9,
+ ATTR_WDUMMY = 1 << 10,
++ ATTR_BOXDRAW = 1 << 11,
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+ };
+
+@@ -113,6 +114,14 @@ char *xstrdup(const char *);
+
+ int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
+
++int isboxdraw(Rune);
++ushort boxdrawindex(const Glyph *);
++#ifdef XFT_VERSION
++/* only exposed to x.c, otherwise we'll need Xft.h for the types */
++void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
++void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
++#endif
++
+ /* config.h globals */
+ extern char *utmp;
+ extern char *scroll;
+@@ -126,3 +135,4 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
++extern const int boxdraw, boxdraw_bold, boxdraw_braille;
+diff --git a/x.c b/x.c
+index 2a3bd38..bf6bbf9 100644
+--- a/x.c
++++ b/x.c
+@@ -1237,6 +1237,8 @@ xinit(int cols, int rows)
+ xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+ if (xsel.xtarget == None)
+ xsel.xtarget = XA_STRING;
++
++ boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
+ }
+
+ int
+@@ -1283,8 +1285,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ yp = winy + font->ascent;
+ }
+
+- /* Lookup character index with default font. */
+- glyphidx = XftCharIndex(xw.dpy, font->match, rune);
++ if (mode & ATTR_BOXDRAW) {
++ /* minor shoehorning: boxdraw uses only this ushort */
++ glyphidx = boxdrawindex(&glyphs[i]);
++ } else {
++ /* Lookup character index with default font. */
++ glyphidx = XftCharIndex(xw.dpy, font->match, rune);
++ }
+ if (glyphidx) {
+ specs[numspecs].font = font->match;
+ specs[numspecs].glyph = glyphidx;
+@@ -1488,8 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+ r.width = width;
+ XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
+
+- /* Render the glyphs. */
+- XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
++ if (base.mode & ATTR_BOXDRAW) {
++ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
++ } else {
++ /* Render the glyphs. */
++ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
++ }
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE) {
+@@ -1532,7 +1543,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+ /*
+ * Select the right color for the right mode.
+ */
+- g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
++ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
+
+ if (IS_SET(MODE_REVERSE)) {
+ g.mode |= ATTR_REVERSE;
+--
+2.35.1
diff --git a/st/patches/st-changealpha-20230519-b44f2ad.diff b/st/patches/st-changealpha-20230519-b44f2ad.diff
new file mode 100644
index 0000000..172969f
--- /dev/null
+++ b/st/patches/st-changealpha-20230519-b44f2ad.diff
@@ -0,0 +1,80 @@
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..8a06176 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -93,6 +93,9 @@ char *termname = "st-256color";
+ */
+ unsigned int tabspaces = 8;
+
++/* Background opacity */
++float alpha_def;
++
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+ /* 8 normal colors */
+@@ -201,6 +204,9 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */
++ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */
++ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */
+ };
+
+ /*
+diff --git a/st.h b/st.h
+index fd3b0d8..3bb587e 100644
+--- a/st.h
++++ b/st.h
+@@ -124,3 +124,4 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
++extern float alpha_def;
+diff --git a/x.c b/x.c
+index aa09997..f8c8c1a 100644
+--- a/x.c
++++ b/x.c
+@@ -59,6 +59,7 @@ static void zoom(const Arg *);
+ static void zoomabs(const Arg *);
+ static void zoomreset(const Arg *);
+ static void ttysend(const Arg *);
++static void chgalpha(const Arg *);
+
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+@@ -1147,6 +1148,9 @@ xinit(int cols, int rows)
+ usedfont = (opt_font == NULL)? font : opt_font;
+ xloadfonts(usedfont, 0);
+
++ /* Backup default alpha value */
++ alpha_def = alpha;
++
+ /* colors */
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ xloadcols();
+@@ -1371,6 +1375,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ return numspecs;
+ }
+
++void
++chgalpha(const Arg *arg)
++{
++ if (arg->f == -1.0f && alpha >= 0.1f)
++ alpha -= 0.1f;
++ else if (arg->f == 1.0f && alpha < 1.0f)
++ alpha += 0.1f;
++ else if (arg->f == 0.0f)
++ alpha = alpha_def;
++ else
++ return;
++
++ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha);
++ /* Required to remove artifacting from borderpx */
++ cresize(0, 0);
++ redraw();
++}
++
+ void
+ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
+ {
diff --git a/st/patches/st-charoffsets-20220311-0.8.5.diff b/st/patches/st-charoffsets-20220311-0.8.5.diff
new file mode 100644
index 0000000..4034d3f
--- /dev/null
+++ b/st/patches/st-charoffsets-20220311-0.8.5.diff
@@ -0,0 +1,43 @@
+From 944b234710e2fc00ea6e9ce9d925dc85514ac9c3 Mon Sep 17 00:00:00 2001
+From: Zacchary Dempsey-Plante <zacc@ztdp.ca>
+Date: Fri, 11 Mar 2022 01:33:05 -0500
+Subject: [PATCH] Added character rendering offsets for correcting different
+ font dimensions.
+
+---
+ config.def.h | 3 +++
+ x.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..8877e5c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -28,6 +28,9 @@ char *vtiden = "\033[?6c";
+ /* Kerning / character bounding-box multipliers */
+ static float cwscale = 1.0;
+ static float chscale = 1.0;
++/* Character rendering offsets in pixels */
++static short cxoffset = 0;
++static short cyoffset = 0;
+
+ /*
+ * word delimiter string
+diff --git a/x.c b/x.c
+index cd96575..6983743 100644
+--- a/x.c
++++ b/x.c
+@@ -1288,8 +1288,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ if (glyphidx) {
+ specs[numspecs].font = font->match;
+ specs[numspecs].glyph = glyphidx;
+- specs[numspecs].x = (short)xp;
+- specs[numspecs].y = (short)yp;
++ specs[numspecs].x = (short)xp + cxoffset;
++ specs[numspecs].y = (short)yp + cyoffset;
+ xp += runewidth;
+ numspecs++;
+ continue;
+--
+2.35.1
+
diff --git a/st/patches/st-clickurl-nocontrol-0.8.5.diff b/st/patches/st-clickurl-nocontrol-0.8.5.diff
new file mode 100644
index 0000000..018939f
--- /dev/null
+++ b/st/patches/st-clickurl-nocontrol-0.8.5.diff
@@ -0,0 +1,214 @@
+From 8d13e4a296f0b2a625df10c8ee6d2fc96ec97580 Mon Sep 17 00:00:00 2001
+From: Kyle Chui <kyle.chui+suckless@pm.me>
+Date: Tue, 9 Apr 2024 16:31:25 -0700
+Subject: [PATCH] Underline URLs and follow with click
+
+---
+ config.def.h | 11 +++++++
+ st.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ st.h | 9 ++++++
+ x.c | 12 ++++++-
+ 4 files changed, 119 insertions(+), 1 deletion(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..4961830 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -472,3 +472,14 @@ static char ascii_printable[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
++
++/*
++ * Open urls starting with urlprefixes, contatining urlchars
++ * by passing as ARG1 to urlhandler.
++ */
++char* urlhandler = "xdg-open";
++char urlchars[] =
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++ "abcdefghijklmnopqrstuvwxyz"
++ "0123456789-._~:/?#@!$&'*+,;=%";
++char* urlprefixes[] = {"http://", "https://", NULL};
+diff --git a/st.c b/st.c
+index 51049ba..a7eb86e 100644
+--- a/st.c
++++ b/st.c
+@@ -643,6 +643,92 @@ getsel(void)
+ return str;
+ }
+
++char *
++strstrany(char* s, char** strs) {
++ char *match;
++ for (int i = 0; strs[i]; i++) {
++ if ((match = strstr(s, strs[i]))) {
++ return match;
++ }
++ }
++ return NULL;
++}
++
++void
++highlighturlsline(int row)
++{
++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */
++ char *match;
++ for (int j = 0; j < term.col; j++) {
++ if (term.line[row][j].u < 127) {
++ linestr[j] = term.line[row][j].u;
++ }
++ linestr[term.col] = '\0';
++ }
++ int url_start = -1;
++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) {
++ url_start = match - linestr;
++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) {
++ term.line[row][c].mode |= ATTR_URL;
++ tsetdirt(row, c);
++ }
++ }
++ free(linestr);
++}
++
++void
++unhighlighturlsline(int row)
++{
++ for (int j = 0; j < term.col; j++) {
++ Glyph* g = &term.line[row][j];
++ if (g->mode & ATTR_URL) {
++ g->mode &= ~ATTR_URL;
++ tsetdirt(row, j);
++ }
++ }
++ return;
++}
++
++int
++followurl(int col, int row) {
++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */
++ char *match;
++ for (int i = 0; i < term.col; i++) {
++ if (term.line[row][i].u < 127) {
++ linestr[i] = term.line[row][i].u;
++ }
++ linestr[term.col] = '\0';
++ }
++ int url_start = -1, found_url = 0;
++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) {
++ url_start = match - linestr;
++ int url_end = url_start;
++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) {
++ url_end++;
++ }
++ if (url_start <= col && col < url_end) {
++ found_url = 1;
++ linestr[url_end] = '\0';
++ break;
++ }
++ }
++ if (!found_url) {
++ free(linestr);
++ return 0;
++ }
++
++ pid_t chpid;
++ if ((chpid = fork()) == 0) {
++ if (fork() == 0)
++ execlp(urlhandler, urlhandler, linestr + url_start, NULL);
++ exit(1);
++ }
++ if (chpid > 0)
++ waitpid(chpid, NULL, 0);
++ free(linestr);
++ return 1;
++}
++
+ void
+ selclear(void)
+ {
+@@ -2652,6 +2738,8 @@ drawregion(int x1, int y1, int x2, int y2)
+ continue;
+
+ term.dirty[y] = 0;
++ unhighlighturlsline(y);
++ highlighturlsline(y);
+ xdrawline(term.line[y], x1, y, x2);
+ }
+ }
+diff --git a/st.h b/st.h
+index 519b9bd..5efc27e 100644
+--- a/st.h
++++ b/st.h
+@@ -33,6 +33,7 @@ enum glyph_attribute {
+ ATTR_WRAP = 1 << 8,
+ ATTR_WIDE = 1 << 9,
+ ATTR_WDUMMY = 1 << 10,
++ ATTR_URL = 1 << 11,
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+ };
+
+@@ -105,6 +106,10 @@ void selextend(int, int, int, int);
+ int selected(int, int);
+ char *getsel(void);
+
++void highlighturlsline(int);
++void unhighlighturlsline(int);
++int followurl(int, int);
++
+ size_t utf8encode(Rune, char *);
+
+ void *xmalloc(size_t);
+@@ -126,3 +131,7 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
++extern char *urlhandler;
++extern char urlchars[];
++extern char *urlprefixes[];
++extern int nurlprefixes;
+diff --git a/x.c b/x.c
+index 8a16faa..c721f8b 100644
+--- a/x.c
++++ b/x.c
+@@ -191,6 +191,7 @@ static void usage(void);
+
+ static void (*handler[LASTEvent])(XEvent *) = {
+ [KeyPress] = kpress,
++ [KeyRelease] = kpress,
+ [ClientMessage] = cmessage,
+ [ConfigureNotify] = resize,
+ [VisibilityNotify] = visibility,
+@@ -445,6 +446,10 @@ mouseaction(XEvent *e, uint release)
+ /* ignore Button<N>mask for Button<N> - it's set on release */
+ uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
+
++ if (release == 0 && e->xbutton.button == Button1) {
++ return followurl(evcol(e), evrow(e));
++ }
++
+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+ if (ms->release == release &&
+ ms->button == e->xbutton.button &&
+@@ -1476,7 +1481,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+
+ /* Render underline and strikethrough. */
+- if (base.mode & ATTR_UNDERLINE) {
++ if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) {
+ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+ width, 1);
+ }
+@@ -1831,6 +1836,11 @@ kpress(XEvent *ev)
+ len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+ else
+ len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
++
++ /* KeyRelease not relevant to shortcuts */
++ if (ev->type == KeyRelease)
++ return;
++
+ /* 1. shortcuts */
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, e->state)) {
+--
+2.42.0
diff --git a/st/patches/st-clipboard-0.8.3.diff b/st/patches/st-clipboard-0.8.3.diff
new file mode 100644
index 0000000..c1e0e9e
--- /dev/null
+++ b/st/patches/st-clipboard-0.8.3.diff
@@ -0,0 +1,12 @@
+diff --git a/x.c b/x.c
+index e5f1737..5cabd60 100644
+--- a/x.c
++++ b/x.c
+@@ -673,6 +673,7 @@ setsel(char *str, Time t)
+ XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+ if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+ selclear();
++ clipcopy(NULL);
+ }
+
+ void
diff --git a/st/patches/st-columnredraw-20241119-fb8569b.diff b/st/patches/st-columnredraw-20241119-fb8569b.diff
new file mode 100644
index 0000000..757c795
--- /dev/null
+++ b/st/patches/st-columnredraw-20241119-fb8569b.diff
@@ -0,0 +1,79 @@
+From fb8569b193cc063ad53388e8e2009fb6682092d2 Mon Sep 17 00:00:00 2001
+From: elbachir-one <bachiralfa@gmail.com>
+Date: Tue, 19 Nov 2024 15:39:16 +0100
+Subject: [PATCH] Added columnredraw
+
+---
+ st.c | 25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+diff --git a/st.c b/st.c
+index 57c6e96..7371554 100644
+--- a/st.c
++++ b/st.c
+@@ -113,6 +113,7 @@ typedef struct {
+ typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
++ int maxcol; /* Maximum number of columns */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ int *dirty; /* dirtyness of lines */
+@@ -1231,8 +1232,8 @@ tclearregion(int x1, int y1, int x2, int y2)
+ if (y1 > y2)
+ temp = y1, y1 = y2, y2 = temp;
+
+- LIMIT(x1, 0, term.col-1);
+- LIMIT(x2, 0, term.col-1);
++ LIMIT(x1, 0, term.maxcol-1);
++ LIMIT(x2, 0, term.maxcol-1);
+ LIMIT(y1, 0, term.row-1);
+ LIMIT(y2, 0, term.row-1);
+
+@@ -2546,11 +2547,18 @@ void
+ tresize(int col, int row)
+ {
+ int i;
+- int minrow = MIN(row, term.row);
+- int mincol = MIN(col, term.col);
++ int tmp;
++ int minrow, mincol;
+ int *bp;
+ TCursor c;
+
++ tmp = col;
++ if (!term.maxcol)
++ term.maxcol = term.col;
++ col = MAX(col, term.maxcol);
++ minrow = MIN(row, term.row);
++ mincol = MIN(col, term.maxcol);
++
+ if (col < 1 || row < 1) {
+ fprintf(stderr,
+ "tresize: error resizing to %dx%d\n", col, row);
+@@ -2593,17 +2601,18 @@ tresize(int col, int row)
+ term.line[i] = xmalloc(col * sizeof(Glyph));
+ term.alt[i] = xmalloc(col * sizeof(Glyph));
+ }
+- if (col > term.col) {
+- bp = term.tabs + term.col;
++ if (col > term.maxcol) {
++ bp = term.tabs + term.maxcol;
+
+- memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
++ memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol));
+ while (--bp > term.tabs && !*bp)
+ /* nothing */ ;
+ for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+ *bp = 1;
+ }
+ /* update terminal size */
+- term.col = col;
++ term.col = tmp;
++ term.maxcol = col;
+ term.row = row;
+ /* reset scrolling region */
+ tsetscroll(0, row-1);
+--
+2.46.2
+
diff --git a/st/patches/st-copyurl-multiline-20230406-211964d.diff b/st/patches/st-copyurl-multiline-20230406-211964d.diff
new file mode 100644
index 0000000..5169c62
--- /dev/null
+++ b/st/patches/st-copyurl-multiline-20230406-211964d.diff
@@ -0,0 +1,166 @@
+From 7405bdc89e4c43cfbeabd0d4d822bc62d1e76730 Mon Sep 17 00:00:00 2001
+From: Gildasio Junior <gildasiojunior@riseup.net>
+Date: Thu, 6 Apr 2023 14:51:06 -0300
+Subject: [PATCH] Loop through urls on screen in both directions
+
+Using previous patches one can loop through urls in the screen in one
+direction: botton-up. This patch add a way that can go in the opposite
+direction: top-down.
+
+This is usefull in a screen with lots of urls.
+---
+ config.def.h | 2 +
+ st.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ st.h | 1 +
+ 3 files changed, 104 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..4df78eb 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { MODKEY, XK_l, copyurl, {.i = 0} },
++ { MODKEY|ShiftMask, XK_L, copyurl, {.i = 1} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index 134e724..c451015 100644
+--- a/st.c
++++ b/st.c
+@@ -152,6 +152,11 @@ typedef struct {
+ int narg; /* nb of args */
+ } STREscape;
+
++typedef struct {
++ int state;
++ size_t length;
++} URLdfa;
++
+ static void execsh(char *, char **);
+ static void stty(char **);
+ static void sigchld(int);
+@@ -201,6 +206,7 @@ static void tdefutf8(char);
+ static int32_t tdefcolor(const int *, int *, int);
+ static void tdeftran(char);
+ static void tstrsequence(uchar);
++static int daddch(URLdfa *, char);
+
+ static void drawregion(int, int, int, int);
+
+@@ -2666,3 +2672,98 @@ redraw(void)
+ tfulldirt();
+ draw();
+ }
++
++int
++daddch(URLdfa *dfa, char c)
++{
++ /* () and [] can appear in urls, but excluding them here will reduce false
++ * positives when figuring out where a given url ends.
++ */
++ static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++ "abcdefghijklmnopqrstuvwxyz"
++ "0123456789-._~:/?#@!$&'*+,;=%";
++ static const char RPFX[] = "//:sptth";
++
++ if (!strchr(URLCHARS, c)) {
++ dfa->length = 0;
++ dfa->state = 0;
++
++ return 0;
++ }
++
++ dfa->length++;
++
++ if (dfa->state == 2 && c == '/') {
++ dfa->state = 0;
++ } else if (dfa->state == 3 && c == 'p') {
++ dfa->state++;
++ } else if (c != RPFX[dfa->state]) {
++ dfa->state = 0;
++ return 0;
++ }
++
++ if (dfa->state++ == 7) {
++ dfa->state = 0;
++ return 1;
++ }
++
++ return 0;
++}
++
++/*
++** Select and copy the previous url on screen (do nothing if there's no url).
++*/
++void
++copyurl(const Arg *arg) {
++ int row = 0, /* row of current URL */
++ col = 0, /* column of current URL start */
++ colend = 0, /* column of last occurrence */
++ passes = 0; /* how many rows have been scanned */
++
++ const char *c = NULL,
++ *match = NULL;
++ URLdfa dfa = { 0 };
++
++ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
++ LIMIT(row, term.top, term.bot);
++
++ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
++ LIMIT(colend, 0, term.col);
++
++ /*
++ ** Scan from (term.row - 1,term.col - 1) to (0,0) and find
++ ** next occurrance of a URL
++ */
++ for (passes = 0; passes < term.row; passes++) {
++ /* Read in each column of every row until
++ ** we hit previous occurrence of URL
++ */
++ for (col = colend; col--;)
++ if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' '))
++ break;
++
++ if (col >= 0)
++ break;
++
++ /* .i = 0 --> botton-up
++ * .i = 1 --> top-down
++ */
++ if (!arg->i) {
++ if (--row < 0)
++ row = term.row - 1;
++ } else {
++ if (++row >= term.row)
++ row = 0;
++ }
++
++ colend = term.col;
++ }
++
++ if (passes < term.row) {
++ selstart(col, row, 0);
++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0);
++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1);
++ xsetsel(getsel());
++ xclipcopy();
++ }
++}
+diff --git a/st.h b/st.h
+index fd3b0d8..baa8f29 100644
+--- a/st.h
++++ b/st.h
+@@ -85,6 +85,7 @@ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+ void toggleprinter(const Arg *);
++void copyurl(const Arg *);
+
+ int tattrset(int);
+ void tnew(int, int);
+--
+2.40.0
diff --git a/st/patches/st-csi_22_23-0.8.5.diff b/st/patches/st-csi_22_23-0.8.5.diff
new file mode 100644
index 0000000..c49aa30
--- /dev/null
+++ b/st/patches/st-csi_22_23-0.8.5.diff
@@ -0,0 +1,208 @@
+From c90af45228c1100377d64ad021fa3f0cff9a1df4 Mon Sep 17 00:00:00 2001
+From: wael <40663@protonmail.com>
+Date: Mon, 11 Apr 2022 21:28:43 +0300
+Subject: [PATCH] [st][patch][csi 22 23] update to 0.8.5
+
+---
+ st.c | 36 ++++++++++++++++++++++++++++++++----
+ st.info | 4 ++--
+ win.h | 4 +++-
+ x.c | 41 ++++++++++++++++++++++++++++++++++++++---
+ 4 files changed, 75 insertions(+), 10 deletions(-)
+
+diff --git a/st.c b/st.c
+index f43cfd3..2802381 100644
+--- a/st.c
++++ b/st.c
+@@ -1801,6 +1801,33 @@ csihandle(void)
+ goto unknown;
+ }
+ break;
++ case 't': /* title stack operations */
++ switch (csiescseq.arg[0]) {
++ case 22: /* pust current title on stack */
++ switch (csiescseq.arg[1]) {
++ case 0:
++ case 1:
++ case 2:
++ xpushtitle();
++ break;
++ default:
++ goto unknown;
++ }
++ break;
++ case 23: /* pop last title from stack */
++ switch (csiescseq.arg[1]) {
++ case 0:
++ case 1:
++ case 2:
++ xsettitle(NULL, 1);
++ break;
++ default:
++ goto unknown;
++ }
++ break;
++ default:
++ goto unknown;
++ }
+ }
+ }
+
+@@ -1885,7 +1912,7 @@ strhandle(void)
+ switch (par) {
+ case 0:
+ if (narg > 1) {
+- xsettitle(strescseq.args[1]);
++ xsettitle(strescseq.args[1], 0);
+ xseticontitle(strescseq.args[1]);
+ }
+ return;
+@@ -1895,7 +1922,7 @@ strhandle(void)
+ return;
+ case 2:
+ if (narg > 1)
+- xsettitle(strescseq.args[1]);
++ xsettitle(strescseq.args[1], 0);
+ return;
+ case 52:
+ if (narg > 2 && allowwindowops) {
+@@ -1973,7 +2000,7 @@ strhandle(void)
+ }
+ break;
+ case 'k': /* old title set compatibility */
+- xsettitle(strescseq.args[0]);
++ xsettitle(strescseq.args[0], 0);
+ return;
+ case 'P': /* DCS -- Device Control String */
+ case '_': /* APC -- Application Program Command */
+@@ -2345,6 +2372,7 @@ eschandle(uchar ascii)
+ break;
+ case 'c': /* RIS -- Reset to initial state */
+ treset();
++ xfreetitlestack();
+ resettitle();
+ xloadcols();
+ break;
+@@ -2631,7 +2659,7 @@ tresize(int col, int row)
+ void
+ resettitle(void)
+ {
+- xsettitle(NULL);
++ xsettitle(NULL, 0);
+ }
+
+ void
+diff --git a/st.info b/st.info
+index 8201ad6..aeef606 100644
+--- a/st.info
++++ b/st.info
+@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor,
+ rin=\E[%p1%dT,
+ ritm=\E[23m,
+ rmacs=\E(B,
+- rmcup=\E[?1049l,
++ rmcup=\E[?1049l\E[23;0;0t,
+ rmir=\E[4l,
+ rmkx=\E[?1l\E>,
+ rmso=\E[27m,
+@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor,
+ sitm=\E[3m,
+ sgr0=\E[0m,
+ smacs=\E(0,
+- smcup=\E[?1049h,
++ smcup=\E[?1049h\E[22;0;0t,
+ smir=\E[4h,
+ smkx=\E[?1h\E=,
+ smso=\E[7m,
+diff --git a/win.h b/win.h
+index e6e4369..ef67fd6 100644
+--- a/win.h
++++ b/win.h
+@@ -31,7 +31,9 @@ void xfinishdraw(void);
+ void xloadcols(void);
+ int xsetcolorname(int, const char *);
+ void xseticontitle(char *);
+-void xsettitle(char *);
++void xfreetitlestack(void);
++void xsettitle(char *, int);
++void xpushtitle(void);
+ int xsetcursor(int);
+ void xsetmode(int, unsigned int);
+ void xsetpointermotion(int);
+diff --git a/x.c b/x.c
+index 2a3bd38..babb04c 100644
+--- a/x.c
++++ b/x.c
+@@ -63,6 +63,9 @@ static void ttysend(const Arg *);
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+
++/* size of title stack */
++#define TITLESTACKSIZE 8
++
+ /* XEMBED messages */
+ #define XEMBED_FOCUS_IN 4
+ #define XEMBED_FOCUS_OUT 5
+@@ -220,6 +223,8 @@ static DC dc;
+ static XWindow xw;
+ static XSelection xsel;
+ static TermWindow win;
++static int tstki; /* title stack index */
++static char *titlestack[TITLESTACKSIZE]; /* title stack */
+
+ /* Font Ring Cache */
+ enum {
+@@ -1626,10 +1631,30 @@ xseticontitle(char *p)
+ }
+
+ void
+-xsettitle(char *p)
++xfreetitlestack(void)
+ {
+- XTextProperty prop;
+- DEFAULT(p, opt_title);
++ for (int i = 0; i < LEN(titlestack); i++) {
++ free(titlestack[i]);
++ titlestack[i] = NULL;
++ }
++}
++
++void
++xsettitle(char *p, int pop)
++{
++ XTextProperty prop;
++
++ free(titlestack[tstki]);
++ if (pop) {
++ titlestack[tstki] = NULL;
++ tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
++ p = titlestack[tstki] ? titlestack[tstki] : opt_title;
++ } else if (p) {
++ titlestack[tstki] = xstrdup(p);
++ } else {
++ titlestack[tstki] = NULL;
++ p = opt_title;
++ }
+
+ if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop) != Success)
+@@ -1639,6 +1664,16 @@ xsettitle(char *p)
+ XFree(prop.value);
+ }
+
++void
++xpushtitle(void)
++{
++ int tstkin = (tstki + 1) % TITLESTACKSIZE;
++
++ free(titlestack[tstkin]);
++ titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
++ tstki = tstkin;
++}
++
+ int
+ xstartdraw(void)
+ {
+--
+2.35.1
+
diff --git a/st/patches/st-cyclefonts-20220731-baa9357.diff b/st/patches/st-cyclefonts-20220731-baa9357.diff
new file mode 100644
index 0000000..1f0297b
--- /dev/null
+++ b/st/patches/st-cyclefonts-20220731-baa9357.diff
@@ -0,0 +1,97 @@
+From 3c83f90504445efb358f18b4ae86193c6baa709c Mon Sep 17 00:00:00 2001
+From: Justinas Grigas <jstn_as@protonmail.com>
+Date: Sun, 31 Jul 2022 10:43:14 +0300
+Subject: [PATCH] cyclefonts: keybind to cycle fonts
+
+This patch is an update to the 20210604, which fixes zoomreset.
+
+Because the cyclefonts function doesn't change the defaultfontsize
+variable, zoomreset function resets all fonts to the size of the first
+one loaded.
+
+With this patch, zoomreset will reset the font to the specified fontsize
+---
+ config.def.h | 7 ++++++-
+ x.c | 20 ++++++++++++++------
+ 2 files changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..c213e48 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -5,7 +5,11 @@
+ *
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
+-static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
++static char *fonts[] = {
++ "Liberation Mono:pixelsize=12:antialias=true:autohint=true",
++ "Gohu GohuFont:pixelsize=11:antialias=false:autohint=false",
++};
++static size_t currentfont = 0;
+ static int borderpx = 2;
+
+ /*
+@@ -201,6 +205,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { TERMMOD, XK_S, cyclefonts, {} },
+ };
+
+ /*
+diff --git a/x.c b/x.c
+index 2a3bd38..08f7275 100644
+--- a/x.c
++++ b/x.c
+@@ -59,6 +59,7 @@ static void zoom(const Arg *);
+ static void zoomabs(const Arg *);
+ static void zoomreset(const Arg *);
+ static void ttysend(const Arg *);
++static void cyclefonts(const Arg *);
+
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+@@ -315,11 +316,7 @@ void
+ zoomreset(const Arg *arg)
+ {
+ Arg larg;
+-
+- if (defaultfontsize > 0) {
+- larg.f = defaultfontsize;
+- zoomabs(&larg);
+- }
++ zoomabs(&larg);
+ }
+
+ void
+@@ -328,6 +325,17 @@ ttysend(const Arg *arg)
+ ttywrite(arg->s, strlen(arg->s), 1);
+ }
+
++void
++cyclefonts(const Arg *arg)
++{
++ currentfont++;
++ currentfont %= (sizeof fonts / sizeof fonts[0]);
++ usedfont = fonts[currentfont];
++ Arg larg;
++ larg.f = usedfontsize;
++ zoomabs(&larg);
++}
++
+ int
+ evcol(XEvent *e)
+ {
+@@ -1144,7 +1152,7 @@ xinit(int cols, int rows)
+ if (!FcInit())
+ die("could not init fontconfig.\n");
+
+- usedfont = (opt_font == NULL)? font : opt_font;
++ usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font;
+ xloadfonts(usedfont, 0);
+
+ /* colors */
+--
+2.37.1
+
diff --git a/st/patches/st-disable-bold-italic-fonts-0.8.2.diff b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff
new file mode 100644
index 0000000..385f1b4
--- /dev/null
+++ b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff
@@ -0,0 +1,70 @@
+From 0856fbfcdae3f8e48db791984591b0bb8a91de68 Mon Sep 17 00:00:00 2001
+From: Ryan Kes <alrayyes@gmail.com>
+Date: Fri, 29 Mar 2019 10:59:09 +0100
+Subject: [PATCH] st-disable-bold-italic-fonts-0.8.2
+
+---
+ config.def.h | 6 ++++++
+ x.c | 10 +++++++++-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/config.def.h b/config.def.h
+index 482901e..4f5aeac 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -6,6 +6,12 @@
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
+ static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
++
++/* disable bold, italic and roman fonts globally */
++int disablebold = 0;
++int disableitalic = 0;
++int disableroman = 0;
++
+ static int borderpx = 2;
+
+ /*
+diff --git a/x.c b/x.c
+index 5828a3b..9663fa6 100644
+--- a/x.c
++++ b/x.c
+@@ -233,6 +233,11 @@ static char *usedfont = NULL;
+ static double usedfontsize = 0;
+ static double defaultfontsize = 0;
+
++/* declared in config.h */
++extern int disablebold;
++extern int disableitalic;
++extern int disableroman;
++
+ static char *opt_class = NULL;
+ static char **opt_cmd = NULL;
+ static char *opt_embed = NULL;
+@@ -966,17 +971,20 @@ xloadfonts(char *fontstr, double fontsize)
+ win.ch = ceilf(dc.font.height * chscale);
+
+ FcPatternDel(pattern, FC_SLANT);
+- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
++ if (!disableitalic)
++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (xloadfont(&dc.ifont, pattern))
+ die("can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_WEIGHT);
+- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
++ if (!disablebold)
++ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (xloadfont(&dc.ibfont, pattern))
+ die("can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_SLANT);
+- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
++ if (!disableroman)
++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ if (xloadfont(&dc.bfont, pattern))
+ die("can't open font %s\n", fontstr);
+
+--
+2.39.2
+
diff --git a/st/patches/st-dynamic-cursor-color-0.9.diff b/st/patches/st-dynamic-cursor-color-0.9.diff
new file mode 100644
index 0000000..1034595
--- /dev/null
+++ b/st/patches/st-dynamic-cursor-color-0.9.diff
@@ -0,0 +1,50 @@
+From 215ec30d6b5fe3319f88f1c9d16a37b6e14e5a53 Mon Sep 17 00:00:00 2001
+From: Bakkeby <bakkeby@gmail.com>
+Date: Mon, 19 Dec 2022 10:20:47 +0100
+Subject: [PATCH] dynamic cursor color: cursor color taken from current
+ character
+
+---
+ x.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+diff --git a/x.c b/x.c
+index 2a3bd38..21aadce 100644
+--- a/x.c
++++ b/x.c
+@@ -1520,6 +1520,7 @@ void
+ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+ {
+ Color drawcol;
++ XRenderColor colbg;
+
+ /* remove the old cursor */
+ if (selected(ox, oy))
+@@ -1548,11 +1549,21 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+ if (selected(cx, cy)) {
+ g.fg = defaultfg;
+ g.bg = defaultrcs;
++ } else if (!(og.mode & ATTR_REVERSE)) {
++ unsigned long col = g.bg;
++ g.bg = g.fg;
++ g.fg = col;
++ }
++
++ if (IS_TRUECOL(g.bg)) {
++ colbg.alpha = 0xffff;
++ colbg.red = TRUERED(g.bg);
++ colbg.green = TRUEGREEN(g.bg);
++ colbg.blue = TRUEBLUE(g.bg);
++ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol);
+ } else {
+- g.fg = defaultbg;
+- g.bg = defaultcs;
++ drawcol = dc.col[g.bg];
+ }
+- drawcol = dc.col[g.bg];
+ }
+
+ /* draw the new one */
+--
+2.38.1
+
diff --git a/st/patches/st-externalpipe-0.8.5.diff b/st/patches/st-externalpipe-0.8.5.diff
new file mode 100644
index 0000000..daf91d3
--- /dev/null
+++ b/st/patches/st-externalpipe-0.8.5.diff
@@ -0,0 +1,104 @@
+diff --git a/st.c b/st.c
+index 034954d..98f2589 100644
+--- a/st.c
++++ b/st.c
+@@ -718,8 +718,14 @@ sigchld(int a)
+ if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
+ die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
+
+- if (pid != p)
++ if (pid != p) {
++ if (p == 0 && wait(&stat) < 0)
++ die("wait: %s\n", strerror(errno));
++
++ /* reinstall sigchld handler */
++ signal(SIGCHLD, sigchld);
+ return;
++ }
+
+ if (WIFEXITED(stat) && WEXITSTATUS(stat))
+ die("child exited with status %d\n", WEXITSTATUS(stat));
+@@ -803,7 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
+ break;
+ default:
+ #ifdef __OpenBSD__
+- if (pledge("stdio rpath tty proc", NULL) == -1)
++ if (pledge("stdio rpath tty proc exec", NULL) == -1)
+ die("pledge\n");
+ #endif
+ close(s);
+@@ -1991,6 +1997,59 @@ strparse(void)
+ }
+ }
+
++void
++externalpipe(const Arg *arg)
++{
++ int to[2];
++ char buf[UTF_SIZ];
++ void (*oldsigpipe)(int);
++ Glyph *bp, *end;
++ int lastpos, n, newline;
++
++ if (pipe(to) == -1)
++ return;
++
++ switch (fork()) {
++ case -1:
++ close(to[0]);
++ close(to[1]);
++ return;
++ case 0:
++ dup2(to[0], STDIN_FILENO);
++ close(to[0]);
++ close(to[1]);
++ execvp(((char **)arg->v)[0], (char **)arg->v);
++ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
++ perror("failed");
++ exit(0);
++ }
++
++ close(to[0]);
++ /* ignore sigpipe for now, in case child exists early */
++ oldsigpipe = signal(SIGPIPE, SIG_IGN);
++ newline = 0;
++ for (n = 0; n < term.row; n++) {
++ bp = term.line[n];
++ lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
++ if (lastpos < 0)
++ break;
++ end = &bp[lastpos + 1];
++ for (; bp < end; ++bp)
++ if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
++ break;
++ if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
++ continue;
++ if (xwrite(to[1], "\n", 1) < 0)
++ break;
++ newline = 0;
++ }
++ if (newline)
++ (void)xwrite(to[1], "\n", 1);
++ close(to[1]);
++ /* restore */
++ signal(SIGPIPE, oldsigpipe);
++}
++
+ void
+ strdump(void)
+ {
+diff --git a/st.h b/st.h
+index fd3b0d8..754cd08 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,7 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void externalpipe(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+--
+2.42.0
+
diff --git a/st/patches/st-externalpipe-eternal-0.8.3.diff b/st/patches/st-externalpipe-eternal-0.8.3.diff
new file mode 100644
index 0000000..4ba830b
--- /dev/null
+++ b/st/patches/st-externalpipe-eternal-0.8.3.diff
@@ -0,0 +1,74 @@
+From 2228468a6db1e648c69849860d30867c0e77650e Mon Sep 17 00:00:00 2001
+From: AtomToast <reg-2@t-online.de>
+Date: Wed, 29 Apr 2020 02:31:29 +0200
+Subject: [PATCH] apply Luke Smiths external pipe eternal patch
+
+Enables external pipe to work on the entire scrollback history.
+
+Source: https://github.com/LukeSmithxyz/st/commit/da13ef12463d1870caed94584db464d68c6b3182
+Made to work on semi-vanilla st.
+
+This patch requires both externalpipe and scrollback patch in order to work
+---
+ st.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+diff --git a/st.c b/st.c
+index d4c88a2..2716f44 100644
+--- a/st.c
++++ b/st.c
+@@ -46,6 +46,7 @@
+ #define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
+ term.line[(y) - term.scr])
++#define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)])
+
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+@@ -431,6 +432,20 @@ tlinelen(int y)
+ return i;
+ }
+
++int
++tlinehistlen(int y)
++{
++ int i = term.col;
++
++ if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP)
++ return i;
++
++ while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ')
++ --i;
++
++ return i;
++}
++
+ void
+ selstart(int col, int row, int snap)
+ {
+@@ -2025,16 +2040,18 @@ externalpipe(const Arg *arg)
+ /* ignore sigpipe for now, in case child exists early */
+ oldsigpipe = signal(SIGPIPE, SIG_IGN);
+ newline = 0;
+- for (n = 0; n < term.row; n++) {
+- bp = term.line[n];
+- lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
++ for (n = 0; n <= HISTSIZE + 2; n++) {
++ bp = TLINE_HIST(n);
++ lastpos = MIN(tlinehistlen(n) + 1, term.col) - 1;
+ if (lastpos < 0)
+ break;
++ if (lastpos == 0)
++ continue;
+ end = &bp[lastpos + 1];
+ for (; bp < end; ++bp)
+ if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
+ break;
+- if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
++ if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP))
+ continue;
+ if (xwrite(to[1], "\n", 1) < 0)
+ break;
+--
+2.26.2
+
diff --git a/st/patches/st-externalpipe-signal-0.8.2.diff b/st/patches/st-externalpipe-signal-0.8.2.diff
new file mode 100644
index 0000000..c573d51
--- /dev/null
+++ b/st/patches/st-externalpipe-signal-0.8.2.diff
@@ -0,0 +1,74 @@
+From df32a82e8a889629ed406ce468f24c35da7e9a03 Mon Sep 17 00:00:00 2001
+From: Miles Alan <m@milesalan.com>
+Date: Sun, 11 Aug 2019 21:33:55 -0500
+Subject: [PATCH] Add handler for SIGUSR1 signal to run an externalpipe command
+
+---
+ config.def.h | 1 +
+ st.c | 14 ++++++++++++++
+ st.h | 1 +
+ 3 files changed, 16 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 0e01717..96d1bdd 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -1,3 +1,4 @@
++char *externalpipe_sigusr1[] = {"/bin/sh", "-c", "externalpipe_buffer.sh st_strings_read"};
+ /* See LICENSE file for copyright and license details. */
+
+ /*
+diff --git a/st.c b/st.c
+index b8e6077..48cae2e 100644
+--- a/st.c
++++ b/st.c
+@@ -155,6 +155,7 @@ typedef struct {
+ static void execsh(char *, char **);
+ static void stty(char **);
+ static void sigchld(int);
++static void sigusr1(int);
+ static void ttywriteraw(const char *, size_t);
+
+ static void csidump(void);
+@@ -719,6 +720,13 @@ execsh(char *cmd, char **args)
+ _exit(1);
+ }
+
++void
++sigusr1(int unused)
++{
++ static Arg a = {.v = externalpipe_sigusr1};
++ externalpipe(&a);
++}
++
+ void
+ sigchld(int a)
+ {
+@@ -765,6 +773,12 @@ stty(char **args)
+ int
+ ttynew(char *line, char *cmd, char *out, char **args)
+ {
++ static struct sigaction sa;
++ sa.sa_handler = sigusr1;
++ sigemptyset(&sa.sa_mask);
++ sa.sa_flags = SA_RESTART;
++ sigaction(SIGUSR1, &sa, NULL);
++
+ int m, s;
+
+ if (out) {
+diff --git a/st.h b/st.h
+index 38c61c4..794b4ff 100644
+--- a/st.h
++++ b/st.h
+@@ -111,6 +111,7 @@ void *xrealloc(void *, size_t);
+ char *xstrdup(char *);
+
+ /* config.h globals */
++extern char *externalpipe_sigusr1[];
+ extern char *utmp;
+ extern char *stty_args;
+ extern char *vtiden;
+--
+2.19.2
+
diff --git a/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff
new file mode 100644
index 0000000..50bada0
--- /dev/null
+++ b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff
@@ -0,0 +1,760 @@
+Author: Jan Christoph Ebersbach <jceb@e-jc.de>
+URL: http://st.suckless.org/patches/fix_keyboard_input
+Fix keyboard input on terminal
+
+Index: st-patches/st/config.def.h
+===================================================================
+--- a/config.def.h
++++ b/config.def.h
+@@ -209,7 +209,80 @@ Shortcut shortcuts[] = {
+ * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
+ * to be mapped below, add them to this array.
+ */
+-static KeySym mappedkeys[] = { -1 };
++static KeySym mappedkeys[] = {
++ XK_space,
++ XK_m,
++ XK_i,
++ XK_A,
++ XK_B,
++ XK_C,
++ XK_D,
++ XK_E,
++ XK_F,
++ XK_G,
++ XK_H,
++ XK_I,
++ XK_K,
++ XK_J,
++ XK_L,
++ XK_M,
++ XK_N,
++ XK_O,
++ XK_P,
++ XK_Q,
++ XK_R,
++ XK_S,
++ XK_T,
++ XK_U,
++ XK_V,
++ XK_W,
++ XK_X,
++ XK_Y,
++ XK_Z,
++ XK_Z,
++ XK_0,
++ XK_1,
++ XK_2,
++ XK_3,
++ XK_4,
++ XK_5,
++ XK_6,
++ XK_7,
++ XK_8,
++ XK_9,
++ XK_exclam,
++ XK_quotedbl,
++ XK_numbersign,
++ XK_dollar,
++ XK_percent,
++ XK_ampersand,
++ XK_apostrophe,
++ XK_parenleft,
++ XK_parenright,
++ XK_asterisk,
++ XK_plus,
++ XK_comma,
++ XK_minus,
++ XK_period,
++ XK_slash,
++ XK_colon,
++ XK_semicolon,
++ XK_less,
++ XK_equal,
++ XK_greater,
++ XK_question,
++ XK_at,
++ XK_bracketleft,
++ XK_backslash,
++ XK_bracketright,
++ XK_asciicircum,
++ XK_underscore,
++ XK_grave,
++ XK_braceleft,
++ XK_bar,
++ XK_braceright,
++ XK_asciitilde,
++};
+
+ /*
+ * State bits to ignore when matching key or button events. By default,
+@@ -232,59 +305,20 @@ static Key key[] = {
+ /* keysym mask string appkey appcursor */
+ { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
+- { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
+- { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+- { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
+- { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
+- { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
+- { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
+- { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
+- { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
+- { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
+- { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
+- { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
+- { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
+- { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
+- { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
+- { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+- { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
+ { XK_KP_End, ControlMask, "\033[J", -1, 0},
+ { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_KP_End, ShiftMask, "\033[K", -1, 0},
+ { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
+- { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
+- { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
+- { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+- { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+- { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
+- { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
+- { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
+- { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
+- { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
+- { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
+- { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
+- { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
+- { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
+- { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
+- { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
+- { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
+- { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
+- { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
+- { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
+- { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
+- { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
+ { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
+ { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
+ { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
+@@ -323,35 +356,26 @@ static Key key[] = {
+ { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
+ { XK_Return, Mod1Mask, "\033\r", 0, 0},
+- { XK_Return, XK_ANY_MOD, "\r", 0, 0},
++ { XK_Return, XK_NO_MOD, "\r", 0, 0},
+ { XK_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
+- { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+- { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { XK_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
+- { XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
+- { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+ { XK_End, ControlMask, "\033[J", -1, 0},
+ { XK_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_End, ShiftMask, "\033[K", -1, 0},
+ { XK_End, ShiftMask, "\033[1;2F", +1, 0},
+- { XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
+ { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
+- { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+ { XK_Next, ControlMask, "\033[6;5~", 0, 0},
+ { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
+- { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
+ { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
+ { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
+@@ -438,6 +462,572 @@ static Key key[] = {
+ { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
+ { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
+ { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
++
++ // libtermkey compatible keyboard input
++ { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1},
++ { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1},
++ { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0},
++ { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0},
++ { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0},
++ { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0},
++ { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0},
++ { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0},
++ { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0},
++ { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0},
++ { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1},
++ { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1},
++ { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0},
++ { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0},
++ { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0},
++ { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0},
++ { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0},
++ { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0},
++ { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0},
++ { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0},
++ { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1},
++ { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1},
++ { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0},
++ { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0},
++ { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0},
++ { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0},
++ { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0},
++ { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0},
++ { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0},
++ { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0},
++ { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1},
++ { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1},
++ { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0},
++ { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0},
++ { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0},
++ { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0},
++ { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0},
++ { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0},
++ { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0},
++ { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0},
++ { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1},
++ { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1},
++ { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0},
++ { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0},
++ { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0},
++ { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0},
++ { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0},
++ { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0},
++ { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0},
++ { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0},
++ { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0},
++ { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0},
++ { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0},
++ { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0},
++ { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0},
++ { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0},
++ { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0},
++ { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0},
++ { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0},
++ { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0},
++ { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0},
++ { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0},
++ { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0},
++ { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0},
++ { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0},
++ { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0},
++ { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0},
++ { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0},
++ { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0},
++ { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0},
++ { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0},
++ { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0},
++ { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0},
++ { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0},
++ { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0},
++ { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0},
++ { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0},
++ { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0},
++ { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0},
++ { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0},
++ { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0},
++ { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0},
++ { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0},
++ { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0},
++ { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0},
++ { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0},
++ { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0},
++ { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0},
++ { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0},
++ { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0},
++ { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0},
++ { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0},
++ { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0},
++ { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0},
++ { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0},
++ { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0},
++ { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0},
++ { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0},
++ { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0},
++ { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0},
++ { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0},
++ { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0},
++ { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0},
++ { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0},
++ { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0},
++ { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0},
++ { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0},
++ { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0},
++ { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0},
++ { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0},
++ { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0},
++ { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0},
++ { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0},
++ { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0},
++ { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0},
++ { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0},
++ { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0},
++ { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0},
++ { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0},
++ { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0},
++ { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0},
++ { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0},
++ { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0},
++ { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0},
++ { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0},
++ { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0},
++ { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0},
++ { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0},
++ { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0},
++ { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0},
++ { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0},
++ { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0},
++ { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0},
++ { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0},
++ { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0},
++ { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0},
++ { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0},
++ { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0},
++ { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0},
++ { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0},
++ { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0},
++ { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0},
++ { XK_KP_0, ControlMask, "\033[176;5u", 0, 0},
++ { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0},
++ { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0},
++ { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0},
++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0},
++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0},
++ { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0},
++ { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0},
++ { XK_KP_0, ControlMask, "\033[177;5u", 0, 0},
++ { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0},
++ { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0},
++ { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0},
++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0},
++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0},
++ { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0},
++ { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0},
++ { XK_KP_2, ControlMask, "\033[178;5u", 0, 0},
++ { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0},
++ { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0},
++ { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0},
++ { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0},
++ { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0},
++ { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0},
++ { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0},
++ { XK_KP_3, ControlMask, "\033[179;5u", 0, 0},
++ { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0},
++ { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0},
++ { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0},
++ { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0},
++ { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0},
++ { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0},
++ { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0},
++ { XK_KP_4, ControlMask, "\033[180;5u", 0, 0},
++ { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0},
++ { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0},
++ { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0},
++ { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0},
++ { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0},
++ { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0},
++ { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0},
++ { XK_KP_5, ControlMask, "\033[181;5u", 0, 0},
++ { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0},
++ { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0},
++ { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0},
++ { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0},
++ { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0},
++ { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0},
++ { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0},
++ { XK_KP_6, ControlMask, "\033[182;5u", 0, 0},
++ { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0},
++ { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0},
++ { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0},
++ { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0},
++ { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0},
++ { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0},
++ { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0},
++ { XK_KP_7, ControlMask, "\033[183;5u", 0, 0},
++ { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0},
++ { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0},
++ { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0},
++ { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0},
++ { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0},
++ { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0},
++ { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0},
++ { XK_KP_8, ControlMask, "\033[184;5u", 0, 0},
++ { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0},
++ { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0},
++ { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0},
++ { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0},
++ { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0},
++ { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0},
++ { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0},
++ { XK_KP_9, ControlMask, "\033[185;5u", 0, 0},
++ { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0},
++ { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0},
++ { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0},
++ { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0},
++ { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0},
++ { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0},
++ { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0},
++ { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0},
++ { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0},
++ { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0},
++ { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0},
++ { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0},
++ { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0},
++ { XK_Tab, ControlMask, "\033[9;5u", 0, 0},
++ { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0},
++ { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0},
++ { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0},
++ { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0},
++ { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0},
++ { XK_Return, ControlMask, "\033[13;5u", 0, 0},
++ { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0},
++ { XK_Return, Mod1Mask, "\033[13;3u", 0, 0},
++ { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0},
++ { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0},
++ { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0},
++ { XK_Return, ShiftMask, "\033[13;2u", 0, 0},
++ { XK_Pause, ControlMask, "\033[18;5u", 0, 0},
++ { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0},
++ { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0},
++ { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0},
++ { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0},
++ { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0},
++ { XK_Pause, ShiftMask, "\033[18;2u", 0, 0},
++ { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0},
++ { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0},
++ { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0},
++ { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0},
++ { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0},
++ { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0},
++ { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0},
++ { XK_Escape, ControlMask, "\033[27;5u", 0, 0},
++ { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0},
++ { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0},
++ { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0},
++ { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0},
++ { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0},
++ { XK_Escape, ShiftMask, "\033[27;2u", 0, 0},
++ { XK_Home, XK_NO_MOD, "\033[H", 0, -1},
++ { XK_Home, XK_NO_MOD, "\033[1~", 0, +1},
++ { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
++ { XK_Home, Mod1Mask, "\033[80;3u", 0, 0},
++ { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0},
++ { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0},
++ { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0},
++ { XK_End, XK_NO_MOD, "\033[4~", 0, 0},
++ { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
++ { XK_End, Mod1Mask, "\033[87;3u", 0, 0},
++ { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0},
++ { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0},
++ { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0},
++ { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0},
++ { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
++ { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0},
++ { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0},
++ { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0},
++ { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0},
++ { XK_Next, XK_NO_MOD, "\033[6~", 0, 0},
++ { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
++ { XK_Next, Mod1Mask, "\033[86;3u", 0, 0},
++ { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0},
++ { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0},
++ { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0},
++ { XK_Print, ControlMask, "\033[97;5u", 0, 0},
++ { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0},
++ { XK_Print, Mod1Mask, "\033[97;3u", 0, 0},
++ { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0},
++ { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0},
++ { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0},
++ { XK_Print, ShiftMask, "\033[97;2u", 0, 0},
++ { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0},
++ { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0},
++ { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0},
++ { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0},
++ { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0},
++ { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0},
++ { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0},
++ { XK_Menu, ControlMask, "\033[103;5u", 0, 0},
++ { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0},
++ { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0},
++ { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0},
++ { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0},
++ { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0},
++ { XK_Menu, ShiftMask, "\033[103;2u", 0, 0},
++ { XK_Delete, XK_NO_MOD, "\033[P", -1, 0},
++ { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0},
++ { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0},
++ { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0},
++ { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0},
++ { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0},
++ { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0},
++ { XK_i, ControlMask, "\033[105;5u", 0, 0},
++ { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0},
++ { XK_m, ControlMask, "\033[109;5u", 0, 0},
++ { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0},
++ { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0},
++ { XK_space, Mod1Mask, "\033[32;3u", 0, 0},
++ { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0},
++ { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0},
++ { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0},
++ { XK_space, ShiftMask, "\033[32;2u", 0, 0},
++ { XK_0, ControlMask, "\033[48;5u", 0, 0},
++ { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0},
++ { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0},
++ { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0},
++ { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0},
++ { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0},
++ { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0},
++ { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0},
++ { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0},
++ { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0},
++ { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0},
++ { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0},
++ { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0},
++ { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0},
++ { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0},
++ { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0},
++ { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0},
++ { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0},
++ { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
++ { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0},
++ { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0},
++ { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0},
++ { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0},
++ { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
++ { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
++ { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
++ { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0},
++ { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0},
++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0},
++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0},
++ { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0},
++ { XK_1, ControlMask, "\033[49;5u", 0, 0},
++ { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0},
++ { XK_2, ControlMask, "\033[50;5u", 0, 0},
++ { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0},
++ { XK_3, ControlMask, "\033[51;5u", 0, 0},
++ { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0},
++ { XK_4, ControlMask, "\033[52;5u", 0, 0},
++ { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0},
++ { XK_5, ControlMask, "\033[53;5u", 0, 0},
++ { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0},
++ { XK_6, ControlMask, "\033[54;5u", 0, 0},
++ { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0},
++ { XK_7, ControlMask, "\033[55;5u", 0, 0},
++ { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0},
++ { XK_8, ControlMask, "\033[56;5u", 0, 0},
++ { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0},
++ { XK_9, ControlMask, "\033[57;5u", 0, 0},
++ { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0},
++ { XK_ampersand, ControlMask, "\033[38;5u", 0, 0},
++ { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0},
++ { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0},
++ { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0},
++ { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0},
++ { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0},
++ { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0},
++ { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0},
++ { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0},
++ { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0},
++ { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0},
++ { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0},
++ { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0},
++ { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0},
++ { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0},
++ { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0},
++ { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0},
++ { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0},
++ { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0},
++ { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0},
++ { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0},
++ { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0},
++ { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0},
++ { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0},
++ { XK_asterisk, ControlMask, "\033[42;5u", 0, 0},
++ { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0},
++ { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0},
++ { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0},
++ { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0},
++ { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0},
++ { XK_at, ControlMask, "\033[64;5u", 0, 0},
++ { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0},
++ { XK_at, Mod1Mask, "\033[64;3u", 0, 0},
++ { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0},
++ { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0},
++ { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0},
++ { XK_backslash, ControlMask, "\033[92;5u", 0, 0},
++ { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0},
++ { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0},
++ { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0},
++ { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0},
++ { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0},
++ { XK_bar, ControlMask, "\033[124;5u", 0, 0},
++ { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0},
++ { XK_bar, Mod1Mask, "\033[124;3u", 0, 0},
++ { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0},
++ { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0},
++ { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0},
++ { XK_braceleft, ControlMask, "\033[123;5u", 0, 0},
++ { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0},
++ { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0},
++ { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0},
++ { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0},
++ { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0},
++ { XK_braceright, ControlMask, "\033[125;5u", 0, 0},
++ { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0},
++ { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0},
++ { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0},
++ { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0},
++ { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0},
++ { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0},
++ { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0},
++ { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0},
++ { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0},
++ { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0},
++ { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0},
++ { XK_bracketright, ControlMask, "\033[93;5u", 0, 0},
++ { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0},
++ { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0},
++ { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0},
++ { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0},
++ { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0},
++ { XK_colon, ControlMask, "\033[58;5u", 0, 0},
++ { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0},
++ { XK_colon, Mod1Mask, "\033[58;3u", 0, 0},
++ { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0},
++ { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0},
++ { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0},
++ { XK_comma, ControlMask, "\033[44;5u", 0, 0},
++ { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0},
++ { XK_comma, Mod1Mask, "\033[44;3u", 0, 0},
++ { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0},
++ { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0},
++ { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0},
++ { XK_dollar, ControlMask, "\033[36;5u", 0, 0},
++ { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0},
++ { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0},
++ { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0},
++ { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0},
++ { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0},
++ { XK_equal, ControlMask, "\033[61;5u", 0, 0},
++ { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0},
++ { XK_equal, Mod1Mask, "\033[61;3u", 0, 0},
++ { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0},
++ { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0},
++ { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0},
++ { XK_exclam, ControlMask, "\033[33;5u", 0, 0},
++ { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0},
++ { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0},
++ { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0},
++ { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0},
++ { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0},
++ { XK_grave, ControlMask, "\033[96;5u", 0, 0},
++ { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0},
++ { XK_grave, Mod1Mask, "\033[96;3u", 0, 0},
++ { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0},
++ { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0},
++ { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0},
++ { XK_greater, ControlMask, "\033[62;5u", 0, 0},
++ { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0},
++ { XK_greater, Mod1Mask, "\033[62;3u", 0, 0},
++ { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0},
++ { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0},
++ { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0},
++ { XK_less, ControlMask, "\033[60;5u", 0, 0},
++ { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0},
++ { XK_less, Mod1Mask, "\033[60;3u", 0, 0},
++ { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0},
++ { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0},
++ { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0},
++ { XK_minus, ControlMask, "\033[45;5u", 0, 0},
++ { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0},
++ { XK_minus, Mod1Mask, "\033[45;3u", 0, 0},
++ { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0},
++ { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0},
++ { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0},
++ { XK_numbersign, ControlMask, "\033[35;5u", 0, 0},
++ { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0},
++ { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0},
++ { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0},
++ { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0},
++ { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0},
++ { XK_parenleft, ControlMask, "\033[40;5u", 0, 0},
++ { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0},
++ { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0},
++ { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0},
++ { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0},
++ { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0},
++ { XK_parenright, ControlMask, "\033[41;5u", 0, 0},
++ { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0},
++ { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0},
++ { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0},
++ { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0},
++ { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0},
++ { XK_percent, ControlMask, "\033[37;5u", 0, 0},
++ { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0},
++ { XK_percent, Mod1Mask, "\033[37;3u", 0, 0},
++ { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0},
++ { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0},
++ { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0},
++ { XK_period, ControlMask, "\033[46;5u", 0, 0},
++ { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0},
++ { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0},
++ { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0},
++ { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0},
++ { XK_plus, ControlMask, "\033[43;5u", 0, 0},
++ { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0},
++ { XK_plus, Mod1Mask, "\033[43;3u", 0, 0},
++ { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0},
++ { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0},
++ { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0},
++ { XK_question, ControlMask, "\033[63;5u", 0, 0},
++ { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0},
++ { XK_question, Mod1Mask, "\033[63;3u", 0, 0},
++ { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0},
++ { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0},
++ { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0},
++ { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0},
++ { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0},
++ { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0},
++ { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0},
++ { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0},
++ { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0},
++ { XK_semicolon, ControlMask, "\033[59;5u", 0, 0},
++ { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0},
++ { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0},
++ { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0},
++ { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0},
++ { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0},
++ { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0},
++ { XK_slash, Mod1Mask, "\033[47;3u", 0, 0},
++ { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0},
++ { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0},
++ { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0},
++ { XK_underscore, ControlMask, "\033[95;5u", 0, 0},
++ { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0},
++ { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0},
++ { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0},
++ { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0},
++ { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0},
+ };
+
+ /*
diff --git a/st/patches/st-focus-20230610-68d1ad9.diff b/st/patches/st-focus-20230610-68d1ad9.diff
new file mode 100644
index 0000000..1c6488a
--- /dev/null
+++ b/st/patches/st-focus-20230610-68d1ad9.diff
@@ -0,0 +1,537 @@
+# From e08d495aaa29c53273942985f40212ef72715604 Mon Sep 17 00:00:00 2001
+# From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+# Date: Sat, 30 May 2020 01:11:42 +0200
+# Subject: [PATCH 1/7] chore: add alpha patch
+#
+# ---
+# config.def.h | 11 +++++++----
+# config.mk | 2 +-
+# st.h | 1 +
+# x.c | 40 ++++++++++++++++++++++++++++++----------
+# 4 files changed, 39 insertions(+), 15 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..6bd6e8d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -93,6 +93,9 @@ char *termname = "st-256color";
+ */
+ unsigned int tabspaces = 8;
+
++/* bg opacity */
++float alpha = 0.8;
++
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+ /* 8 normal colors */
+@@ -120,8 +123,7 @@ static const char *colorname[] = {
+ /* more colors can be added after 255 to use with DefaultXX */
+ "#cccccc",
+ "#555555",
+- "gray90", /* default foreground colour */
+- "black", /* default background colour */
++ "black",
+ };
+
+
+@@ -129,8 +131,9 @@ static const char *colorname[] = {
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+-unsigned int defaultfg = 258;
+-unsigned int defaultbg = 259;
++unsigned int defaultfg = 7;
++unsigned int defaultbg = 258;
++//static
+ unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
+
+diff --git a/config.mk b/config.mk
+index 1e306f8..47c615e 100644
+--- a/config.mk
++++ b/config.mk
+@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config
+ INCS = -I$(X11INC) \
+ `$(PKG_CONFIG) --cflags fontconfig` \
+ `$(PKG_CONFIG) --cflags freetype2`
+-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
+ `$(PKG_CONFIG) --libs fontconfig` \
+ `$(PKG_CONFIG) --libs freetype2`
+
+diff --git a/st.h b/st.h
+index fd3b0d8..9f91e2a 100644
+--- a/st.h
++++ b/st.h
+@@ -124,3 +124,4 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
++extern float alpha;
+diff --git a/x.c b/x.c
+index 2a3bd38..27e81d1 100644
+--- a/x.c
++++ b/x.c
+@@ -105,6 +105,7 @@ typedef struct {
+ XSetWindowAttributes attrs;
+ int scr;
+ int isfixed; /* is fixed geometry? */
++ int depth; /* bit depth */
+ int l, t; /* left and top offset */
+ int gm; /* geometry mask */
+ } XWindow;
+@@ -243,6 +244,7 @@ static char *usedfont = NULL;
+ static double usedfontsize = 0;
+ static double defaultfontsize = 0;
+
++static char *opt_alpha = NULL;
+ static char *opt_class = NULL;
+ static char **opt_cmd = NULL;
+ static char *opt_embed = NULL;
+@@ -752,7 +754,7 @@ xresize(int col, int row)
+
+ XFreePixmap(xw.dpy, xw.buf);
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
++ xw.depth);
+ XftDrawChange(xw.draw, xw.buf);
+ xclear(0, 0, win.w, win.h);
+
+@@ -812,6 +814,13 @@ xloadcols(void)
+ else
+ die("could not allocate color %d\n", i);
+ }
++
++ /* set alpha value of bg color */
++ if (opt_alpha)
++ alpha = strtof(opt_alpha, NULL);
++ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
++ dc.col[defaultbg].pixel &= 0x00FFFFFF;
++ dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
+ loaded = 1;
+ }
+
+@@ -1134,11 +1143,23 @@ xinit(int cols, int rows)
+ Window parent;
+ pid_t thispid = getpid();
+ XColor xmousefg, xmousebg;
++ XWindowAttributes attr;
++ XVisualInfo vis;
+
+ if (!(xw.dpy = XOpenDisplay(NULL)))
+ die("can't open display\n");
+ xw.scr = XDefaultScreen(xw.dpy);
+- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
++
++ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
++ parent = XRootWindow(xw.dpy, xw.scr);
++ xw.depth = 32;
++ } else {
++ XGetWindowAttributes(xw.dpy, parent, &attr);
++ xw.depth = attr.depth;
++ }
++
++ XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
++ xw.vis = vis.visual;
+
+ /* font */
+ if (!FcInit())
+@@ -1148,7 +1169,7 @@ xinit(int cols, int rows)
+ xloadfonts(usedfont, 0);
+
+ /* colors */
+- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
++ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
+ xloadcols();
+
+ /* adjust fixed window geometry */
+@@ -1168,19 +1189,15 @@ xinit(int cols, int rows)
+ | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+ xw.attrs.colormap = xw.cmap;
+
+- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
+- parent = XRootWindow(xw.dpy, xw.scr);
+ xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
+- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
++ win.w, win.h, 0, xw.depth, InputOutput,
+ xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
+ | CWEventMask | CWColormap, &xw.attrs);
+
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ gcvalues.graphics_exposures = False;
+- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+- &gcvalues);
+- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
++ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
++ dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
+ XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
+ XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
+
+@@ -2035,6 +2052,9 @@ main(int argc, char *argv[])
+ case 'a':
+ allowaltscreen = 0;
+ break;
++ case 'A':
++ opt_alpha = EARGF(usage());
++ break;
+ case 'c':
+ opt_class = EARGF(usage());
+ break;
+--
+2.34.1
+
+
+From 292b70d7b9976e624931f8ec264a8875e29d2f3c Mon Sep 17 00:00:00 2001
+From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+Date: Sat, 30 May 2020 01:13:35 +0200
+Subject: [PATCH 2/7] [patch:focus] add initial patch
+
+---
+ config.def.h | 6 +++---
+ st.h | 2 +-
+ x.c | 33 +++++++++++++++++++--------------
+ 3 files changed, 23 insertions(+), 18 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6bd6e8d..cdfbaf1 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -94,7 +94,7 @@ char *termname = "st-256color";
+ unsigned int tabspaces = 8;
+
+ /* bg opacity */
+-float alpha = 0.8;
++float alpha = 0.8, alphaUnfocused = 0.6;
+
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+@@ -132,10 +132,10 @@ static const char *colorname[] = {
+ * foreground, background, cursor, reverse cursor
+ */
+ unsigned int defaultfg = 7;
+-unsigned int defaultbg = 258;
+-//static
++unsigned int defaultbg = 0;
+ unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
++unsigned int bg = 17, bgUnfocused = 16;
+
+ /*
+ * Default shape of cursor
+diff --git a/st.h b/st.h
+index 9f91e2a..62e3486 100644
+--- a/st.h
++++ b/st.h
+@@ -124,4 +124,4 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
+-extern float alpha;
++extern float alpha, alphaUnfocused;
+diff --git a/x.c b/x.c
+index 27e81d1..05d6e2e 100644
+--- a/x.c
++++ b/x.c
+@@ -255,6 +255,7 @@ static char *opt_name = NULL;
+ static char *opt_title = NULL;
+
+ static uint buttons; /* bit field of pressed buttons */
++static int focused = 0;
+
+ void
+ clipcopy(const Arg *dummy)
+@@ -792,35 +793,38 @@ xloadcolor(int i, const char *name, Color *ncolor)
+ return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
+ }
+
++void
++xloadalpha(void)
++{
++ float const usedAlpha = focused ? alpha : alphaUnfocused;
++ if (opt_alpha) alpha = strtof(opt_alpha, NULL);
++ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
++ dc.col[defaultbg].pixel &= 0x00FFFFFF;
++ dc.col[defaultbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24;
++}
++
+ void
+ xloadcols(void)
+ {
+- int i;
+ static int loaded;
+ Color *cp;
+
+- if (loaded) {
+- for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
+- XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+- } else {
+- dc.collen = MAX(LEN(colorname), 256);
+- dc.col = xmalloc(dc.collen * sizeof(Color));
++ if (!loaded) {
++ dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256));
++ dc.col = xmalloc((dc.collen) * sizeof(Color));
+ }
+
+- for (i = 0; i < dc.collen; i++)
++ for (int i = 0; i+1 < dc.collen; ++i)
+ if (!xloadcolor(i, NULL, &dc.col[i])) {
+ if (colorname[i])
+ die("could not allocate color '%s'\n", colorname[i]);
+ else
+ die("could not allocate color %d\n", i);
+ }
++ if (dc.collen) // cannot die, as the color is already loaded.
++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]);
+
+- /* set alpha value of bg color */
+- if (opt_alpha)
+- alpha = strtof(opt_alpha, NULL);
+- dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+- dc.col[defaultbg].pixel &= 0x00FFFFFF;
+- dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
++ xloadalpha();
+ loaded = 1;
+ }
+
+@@ -2106,6 +2110,7 @@ run:
+ XSetLocaleModifiers("");
+ cols = MAX(cols, 1);
+ rows = MAX(rows, 1);
++ defaultbg = MAX(LEN(colorname), 256);
+ tnew(cols, rows);
+ xinit(cols, rows);
+ xsetenv();
+--
+2.34.1
+
+
+From 9bb6788325306d9ec2bead559dacd031287a2b8c Mon Sep 17 00:00:00 2001
+From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+Date: Fri, 5 Jun 2020 20:48:06 +0200
+Subject: [PATCH 3/7] [patch:focus]: fix
+
+---
+ x.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/x.c b/x.c
+index 05d6e2e..97481ba 100644
+--- a/x.c
++++ b/x.c
+@@ -1798,12 +1798,22 @@ focus(XEvent *ev)
+ xseturgency(0);
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[I", 3, 0);
++ if (!focused) {
++ xloadcols();
++ redraw();
++ }
++ focused = 1;
+ } else {
+ if (xw.ime.xic)
+ XUnsetICFocus(xw.ime.xic);
+ win.mode &= ~MODE_FOCUSED;
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[O", 3, 0);
++ if (focused) {
++ xloadcols();
++ redraw();
++ }
++ focused = 0;
+ }
+ }
+
+--
+2.34.1
+
+
+From 62b6683ddf40aff222b59d5e074770d8d7336342 Mon Sep 17 00:00:00 2001
+From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+Date: Sat, 6 Jun 2020 12:57:43 +0200
+Subject: [PATCH 4/7] [patch:focus]: fix
+
+---
+ x.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/x.c b/x.c
+index 97481ba..c4a4b00 100644
+--- a/x.c
++++ b/x.c
+@@ -1799,10 +1799,10 @@ focus(XEvent *ev)
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[I", 3, 0);
+ if (!focused) {
++ focused = 1;
+ xloadcols();
+ redraw();
+ }
+- focused = 1;
+ } else {
+ if (xw.ime.xic)
+ XUnsetICFocus(xw.ime.xic);
+@@ -1810,10 +1810,10 @@ focus(XEvent *ev)
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[O", 3, 0);
+ if (focused) {
++ focused = 0;
+ xloadcols();
+ redraw();
+ }
+- focused = 0;
+ }
+ }
+
+--
+2.34.1
+
+
+From dc6c039192e887e70a2e6f07ac55c317e6b1c3be Mon Sep 17 00:00:00 2001
+From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+Date: Thu, 23 Jul 2020 18:17:50 +0200
+Subject: [PATCH 5/7] potential fix: exchange redraw with tfulldirt
+
+---
+ st.c | 1 -
+ st.h | 1 +
+ x.c | 4 ++--
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/st.c b/st.c
+index 62def59..8ee76a3 100644
+--- a/st.c
++++ b/st.c
+@@ -194,7 +194,6 @@ static void tsetscroll(int, int);
+ static void tswapscreen(void);
+ static void tsetmode(int, int, const int *, int);
+ static int twrite(const char *, int, int);
+-static void tfulldirt(void);
+ static void tcontrolcode(uchar );
+ static void tdectest(char );
+ static void tdefutf8(char);
+diff --git a/st.h b/st.h
+index 62e3486..13be339 100644
+--- a/st.h
++++ b/st.h
+@@ -79,6 +79,7 @@ typedef union {
+
+ void die(const char *, ...);
+ void redraw(void);
++void tfulldirt(void);
+ void draw(void);
+
+ void printscreen(const Arg *);
+diff --git a/x.c b/x.c
+index c4a4b00..92c87b4 100644
+--- a/x.c
++++ b/x.c
+@@ -1801,7 +1801,7 @@ focus(XEvent *ev)
+ if (!focused) {
+ focused = 1;
+ xloadcols();
+- redraw();
++ tfulldirt();
+ }
+ } else {
+ if (xw.ime.xic)
+@@ -1812,7 +1812,7 @@ focus(XEvent *ev)
+ if (focused) {
+ focused = 0;
+ xloadcols();
+- redraw();
++ tfulldirt();
+ }
+ }
+ }
+--
+2.34.1
+
+
+From 4da97936d57e3528ef7cf36c254c0985f6640132 Mon Sep 17 00:00:00 2001
+From: Wim Stockman <wim@yasendfile.org>
+Date: Sat, 4 Feb 2023 13:46:02 +0100
+Subject: [PATCH 6/7] Performs upgrade avoid reloading all the colors again and
+ again also avoids problem when colors are set dynamically when focus in and
+ out that the colourpallette is not reset each time.
+
+---
+ x.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/x.c b/x.c
+index 92c87b4..879bf0e 100644
+--- a/x.c
++++ b/x.c
+@@ -796,6 +796,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
+ void
+ xloadalpha(void)
+ {
++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]);
+ float const usedAlpha = focused ? alpha : alphaUnfocused;
+ if (opt_alpha) alpha = strtof(opt_alpha, NULL);
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
+@@ -821,8 +822,6 @@ xloadcols(void)
+ else
+ die("could not allocate color %d\n", i);
+ }
+- if (dc.collen) // cannot die, as the color is already loaded.
+- xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]);
+
+ xloadalpha();
+ loaded = 1;
+@@ -1800,7 +1799,7 @@ focus(XEvent *ev)
+ ttywrite("\033[I", 3, 0);
+ if (!focused) {
+ focused = 1;
+- xloadcols();
++ xloadalpha();
+ tfulldirt();
+ }
+ } else {
+@@ -1811,7 +1810,7 @@ focus(XEvent *ev)
+ ttywrite("\033[O", 3, 0);
+ if (focused) {
+ focused = 0;
+- xloadcols();
++ xloadalpha();
+ tfulldirt();
+ }
+ }
+--
+2.34.1
+
+
+From ec16984d95e0ff9ac33b2b3d30f292c3a327c473 Mon Sep 17 00:00:00 2001
+From: Julius Huelsmann <juliusHuelsmann@gmail.com>
+Date: Sat, 10 Jun 2023 13:16:11 +0200
+Subject: [PATCH 7/7] changed default config a bit
+
+---
+ config.def.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index cdfbaf1..779178f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -94,7 +94,7 @@ char *termname = "st-256color";
+ unsigned int tabspaces = 8;
+
+ /* bg opacity */
+-float alpha = 0.8, alphaUnfocused = 0.6;
++float alpha = 0.93, alphaUnfocused = 0.6;
+
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+@@ -135,7 +135,7 @@ unsigned int defaultfg = 7;
+ unsigned int defaultbg = 0;
+ unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
+-unsigned int bg = 17, bgUnfocused = 16;
++unsigned int bg = 0, bgUnfocused = 16;
+
+ /*
+ * Default shape of cursor
+--
+2.34.1
diff --git a/st/patches/st-font2-0.8.5.diff b/st/patches/st-font2-0.8.5.diff
new file mode 100644
index 0000000..9b22b8a
--- /dev/null
+++ b/st/patches/st-font2-0.8.5.diff
@@ -0,0 +1,163 @@
+From 1635e04d3643dd4caa0c7c2043b585c6d7e4705f Mon Sep 17 00:00:00 2001
+From: Rizqi Nur Assyaufi <bandithijo@gmail.com>
+Date: Mon, 18 Jul 2022 01:15:45 +0800
+Subject: [PATCH] [st][patch][font2] Add patch for st-0.8.5
+
+---
+ config.def.h | 6 +++
+ x.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 107 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..717b2f0 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -6,6 +6,12 @@
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
+ static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
++/* Spare fonts */
++static char *font2[] = {
++/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */
++/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */
++};
++
+ static int borderpx = 2;
+
+ /*
+diff --git a/x.c b/x.c
+index 8a16faa..220fc4f 100644
+--- a/x.c
++++ b/x.c
+@@ -157,6 +157,8 @@ static void xhints(void);
+ static int xloadcolor(int, const char *, Color *);
+ static int xloadfont(Font *, FcPattern *);
+ static void xloadfonts(const char *, double);
++static int xloadsparefont(FcPattern *, int);
++static void xloadsparefonts(void);
+ static void xunloadfont(Font *);
+ static void xunloadfonts(void);
+ static void xsetenv(void);
+@@ -306,6 +308,7 @@ zoomabs(const Arg *arg)
+ {
+ xunloadfonts();
+ xloadfonts(usedfont, arg->f);
++ xloadsparefonts();
+ cresize(0, 0);
+ redraw();
+ xhints();
+@@ -1034,6 +1037,101 @@ xloadfonts(const char *fontstr, double fontsize)
+ FcPatternDestroy(pattern);
+ }
+
++int
++xloadsparefont(FcPattern *pattern, int flags)
++{
++ FcPattern *match;
++ FcResult result;
++
++ match = FcFontMatch(NULL, pattern, &result);
++ if (!match) {
++ return 1;
++ }
++
++ if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) {
++ FcPatternDestroy(match);
++ return 1;
++ }
++
++ frc[frclen].flags = flags;
++ /* Believe U+0000 glyph will present in each default font */
++ frc[frclen].unicodep = 0;
++ frclen++;
++
++ return 0;
++}
++
++void
++xloadsparefonts(void)
++{
++ FcPattern *pattern;
++ double sizeshift, fontval;
++ int fc;
++ char **fp;
++
++ if (frclen != 0)
++ die("can't embed spare fonts. cache isn't empty");
++
++ /* Calculate count of spare fonts */
++ fc = sizeof(font2) / sizeof(*font2);
++ if (fc == 0)
++ return;
++
++ /* Allocate memory for cache entries. */
++ if (frccap < 4 * fc) {
++ frccap += 4 * fc - frccap;
++ frc = xrealloc(frc, frccap * sizeof(Fontcache));
++ }
++
++ for (fp = font2; fp - font2 < fc; ++fp) {
++
++ if (**fp == '-')
++ pattern = XftXlfdParse(*fp, False, False);
++ else
++ pattern = FcNameParse((FcChar8 *)*fp);
++
++ if (!pattern)
++ die("can't open spare font %s\n", *fp);
++
++ if (defaultfontsize > 0) {
++ sizeshift = usedfontsize - defaultfontsize;
++ if (sizeshift != 0 &&
++ FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
++ FcResultMatch) {
++ fontval += sizeshift;
++ FcPatternDel(pattern, FC_PIXEL_SIZE);
++ FcPatternDel(pattern, FC_SIZE);
++ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
++ }
++ }
++
++ FcPatternAddBool(pattern, FC_SCALABLE, 1);
++
++ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
++ XftDefaultSubstitute(xw.dpy, xw.scr, pattern);
++
++ if (xloadsparefont(pattern, FRC_NORMAL))
++ die("can't open spare font %s\n", *fp);
++
++ FcPatternDel(pattern, FC_SLANT);
++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
++ if (xloadsparefont(pattern, FRC_ITALIC))
++ die("can't open spare font %s\n", *fp);
++
++ FcPatternDel(pattern, FC_WEIGHT);
++ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
++ if (xloadsparefont(pattern, FRC_ITALICBOLD))
++ die("can't open spare font %s\n", *fp);
++
++ FcPatternDel(pattern, FC_SLANT);
++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
++ if (xloadsparefont(pattern, FRC_BOLD))
++ die("can't open spare font %s\n", *fp);
++
++ FcPatternDestroy(pattern);
++ }
++}
++
+ void
+ xunloadfont(Font *f)
+ {
+@@ -1131,6 +1229,9 @@ xinit(int cols, int rows)
+ usedfont = (opt_font == NULL)? font : opt_font;
+ xloadfonts(usedfont, 0);
+
++ /* spare fonts */
++ xloadsparefonts();
++
+ /* colors */
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ xloadcols();
+--
+2.37.1
+
diff --git a/st/patches/st-fullscreen-0.8.5.diff b/st/patches/st-fullscreen-0.8.5.diff
new file mode 100644
index 0000000..3e2868d
--- /dev/null
+++ b/st/patches/st-fullscreen-0.8.5.diff
@@ -0,0 +1,69 @@
+diff -r -u a/config.def.h b/config.def.h
+--- a/config.def.h 2022-01-07 06:41:35.000000000 -0500
++++ b/config.def.h 2022-01-15 13:32:01.644320198 -0500
+@@ -201,6 +201,8 @@
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} },
++ { MODKEY, XK_Return, fullscreen, {.i = 0} },
+ };
+
+ /*
+diff -r -u a/st.h b/st.h
+--- a/st.h 2022-01-07 06:41:35.000000000 -0500
++++ b/st.h 2022-01-15 13:32:40.084320514 -0500
+@@ -81,6 +81,7 @@
+ void redraw(void);
+ void draw(void);
+
++void fullscreen(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+diff -r -u a/x.c b/x.c
+--- a/x.c 2022-01-07 06:41:35.000000000 -0500
++++ b/x.c 2022-01-15 13:50:28.164329295 -0500
+@@ -94,6 +94,7 @@
+ Drawable buf;
+ GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+ Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
++ Atom netwmstate, netwmfullscreen;
+ struct {
+ XIM xim;
+ XIC xic;
+@@ -744,6 +745,24 @@
+ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
+ }
+
++void
++fullscreen(const Arg *arg)
++{
++ XEvent ev;
++
++ memset(&ev, 0, sizeof(ev));
++
++ ev.xclient.type = ClientMessage;
++ ev.xclient.message_type = xw.netwmstate;
++ ev.xclient.display = xw.dpy;
++ ev.xclient.window = xw.win;
++ ev.xclient.format = 32;
++ ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */
++ ev.xclient.data.l[1] = xw.netwmfullscreen;
++
++ XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev);
++}
++
+ ushort
+ sixd_to_16bit(int x)
+ {
+@@ -1208,6 +1227,9 @@
+ XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
+ PropModeReplace, (uchar *)&thispid, 1);
+
++ xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False);
++ xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False);
++
+ win.mode = MODE_NUMLOCK;
+ resettitle();
+ xhints();
diff --git a/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff
new file mode 100644
index 0000000..0448226
--- /dev/null
+++ b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff
@@ -0,0 +1,213 @@
+From 9583955da47177c9557210f70baaaf9511ba106c Mon Sep 17 00:00:00 2001
+From: wael <40663@protonmail.com>
+Date: Mon, 11 Apr 2022 17:14:06 +0300
+Subject: [PATCH] boxdraw support for glyph wide support
+
+---
+ st.h | 6 +++
+ x.c | 139 ++++++++++++++++++++++++++++++-----------------------------
+ 2 files changed, 76 insertions(+), 69 deletions(-)
+
+diff --git a/st.h b/st.h
+index 07a7c66..3b8c97d 100644
+--- a/st.h
++++ b/st.h
+@@ -37,6 +37,12 @@ enum glyph_attribute {
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+ };
+
++enum drawing_mode {
++ DRAW_NONE = 0,
++ DRAW_BG = 1 << 0,
++ DRAW_FG = 1 << 1,
++};
++
+ enum selection_mode {
+ SEL_IDLE = 0,
+ SEL_EMPTY = 1,
+diff --git a/x.c b/x.c
+index bf6bbf9..1311c0d 100644
+--- a/x.c
++++ b/x.c
+@@ -142,7 +142,7 @@ typedef struct {
+
+ static inline ushort sixd_to_16bit(int);
+ static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
+-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
++static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int);
+ static void xdrawglyph(Glyph, int, int);
+ static void xclear(int, int, int, int);
+ static int xgeommasktogravity(int);
+@@ -1379,7 +1379,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ }
+
+ void
+-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
++xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode)
+ {
+ int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
+ int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
+@@ -1470,51 +1470,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+ if (base.mode & ATTR_INVISIBLE)
+ fg = bg;
+
+- /* Intelligent cleaning up of the borders. */
+- if (x == 0) {
+- xclear(0, (y == 0)? 0 : winy, borderpx,
+- winy + win.ch +
+- ((winy + win.ch >= borderpx + win.th)? win.h : 0));
+- }
+- if (winx + width >= borderpx + win.tw) {
+- xclear(winx + width, (y == 0)? 0 : winy, win.w,
+- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
+- }
+- if (y == 0)
+- xclear(winx, 0, winx + width, borderpx);
+- if (winy + win.ch >= borderpx + win.th)
+- xclear(winx, winy + win.ch, winx + width, win.h);
+-
+- /* Clean up the region we want to draw to. */
+- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+-
+- /* Set the clip region because Xft is sometimes dirty. */
+- r.x = 0;
+- r.y = 0;
+- r.height = win.ch;
+- r.width = width;
+- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
+-
+- if (base.mode & ATTR_BOXDRAW) {
+- drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
+- } else {
+- /* Render the glyphs. */
+- XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+- }
++ if (dmode & DRAW_BG) {
++ /* Intelligent cleaning up of the borders. */
++ if (x == 0) {
++ xclear(0, (y == 0)? 0 : winy, borderpx,
++ winy + win.ch +
++ ((winy + win.ch >= borderpx + win.th)? win.h : 0));
++ }
++ if (winx + width >= borderpx + win.tw) {
++ xclear(winx + width, (y == 0)? 0 : winy, win.w,
++ ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
++ }
++ if (y == 0)
++ xclear(winx, 0, winx + width, borderpx);
++ if (winy + win.ch >= borderpx + win.th)
++ xclear(winx, winy + win.ch, winx + width, win.h);
++ /* Fill the background */
++ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
++ }
++
++
++ if (dmode & DRAW_FG) {
++ if (base.mode & ATTR_BOXDRAW) {
++ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
++ } else {
++ /* Render the glyphs. */
++ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
++ }
+
+- /* Render underline and strikethrough. */
+- if (base.mode & ATTR_UNDERLINE) {
+- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
+- width, 1);
+- }
++ /* Render underline and strikethrough. */
++ if (base.mode & ATTR_UNDERLINE) {
++ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
++ width, 1);
++ }
+
+- if (base.mode & ATTR_STRUCK) {
+- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
+- width, 1);
+- }
+-
+- /* Reset clip to none. */
+- XftDrawSetClip(xw.draw, 0);
++ if (base.mode & ATTR_STRUCK) {
++ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
++ width, 1);
++ }
++ }
+ }
+
+ void
+@@ -1524,7 +1518,7 @@ xdrawglyph(Glyph g, int x, int y)
+ XftGlyphFontSpec spec;
+
+ numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
+- xdrawglyphfontspecs(&spec, g, numspecs, x, y);
++ xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG);
+ }
+
+ void
+@@ -1659,32 +1653,39 @@ xstartdraw(void)
+ void
+ xdrawline(Line line, int x1, int y1, int x2)
+ {
+- int i, x, ox, numspecs;
++ int i, x, ox, numspecs, numspecs_cached;
+ Glyph base, new;
+- XftGlyphFontSpec *specs = xw.specbuf;
+-
+- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
+- i = ox = 0;
+- for (x = x1; x < x2 && i < numspecs; x++) {
+- new = line[x];
+- if (new.mode == ATTR_WDUMMY)
+- continue;
+- if (selected(x, y1))
+- new.mode ^= ATTR_REVERSE;
+- if (i > 0 && ATTRCMP(base, new)) {
+- xdrawglyphfontspecs(specs, base, i, ox, y1);
+- specs += i;
+- numspecs -= i;
+- i = 0;
+- }
+- if (i == 0) {
+- ox = x;
+- base = new;
++ XftGlyphFontSpec *specs;
++
++ numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1);
++
++ /* Draw line in 2 passes: background and foreground. This way wide glyphs
++ won't get truncated (#223) */
++ for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) {
++ specs = xw.specbuf;
++ numspecs = numspecs_cached;
++ i = ox = 0;
++ for (x = x1; x < x2 && i < numspecs; x++) {
++ new = line[x];
++ if (new.mode == ATTR_WDUMMY)
++ continue;
++ if (selected(x, y1))
++ new.mode ^= ATTR_REVERSE;
++ if (i > 0 && ATTRCMP(base, new)) {
++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
++ specs += i;
++ numspecs -= i;
++ i = 0;
++ }
++ if (i == 0) {
++ ox = x;
++ base = new;
++ }
++ i++;
+ }
+- i++;
++ if (i > 0)
++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
+ }
+- if (i > 0)
+- xdrawglyphfontspecs(specs, base, i, ox, y1);
+ }
+
+ void
+--
+2.35.1
+
diff --git a/st/patches/st-iso14755-0.8.5.diff b/st/patches/st-iso14755-0.8.5.diff
new file mode 100644
index 0000000..adaedb4
--- /dev/null
+++ b/st/patches/st-iso14755-0.8.5.diff
@@ -0,0 +1,89 @@
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..6d1aee0 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -170,6 +170,11 @@ static unsigned int defaultattr = 11;
+ */
+ static uint forcemousemod = ShiftMask;
+
++/*
++ * Command used to query unicode glyphs.
++ */
++char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null";
++
+ /*
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+@@ -201,6 +206,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { TERMMOD, XK_I, iso14755, {.i = 0} },
+ };
+
+ /*
+diff --git a/st.1 b/st.1
+index 39120b4..4a98626 100644
+--- a/st.1
++++ b/st.1
+@@ -159,6 +159,10 @@ Copy the selected text to the clipboard selection.
+ .TP
+ .B Ctrl-Shift-v
+ Paste from the clipboard selection.
++.TP
++.B Ctrl-Shift-i
++Launch dmenu to enter a unicode codepoint and send the corresponding glyph
++to st.
+ .SH CUSTOMIZATION
+ .B st
+ can be customized by creating a custom config.h and (re)compiling the source
+diff --git a/st.c b/st.c
+index 51049ba..308162b 100644
+--- a/st.c
++++ b/st.c
+@@ -2068,6 +2068,28 @@ tprinter(char *s, size_t len)
+ }
+ }
+
++void
++iso14755(const Arg *arg)
++{
++ FILE *p;
++ char *us, *e, codepoint[9], uc[UTF_SIZ];
++ unsigned long utf32;
++
++ if (!(p = popen(iso14755_cmd, "r")))
++ return;
++
++ us = fgets(codepoint, sizeof(codepoint), p);
++ pclose(p);
++
++ if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
++ return;
++ if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
++ (*e != '\n' && *e != '\0'))
++ return;
++
++ ttywrite(uc, utf8encode(utf32, uc), 1);
++}
++
+ void
+ toggleprinter(const Arg *arg)
+ {
+diff --git a/st.h b/st.h
+index 519b9bd..51aa1ae 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,7 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void iso14755(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+@@ -126,3 +127,4 @@ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern unsigned int defaultcs;
++extern char *iso14755_cmd;
diff --git a/st/patches/st-keyboard_select-20200617-9ba7ecf.diff b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff
new file mode 100644
index 0000000..fac41ea
--- /dev/null
+++ b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff
@@ -0,0 +1,319 @@
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..54612d1 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -199,6 +199,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { TERMMOD, XK_Escape, keyboard_select,{.i = 0} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index ef8abd5..0c6c6ca 100644
+--- a/st.c
++++ b/st.c
+@@ -16,6 +16,8 @@
+ #include <termios.h>
+ #include <unistd.h>
+ #include <wchar.h>
++#include <X11/keysym.h>
++#include <X11/X.h>
+
+ #include "st.h"
+ #include "win.h"
+@@ -2487,6 +2489,9 @@ tresize(int col, int row)
+ int *bp;
+ TCursor c;
+
++ if ( row < term.row || col < term.col )
++ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
++
+ if (col < 1 || row < 1) {
+ fprintf(stderr,
+ "tresize: error resizing to %dx%d\n", col, row);
+@@ -2612,3 +2617,220 @@ redraw(void)
+ tfulldirt();
+ draw();
+ }
++
++void set_notifmode(int type, KeySym ksym) {
++ static char *lib[] = { " MOVE ", " SEL "};
++ static Glyph *g, *deb, *fin;
++ static int col, bot;
++
++ if ( ksym == -1 ) {
++ free(g);
++ col = term.col, bot = term.bot;
++ g = xmalloc(col * sizeof(Glyph));
++ memcpy(g, term.line[bot], col * sizeof(Glyph));
++
++ }
++ else if ( ksym == -2 )
++ memcpy(term.line[bot], g, col * sizeof(Glyph));
++
++ if ( type < 2 ) {
++ char *z = lib[type];
++ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
++ deb->mode = ATTR_REVERSE,
++ deb->u = *z,
++ deb->fg = defaultfg, deb->bg = defaultbg;
++ }
++ else if ( type < 5 )
++ memcpy(term.line[bot], g, col * sizeof(Glyph));
++ else {
++ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
++ deb->mode = ATTR_REVERSE,
++ deb->u = ' ',
++ deb->fg = defaultfg, deb->bg = defaultbg;
++ term.line[bot][0].u = ksym;
++ }
++
++ term.dirty[bot] = 1;
++ drawregion(0, bot, col, bot + 1);
++}
++
++void select_or_drawcursor(int selectsearch_mode, int type) {
++ int done = 0;
++
++ if ( selectsearch_mode & 1 ) {
++ selextend(term.c.x, term.c.y, type, done);
++ xsetsel(getsel());
++ }
++ else
++ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++}
++
++void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) {
++ Rune *r;
++ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
++
++ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
++ for (r = target; r - target < ptarget; r++) {
++ if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) {
++ if ( r - target == ptarget - 1 ) break;
++ } else {
++ r = NULL;
++ break;
++ }
++ }
++ if ( r != NULL ) break;
++ }
++
++ if ( i != bound ) {
++ term.c.y = i / term.col, term.c.x = i % term.col;
++ select_or_drawcursor(selectsearch_mode, type);
++ }
++}
++
++int trt_kbdselect(KeySym ksym, char *buf, int len) {
++ static TCursor cu;
++ static Rune target[64];
++ static int type = 1, ptarget, in_use;
++ static int sens, quant;
++ static char selectsearch_mode;
++ int i, bound, *xy;
++
++
++ if ( selectsearch_mode & 2 ) {
++ if ( ksym == XK_Return ) {
++ selectsearch_mode ^= 2;
++ set_notifmode(selectsearch_mode, -2);
++ if ( ksym == XK_Escape ) ptarget = 0;
++ return 0;
++ }
++ else if ( ksym == XK_BackSpace ) {
++ if ( !ptarget ) return 0;
++ term.line[term.bot][ptarget--].u = ' ';
++ }
++ else if ( len < 1 ) {
++ return 0;
++ }
++ else if ( ptarget == term.col || ksym == XK_Escape ) {
++ return 0;
++ }
++ else {
++ utf8decode(buf, &target[ptarget++], len);
++ term.line[term.bot][ptarget].u = target[ptarget - 1];
++ }
++
++ if ( ksym != XK_BackSpace )
++ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
++
++ term.dirty[term.bot] = 1;
++ drawregion(0, term.bot, term.col, term.bot + 1);
++ return 0;
++ }
++
++ switch ( ksym ) {
++ case -1 :
++ in_use = 1;
++ cu.x = term.c.x, cu.y = term.c.y;
++ set_notifmode(0, ksym);
++ return MODE_KBDSELECT;
++ case XK_s :
++ if ( selectsearch_mode & 1 )
++ selclear();
++ else
++ selstart(term.c.x, term.c.y, 0);
++ set_notifmode(selectsearch_mode ^= 1, ksym);
++ break;
++ case XK_t :
++ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */
++ selextend(term.c.x, term.c.y, type, i = 0);
++ break;
++ case XK_slash :
++ case XK_KP_Divide :
++ case XK_question :
++ ksym &= XK_question; /* Divide to slash */
++ sens = (ksym == XK_slash) ? -1 : 1;
++ ptarget = 0;
++ set_notifmode(15, ksym);
++ selectsearch_mode ^= 2;
++ break;
++ case XK_Escape :
++ if ( !in_use ) break;
++ selclear();
++ case XK_Return :
++ set_notifmode(4, ksym);
++ term.c.x = cu.x, term.c.y = cu.y;
++ select_or_drawcursor(selectsearch_mode = 0, type);
++ in_use = quant = 0;
++ return MODE_KBDSELECT;
++ case XK_n :
++ case XK_N :
++ if ( ptarget )
++ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
++ break;
++ case XK_BackSpace :
++ term.c.x = 0;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_dollar :
++ term.c.x = term.col - 1;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_Home :
++ term.c.x = 0, term.c.y = 0;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_End :
++ term.c.x = cu.x, term.c.y = cu.y;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_Page_Up :
++ case XK_Page_Down :
++ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_exclam :
++ term.c.x = term.col >> 1;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ case XK_asterisk :
++ case XK_KP_Multiply :
++ term.c.x = term.col >> 1;
++ case XK_underscore :
++ term.c.y = cu.y >> 1;
++ select_or_drawcursor(selectsearch_mode, type);
++ break;
++ default :
++ if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */
++ quant = (quant * 10) + (ksym ^ XK_0);
++ return 0;
++ }
++ else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */
++ quant = (quant * 10) + (ksym ^ XK_KP_0);
++ return 0;
++ }
++ else if ( ksym == XK_k || ksym == XK_h )
++ i = ksym & 1;
++ else if ( ksym == XK_l || ksym == XK_j )
++ i = ((ksym & 6) | 4) >> 1;
++ else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 )
++ break;
++
++ xy = (i & 1) ? &term.c.y : &term.c.x;
++ sens = (i & 2) ? 1 : -1;
++ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
++
++ if ( quant == 0 )
++ quant++;
++
++ if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) )
++ break;
++
++ *xy += quant * sens;
++ if ( *xy < 0 || ( bound > 0 && *xy > bound) )
++ *xy = bound;
++
++ select_or_drawcursor(selectsearch_mode, type);
++ }
++ quant = 0;
++ return 0;
++}
+diff --git a/st.h b/st.h
+index 3d351b6..2d1a11b 100644
+--- a/st.h
++++ b/st.h
+@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *);
+ void *xmalloc(size_t);
+ void *xrealloc(void *, size_t);
+ char *xstrdup(char *);
++int trt_kbdselect(KeySym, char *, int);
+
+ /* config.h globals */
+ extern char *utmp;
+diff --git a/win.h b/win.h
+index a6ef1b9..9a47fbb 100644
+--- a/win.h
++++ b/win.h
+@@ -21,6 +21,7 @@ enum win_mode {
+ MODE_NUMLOCK = 1 << 17,
+ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+ |MODE_MOUSEMANY,
++ MODE_KBDSELECT = 1 << 18,
+ };
+
+ void xbell(void);
+@@ -36,4 +37,6 @@ void xsetmode(int, unsigned int);
+ void xsetpointermotion(int);
+ void xsetsel(char *);
+ int xstartdraw(void);
++void toggle_winmode(int);
++void keyboard_select(const Arg *);
+ void xximspot(int, int);
+diff --git a/x.c b/x.c
+index 210f184..b77ce54 100644
+--- a/x.c
++++ b/x.c
+@@ -1800,6 +1800,12 @@ kpress(XEvent *ev)
+ len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+ else
+ len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
++ if ( IS_SET(MODE_KBDSELECT) ) {
++ if ( match(XK_NO_MOD, e->state) ||
++ (XK_Shift_L | XK_Shift_R) & e->state )
++ win.mode ^= trt_kbdselect(ksym, buf, len);
++ return;
++ }
+ /* 1. shortcuts */
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, e->state)) {
+@@ -1977,6 +1983,14 @@ usage(void)
+ " [stty_args ...]\n", argv0, argv0);
+ }
+
++void toggle_winmode(int flag) {
++ win.mode ^= flag;
++}
++
++void keyboard_select(const Arg *dummy) {
++ win.mode ^= trt_kbdselect(-1, NULL, 0);
++}
++
+ int
+ main(int argc, char *argv[])
+ {
diff --git a/st/patches/st-newterm-0.9-tabbed.diff b/st/patches/st-newterm-0.9-tabbed.diff
new file mode 100644
index 0000000..a32c316
--- /dev/null
+++ b/st/patches/st-newterm-0.9-tabbed.diff
@@ -0,0 +1,38 @@
+From 88559b5cb6ed3f996fc00e923f9ded3c0b353fc5 Mon Sep 17 00:00:00 2001
+From: meator <meator.dev@gmail.com>
+Date: Wed, 26 Oct 2022 14:06:49 +0200
+Subject: [PATCH] Make newterm work with the tabbed patch
+
+This commit is an updated version of st-newterm-0.8.2-tabbed.diff.
+---
+ st.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/st.c b/st.c
+index 0261283..e4a9021 100644
+--- a/st.c
++++ b/st.c
+@@ -1061,6 +1061,7 @@ tswapscreen(void)
+ void
+ newterm(const Arg* a)
+ {
++ char *tabbed_win;
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+@@ -1073,7 +1074,11 @@ newterm(const Arg* a)
+ break;
+ case 0:
+ chdir_by_pid(pid);
+- execl("/proc/self/exe", argv0, NULL);
++ tabbed_win = getenv("XEMBED");
++ if (tabbed_win)
++ execl("/proc/self/exe", argv0, "-w", tabbed_win, NULL);
++ else
++ execl("/proc/self/exe", argv0, NULL);
+ _exit(1);
+ break;
+ default:
+--
+2.38.0
+
diff --git a/st/patches/st-newterm-0.9-tmux.diff b/st/patches/st-newterm-0.9-tmux.diff
new file mode 100644
index 0000000..cd73e60
--- /dev/null
+++ b/st/patches/st-newterm-0.9-tmux.diff
@@ -0,0 +1,140 @@
+From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001
+From: meator <meator.dev@gmail.com>
+Date: Tue, 25 Oct 2022 20:19:28 +0200
+Subject: [PATCH] Add support for tmux in newterm
+
+This commit tries to figure out if st's child is tmux and if so, it
+launches a shell with the CWD of the current process in the tmux session
+instead of the tmux client itself.
+
+This is heavily inspired by
+https://gist.github.com/TiddoLangerak/c61e1e48df91192f9554 (but
+converted to C).
+
+Tmux has to be a direct child of st. This means that you'll have to
+usually use the 'exec' shell builtin to attach tmux sessions.
+
+This patch only works on Linux. Other systems use different procfs which
+is incompatible or don't have procfs at all (or it's optional).
+---
+ st.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 82 insertions(+), 1 deletion(-)
+
+diff --git a/st.c b/st.c
+index 0261283..b95bf7a 100644
+--- a/st.c
++++ b/st.c
+@@ -221,6 +221,8 @@ static char base64dec_getc(const char **);
+
+ static ssize_t xwrite(int, const char *, size_t);
+
++static int gettmuxpts(void);
++
+ /* Globals */
+ static Term term;
+ static Selection sel;
+@@ -1061,6 +1063,12 @@ tswapscreen(void)
+ void
+ newterm(const Arg* a)
+ {
++ int pts;
++ FILE *fsession, *fpid;
++ char session[5];
++ char pidstr[10];
++ char buf[48];
++ size_t size;
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+@@ -1072,7 +1080,37 @@ newterm(const Arg* a)
+ _exit(1);
+ break;
+ case 0:
+- chdir_by_pid(pid);
++ signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */
++ pts = gettmuxpts();
++ if (pts != -1) {
++ snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts);
++ fsession = popen(buf, "r");
++ if (!fsession) {
++ fprintf(stderr, "Couldn't launch tmux.");
++ _exit(1);
++ }
++ size = fread(session, 1, sizeof session, fsession);
++ if (pclose(fsession) != 0 || size == 0) {
++ fprintf(stderr, "Couldn't get tmux session.");
++ _exit(1);
++ }
++ session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */
++
++ snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session);
++ fpid = popen(buf, "r");
++ if (!fpid) {
++ fprintf(stderr, "Couldn't launch tmux.");
++ _exit(1);
++ }
++ size = fread(pidstr, 1, sizeof pidstr, fpid);
++ if (pclose(fpid) != 0 || size == 0) {
++ fprintf(stderr, "Couldn't get tmux session.");
++ _exit(1);
++ }
++ pidstr[size - 1] = '\0';
++ }
++
++ chdir_by_pid(pts != -1 ? atol(pidstr) : pid);
+ execl("/proc/self/exe", argv0, NULL);
+ _exit(1);
+ break;
+@@ -1092,6 +1130,49 @@ chdir_by_pid(pid_t pid)
+ return chdir(buf);
+ }
+
++/* returns the pty of tmux client or -1 if the child of st isn't tmux */
++static int
++gettmuxpts(void)
++{
++ char buf[32];
++ char comm[17];
++ int tty;
++ FILE *fstat;
++ FILE *fcomm;
++ size_t numread;
++
++ snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid);
++
++ fcomm = fopen(buf, "r");
++ if (!fcomm) {
++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno));
++ _exit(1);
++ }
++
++ numread = fread(comm, 1, sizeof comm - 1, fcomm);
++ comm[numread] = '\0';
++
++ fclose(fcomm);
++
++ if (strcmp("tmux: client\n", comm) != 0)
++ return -1;
++
++ snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid);
++ fstat = fopen(buf, "r");
++ if (!fstat) {
++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno));
++ _exit(1);
++ }
++
++ /*
++ * We can't skip the second field with %*s because it contains a space so
++ * we skip strlen("tmux: client") + 2 for the braces which is 14.
++ */
++ fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty);
++ fclose(fstat);
++ return ((0xfff00000 & tty) >> 12) | (0xff & tty);
++}
++
+ void
+ tscrolldown(int orig, int n)
+ {
+--
+2.38.0
+
diff --git a/st/patches/st-newterm-0.9.diff b/st/patches/st-newterm-0.9.diff
new file mode 100644
index 0000000..5525e7a
--- /dev/null
+++ b/st/patches/st-newterm-0.9.diff
@@ -0,0 +1,112 @@
+From e1cf625f4f225a007a5835421896089669195e02 Mon Sep 17 00:00:00 2001
+From: meator <meator.dev@gmail.com>
+Date: Wed, 26 Oct 2022 13:05:38 +0200
+Subject: [PATCH] Add shortcut to spawn new terminal in the current dir
+
+This commit is inspired by Santtu's st-newterm-20220221-0.8.5.diff. It
+removes the unused res variable, it makes use of _exit() instead of
+exit() and it replaces execlp() with execl() (PATH searching is useless
+when the path is absolute).
+---
+ config.def.h | 1 +
+ st.c | 38 ++++++++++++++++++++++++++++++++++++++
+ st.h | 1 +
+ 3 files changed, 40 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..7c75246 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { TERMMOD, XK_Return, newterm, {.i = 0} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index 62def59..0261283 100644
+--- a/st.c
++++ b/st.c
+@@ -20,6 +20,8 @@
+ #include "st.h"
+ #include "win.h"
+
++extern char *argv0;
++
+ #if defined(__linux)
+ #include <pty.h>
+ #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+@@ -153,6 +155,7 @@ typedef struct {
+ } STREscape;
+
+ static void execsh(char *, char **);
++static int chdir_by_pid(pid_t pid);
+ static void stty(char **);
+ static void sigchld(int);
+ static void ttywriteraw(const char *, size_t);
+@@ -806,6 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
+ if (pledge("stdio rpath tty proc", NULL) == -1)
+ die("pledge\n");
+ #endif
++ fcntl(m, F_SETFD, FD_CLOEXEC);
+ close(s);
+ cmdfd = m;
+ signal(SIGCHLD, sigchld);
+@@ -1054,6 +1058,40 @@ tswapscreen(void)
+ tfulldirt();
+ }
+
++void
++newterm(const Arg* a)
++{
++ switch (fork()) {
++ case -1:
++ die("fork failed: %s\n", strerror(errno));
++ break;
++ case 0:
++ switch (fork()) {
++ case -1:
++ fprintf(stderr, "fork failed: %s\n", strerror(errno));
++ _exit(1);
++ break;
++ case 0:
++ chdir_by_pid(pid);
++ execl("/proc/self/exe", argv0, NULL);
++ _exit(1);
++ break;
++ default:
++ _exit(0);
++ }
++ default:
++ wait(NULL);
++ }
++}
++
++static int
++chdir_by_pid(pid_t pid)
++{
++ char buf[32];
++ snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid);
++ return chdir(buf);
++}
++
+ void
+ tscrolldown(int orig, int n)
+ {
+diff --git a/st.h b/st.h
+index fd3b0d8..f2b03b0 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,7 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void newterm(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+--
+2.38.0
+
diff --git a/st/patches/st-openclipboard-20220217-0.8.5.diff b/st/patches/st-openclipboard-20220217-0.8.5.diff
new file mode 100644
index 0000000..196c543
--- /dev/null
+++ b/st/patches/st-openclipboard-20220217-0.8.5.diff
@@ -0,0 +1,91 @@
+From 1e752ae33791652d050e7d03e6d8e9df3fb459e3 Mon Sep 17 00:00:00 2001
+From: Santtu Lakkala <inz@inz.fi>
+Date: Thu, 17 Feb 2022 18:11:35 +0200
+Subject: [PATCH] Open url from clipboard
+
+Based on the previous versions of the patch, but uses double-fork/execlp
+instead of system() to avoid potential shell escaping issues and make
+the command line building unnecessary.
+---
+ config.def.h | 1 +
+ st.c | 2 +-
+ st.h | 1 +
+ x.c | 21 +++++++++++++++++++++
+ 4 files changed, 24 insertions(+), 1 deletion(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..a696ec7 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { MODKEY, XK_o, opencopied, {.v = "xdg-open"} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index 51049ba..4fbc5c8 100644
+--- a/st.c
++++ b/st.c
+@@ -810,7 +810,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
+ break;
+ default:
+ #ifdef __OpenBSD__
+- if (pledge("stdio rpath tty proc", NULL) == -1)
++ if (pledge("stdio rpath tty proc exec", NULL) == -1)
+ die("pledge\n");
+ #endif
+ close(s);
+diff --git a/st.h b/st.h
+index 519b9bd..3b4b395 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,7 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void opencopied(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+diff --git a/x.c b/x.c
+index 8a16faa..3a4e5f0 100644
+--- a/x.c
++++ b/x.c
+@@ -5,6 +5,7 @@
+ #include <locale.h>
+ #include <signal.h>
+ #include <sys/select.h>
++#include <sys/wait.h>
+ #include <time.h>
+ #include <unistd.h>
+ #include <libgen.h>
+@@ -2078,3 +2079,23 @@ run:
+
+ return 0;
+ }
++
++void
++opencopied(const Arg *arg)
++{
++ char * const clip = xsel.clipboard;
++ pid_t chpid;
++
++ if(!clip) {
++ fprintf(stderr, "Warning: nothing copied to clipboard\n");
++ return;
++ }
++
++ if ((chpid = fork()) == 0) {
++ if (fork() == 0)
++ execlp(arg->v, arg->v, clip, NULL);
++ exit(1);
++ }
++ if (chpid > 0)
++ waitpid(chpid, NULL, 0);
++}
+--
+2.32.0
+
diff --git a/st/patches/st-scrollback-0.9.2.diff b/st/patches/st-scrollback-0.9.2.diff
new file mode 100644
index 0000000..b022a05
--- /dev/null
+++ b/st/patches/st-scrollback-0.9.2.diff
@@ -0,0 +1,351 @@
+diff --git a/config.def.h b/config.def.h
+index 2cd740a..40b7d93 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
++ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index b9f66e7..2478942 100644
+--- a/st.c
++++ b/st.c
+@@ -35,6 +35,7 @@
+ #define ESC_ARG_SIZ 16
+ #define STR_BUF_SIZ ESC_BUF_SIZ
+ #define STR_ARG_SIZ ESC_ARG_SIZ
++#define HISTSIZE 2000
+
+ /* macros */
+ #define IS_SET(flag) ((term.mode & (flag)) != 0)
+@@ -42,6 +43,9 @@
+ #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+ #define ISDELIM(u) (u && wcschr(worddelimiters, u))
++#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
++ term.scr + HISTSIZE + 1) % HISTSIZE] : \
++ term.line[(y) - term.scr])
+
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+@@ -115,6 +119,9 @@ typedef struct {
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
++ Line hist[HISTSIZE]; /* history buffer */
++ int histi; /* history index */
++ int scr; /* scroll back */
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+@@ -185,8 +192,8 @@ static void tnewline(int);
+ static void tputtab(int);
+ static void tputc(Rune);
+ static void treset(void);
+-static void tscrollup(int, int);
+-static void tscrolldown(int, int);
++static void tscrollup(int, int, int);
++static void tscrolldown(int, int, int);
+ static void tsetattr(const int *, int);
+ static void tsetchar(Rune, const Glyph *, int, int);
+ static void tsetdirt(int, int);
+@@ -409,10 +416,10 @@ tlinelen(int y)
+ {
+ int i = term.col;
+
+- if (term.line[y][i - 1].mode & ATTR_WRAP)
++ if (TLINE(y)[i - 1].mode & ATTR_WRAP)
+ return i;
+
+- while (i > 0 && term.line[y][i - 1].u == ' ')
++ while (i > 0 && TLINE(y)[i - 1].u == ' ')
+ --i;
+
+ return i;
+@@ -521,7 +528,7 @@ selsnap(int *x, int *y, int direction)
+ * Snap around if the word wraps around at the end or
+ * beginning of a line.
+ */
+- prevgp = &term.line[*y][*x];
++ prevgp = &TLINE(*y)[*x];
+ prevdelim = ISDELIM(prevgp->u);
+ for (;;) {
+ newx = *x + direction;
+@@ -536,14 +543,14 @@ selsnap(int *x, int *y, int direction)
+ yt = *y, xt = *x;
+ else
+ yt = newy, xt = newx;
+- if (!(term.line[yt][xt].mode & ATTR_WRAP))
++ if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
+ break;
+ }
+
+ if (newx >= tlinelen(newy))
+ break;
+
+- gp = &term.line[newy][newx];
++ gp = &TLINE(newy)[newx];
+ delim = ISDELIM(gp->u);
+ if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+ || (delim && gp->u != prevgp->u)))
+@@ -564,14 +571,14 @@ selsnap(int *x, int *y, int direction)
+ *x = (direction < 0) ? 0 : term.col - 1;
+ if (direction < 0) {
+ for (; *y > 0; *y += direction) {
+- if (!(term.line[*y-1][term.col-1].mode
++ if (!(TLINE(*y-1)[term.col-1].mode
+ & ATTR_WRAP)) {
+ break;
+ }
+ }
+ } else if (direction > 0) {
+ for (; *y < term.row-1; *y += direction) {
+- if (!(term.line[*y][term.col-1].mode
++ if (!(TLINE(*y)[term.col-1].mode
+ & ATTR_WRAP)) {
+ break;
+ }
+@@ -602,13 +609,13 @@ getsel(void)
+ }
+
+ if (sel.type == SEL_RECTANGULAR) {
+- gp = &term.line[y][sel.nb.x];
++ gp = &TLINE(y)[sel.nb.x];
+ lastx = sel.ne.x;
+ } else {
+- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
++ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
+ lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
+ }
+- last = &term.line[y][MIN(lastx, linelen-1)];
++ last = &TLINE(y)[MIN(lastx, linelen-1)];
+ while (last >= gp && last->u == ' ')
+ --last;
+
+@@ -844,6 +851,9 @@ void
+ ttywrite(const char *s, size_t n, int may_echo)
+ {
+ const char *next;
++ Arg arg = (Arg) { .i = term.scr };
++
++ kscrolldown(&arg);
+
+ if (may_echo && IS_SET(MODE_ECHO))
+ twrite(s, n, 1);
+@@ -1055,13 +1065,53 @@ tswapscreen(void)
+ }
+
+ void
+-tscrolldown(int orig, int n)
++kscrolldown(const Arg* a)
++{
++ int n = a->i;
++
++ if (n < 0)
++ n = term.row + n;
++
++ if (n > term.scr)
++ n = term.scr;
++
++ if (term.scr > 0) {
++ term.scr -= n;
++ selscroll(0, -n);
++ tfulldirt();
++ }
++}
++
++void
++kscrollup(const Arg* a)
++{
++ int n = a->i;
++
++ if (n < 0)
++ n = term.row + n;
++
++ if (term.scr <= HISTSIZE-n) {
++ term.scr += n;
++ selscroll(0, n);
++ tfulldirt();
++ }
++}
++
++void
++tscrolldown(int orig, int n, int copyhist)
+ {
+ int i;
+ Line temp;
+
+ LIMIT(n, 0, term.bot-orig+1);
+
++ if (copyhist) {
++ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
++ temp = term.hist[term.histi];
++ term.hist[term.histi] = term.line[term.bot];
++ term.line[term.bot] = temp;
++ }
++
+ tsetdirt(orig, term.bot-n);
+ tclearregion(0, term.bot-n+1, term.col-1, term.bot);
+
+@@ -1071,17 +1121,28 @@ tscrolldown(int orig, int n)
+ term.line[i-n] = temp;
+ }
+
+- selscroll(orig, n);
++ if (term.scr == 0)
++ selscroll(orig, n);
+ }
+
+ void
+-tscrollup(int orig, int n)
++tscrollup(int orig, int n, int copyhist)
+ {
+ int i;
+ Line temp;
+
+ LIMIT(n, 0, term.bot-orig+1);
+
++ if (copyhist) {
++ term.histi = (term.histi + 1) % HISTSIZE;
++ temp = term.hist[term.histi];
++ term.hist[term.histi] = term.line[orig];
++ term.line[orig] = temp;
++ }
++
++ if (term.scr > 0 && term.scr < HISTSIZE)
++ term.scr = MIN(term.scr + n, HISTSIZE-1);
++
+ tclearregion(0, orig, term.col-1, orig+n-1);
+ tsetdirt(orig+n, term.bot);
+
+@@ -1091,7 +1152,8 @@ tscrollup(int orig, int n)
+ term.line[i+n] = temp;
+ }
+
+- selscroll(orig, -n);
++ if (term.scr == 0)
++ selscroll(orig, -n);
+ }
+
+ void
+@@ -1120,7 +1182,7 @@ tnewline(int first_col)
+ int y = term.c.y;
+
+ if (y == term.bot) {
+- tscrollup(term.top, 1);
++ tscrollup(term.top, 1, 1);
+ } else {
+ y++;
+ }
+@@ -1285,14 +1347,14 @@ void
+ tinsertblankline(int n)
+ {
+ if (BETWEEN(term.c.y, term.top, term.bot))
+- tscrolldown(term.c.y, n);
++ tscrolldown(term.c.y, n, 0);
+ }
+
+ void
+ tdeleteline(int n)
+ {
+ if (BETWEEN(term.c.y, term.top, term.bot))
+- tscrollup(term.c.y, n);
++ tscrollup(term.c.y, n, 0);
+ }
+
+ int32_t
+@@ -1730,11 +1792,11 @@ csihandle(void)
+ case 'S': /* SU -- Scroll <n> line up */
+ if (csiescseq.priv) break;
+ DEFAULT(csiescseq.arg[0], 1);
+- tscrollup(term.top, csiescseq.arg[0]);
++ tscrollup(term.top, csiescseq.arg[0], 0);
+ break;
+ case 'T': /* SD -- Scroll <n> line down */
+ DEFAULT(csiescseq.arg[0], 1);
+- tscrolldown(term.top, csiescseq.arg[0]);
++ tscrolldown(term.top, csiescseq.arg[0], 0);
+ break;
+ case 'L': /* IL -- Insert <n> blank lines */
+ DEFAULT(csiescseq.arg[0], 1);
+@@ -2306,7 +2368,7 @@ eschandle(uchar ascii)
+ return 0;
+ case 'D': /* IND -- Linefeed */
+ if (term.c.y == term.bot) {
+- tscrollup(term.top, 1);
++ tscrollup(term.top, 1, 1);
+ } else {
+ tmoveto(term.c.x, term.c.y+1);
+ }
+@@ -2319,7 +2381,7 @@ eschandle(uchar ascii)
+ break;
+ case 'M': /* RI -- Reverse index */
+ if (term.c.y == term.top) {
+- tscrolldown(term.top, 1);
++ tscrolldown(term.top, 1, 1);
+ } else {
+ tmoveto(term.c.x, term.c.y-1);
+ }
+@@ -2542,7 +2604,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
+ void
+ tresize(int col, int row)
+ {
+- int i;
++ int i, j;
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
+ int *bp;
+@@ -2579,6 +2641,14 @@ tresize(int col, int row)
+ term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
+ term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+
++ for (i = 0; i < HISTSIZE; i++) {
++ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
++ for (j = mincol; j < col; j++) {
++ term.hist[i][j] = term.c.attr;
++ term.hist[i][j].u = ' ';
++ }
++ }
++
+ /* resize each row to new width, zero-pad if needed */
+ for (i = 0; i < minrow; i++) {
+ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+@@ -2637,7 +2707,7 @@ drawregion(int x1, int y1, int x2, int y2)
+ continue;
+
+ term.dirty[y] = 0;
+- xdrawline(term.line[y], x1, y, x2);
++ xdrawline(TLINE(y), x1, y, x2);
+ }
+ }
+
+@@ -2658,8 +2728,9 @@ draw(void)
+ cx--;
+
+ drawregion(0, 0, term.col, term.row);
+- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++ if (term.scr == 0)
++ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+ term.ocx = cx;
+ term.ocy = term.c.y;
+ xfinishdraw();
+diff --git a/st.h b/st.h
+index fd3b0d8..818a6f8 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,8 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void kscrolldown(const Arg *);
++void kscrollup(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
diff --git a/st/patches/st-scrollback-mouse-0.9.2.diff b/st/patches/st-scrollback-mouse-0.9.2.diff
new file mode 100644
index 0000000..a956d2b
--- /dev/null
+++ b/st/patches/st-scrollback-mouse-0.9.2.diff
@@ -0,0 +1,25 @@
+From 6b7e7e6c5c44dd6347ad49691b80d808c1b0cb77 Mon Sep 17 00:00:00 2001
+From: Jernej Jakob <jernej.jakob@gmail.com>
+Date: Mon, 1 Jul 2024 14:00:02 +0200
+Subject: [PATCH] [st][patch] Update st-scrollback-mouse for 0.9.2
+
+---
+ config.def.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 8b25d40..d259675 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask;
+ */
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release */
++ { ShiftMask, Button4, kscrollup, {.i = 1} },
++ { ShiftMask, Button5, kscrolldown, {.i = 1} },
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+--
+2.44.2
+
diff --git a/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff
new file mode 100644
index 0000000..6a8722b
--- /dev/null
+++ b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff
@@ -0,0 +1,78 @@
+From 580e3f386e9215707100e9ba44797701943fd927 Mon Sep 17 00:00:00 2001
+From: asparagii <michele.lambertucci1@gmail.com>
+Date: Thu, 27 Jan 2022 15:49:27 +0100
+Subject: [PATCH] st-scrollback-mouse-altscreen
+
+---
+ config.def.h | 4 ++--
+ st.c | 5 +++++
+ st.h | 1 +
+ x.c | 2 ++
+ 4 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index c217315..c223706 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -176,8 +176,8 @@ static uint forcemousemod = ShiftMask;
+ */
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release */
+- { ShiftMask, Button4, kscrollup, {.i = 1} },
+- { ShiftMask, Button5, kscrolldown, {.i = 1} },
++ { XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, /* !alt */ -1 },
++ { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, /* !alt */ -1 },
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+diff --git a/st.c b/st.c
+index f3af82b..876a6bf 100644
+--- a/st.c
++++ b/st.c
+@@ -1060,6 +1060,11 @@ tnew(int col, int row)
+ treset();
+ }
+
++int tisaltscr(void)
++{
++ return IS_SET(MODE_ALTSCREEN);
++}
++
+ void
+ tswapscreen(void)
+ {
+diff --git a/st.h b/st.h
+index da36b34..e95c6f8 100644
+--- a/st.h
++++ b/st.h
+@@ -89,6 +89,7 @@ void sendbreak(const Arg *);
+ void toggleprinter(const Arg *);
+
+ int tattrset(int);
++int tisaltscr(void);
+ void tnew(int, int);
+ void tresize(int, int);
+ void tsetdirtattr(int);
+diff --git a/x.c b/x.c
+index cd96575..9274556 100644
+--- a/x.c
++++ b/x.c
+@@ -34,6 +34,7 @@ typedef struct {
+ void (*func)(const Arg *);
+ const Arg arg;
+ uint release;
++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
+ } MouseShortcut;
+
+ typedef struct {
+@@ -455,6 +456,7 @@ mouseaction(XEvent *e, uint release)
+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+ if (ms->release == release &&
+ ms->button == e->xbutton.button &&
++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
+ (match(ms->mod, state) || /* exact or forced */
+ match(ms->mod, state & ~forcemousemod))) {
+ ms->func(&(ms->arg));
+--
+2.34.1
+
diff --git a/st/patches/st-scrollback-mouse-increment-0.9.2.diff b/st/patches/st-scrollback-mouse-increment-0.9.2.diff
new file mode 100644
index 0000000..97689d3
--- /dev/null
+++ b/st/patches/st-scrollback-mouse-increment-0.9.2.diff
@@ -0,0 +1,30 @@
+From bf7f0cf6ff2b47c65f750de6e30dce09a34f9201 Mon Sep 17 00:00:00 2001
+From: Jernej Jakob <jernej.jakob@gmail.com>
+Date: Mon, 1 Jul 2024 14:02:36 +0200
+Subject: [PATCH] [st][patch] Update st-scrollback-mouse-increment for 0.9.2
+
+---
+ config.def.h | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index d259675..0c427ee 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -174,10 +174,11 @@ static uint forcemousemod = ShiftMask;
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+ */
++const unsigned int mousescrollincrement = 1;
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release */
+- { ShiftMask, Button4, kscrollup, {.i = 1} },
+- { ShiftMask, Button5, kscrolldown, {.i = 1} },
++ { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement} },
++ { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement} },
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+--
+2.44.2
+
diff --git a/st/patches/st-spoiler-20180309-c5ba9c0.diff b/st/patches/st-spoiler-20180309-c5ba9c0.diff
new file mode 100644
index 0000000..e6b7ab5
--- /dev/null
+++ b/st/patches/st-spoiler-20180309-c5ba9c0.diff
@@ -0,0 +1,21 @@
+diff --git a/x.c b/x.c
+--- a/x.c
++++ b/x.c
+@@ -1330,9 +1330,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+ }
+
+ if (base.mode & ATTR_REVERSE) {
+- temp = fg;
+- fg = bg;
+- bg = temp;
++ if (bg == fg) {
++ bg = &dc.col[defaultfg];
++ fg = &dc.col[defaultbg];
++ } else {
++ temp = fg;
++ fg = bg;
++ bg = temp;
++ }
+ }
+
+ if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK)
diff --git a/st/patches/st-swapmouse-0.8.4.diff b/st/patches/st-swapmouse-0.8.4.diff
new file mode 100644
index 0000000..d948dae
--- /dev/null
+++ b/st/patches/st-swapmouse-0.8.4.diff
@@ -0,0 +1,37 @@
+diff -up st-0.8.4-ori/x.c st-0.8.4/x.c
+--- st-0.8.4-ori/x.c 2020-06-19 14:59:45.000000000 +0530
++++ st-0.8.4/x.c 2020-07-20 03:39:56.260922736 +0530
+@@ -254,6 +254,9 @@ static char *opt_title = NULL;
+
+ static int oldbutton = 3; /* button event on startup: 3 = release */
+
++static Cursor cursor;
++static XColor xmousefg, xmousebg;
++
+ void
+ clipcopy(const Arg *dummy)
+ {
+@@ -1099,10 +1102,8 @@ void
+ xinit(int cols, int rows)
+ {
+ XGCValues gcvalues;
+- Cursor cursor;
+ Window parent;
+ pid_t thispid = getpid();
+- XColor xmousefg, xmousebg;
+
+ if (!(xw.dpy = XOpenDisplay(NULL)))
+ die("can't open display\n");
+@@ -1683,6 +1684,12 @@ xsetmode(int set, unsigned int flags)
+ {
+ int mode = win.mode;
+ MODBIT(win.mode, set, flags);
++ if (flags & MODE_MOUSE) {
++ if (win.mode & MODE_MOUSE)
++ XUndefineCursor(xw.dpy, xw.win);
++ else
++ XDefineCursor(xw.dpy, xw.win, cursor);
++ }
+ if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
+ redraw();
+ }
diff --git a/st/patches/st-title_parsing_fix-0.8.5.diff b/st/patches/st-title_parsing_fix-0.8.5.diff
new file mode 100644
index 0000000..a5cee40
--- /dev/null
+++ b/st/patches/st-title_parsing_fix-0.8.5.diff
@@ -0,0 +1,145 @@
+From 8446609384429bfc4342ede4b52ff42214ad2b77 Mon Sep 17 00:00:00 2001
+From: Rizqi Nur Assyaufi <bandithijo@gmail.com>
+Date: Mon, 18 Jul 2022 00:35:26 +0800
+Subject: [PATCH] Fixes title parsing for st-0.8.5
+
+In st, titles get truncated after the first ';' character, this patch
+fixes that.
+---
+ st.c | 38 ++++++++++++++++++++------------------
+ 1 file changed, 20 insertions(+), 18 deletions(-)
+
+diff --git a/st.c b/st.c
+index 51049ba..a2e595c 100644
+--- a/st.c
++++ b/st.c
+@@ -42,6 +42,8 @@
+ #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+ #define ISDELIM(u) (u && wcschr(worddelimiters, u))
++#define STRESCARGREST(n) ((n) == 0 ? strescseq.buf : strescseq.argp[(n)-1] + 1)
++#define STRESCARGJUST(n) (*(strescseq.argp[n]) = '\0', STRESCARGREST(n))
+
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+@@ -148,7 +150,7 @@ typedef struct {
+ char *buf; /* allocated raw string */
+ size_t siz; /* allocation size */
+ size_t len; /* raw string length */
+- char *args[STR_ARG_SIZ];
++ char *argp[STR_ARG_SIZ]; /* pointers to the end of nth argument */
+ int narg; /* nb of args */
+ } STREscape;
+
+@@ -1885,29 +1887,30 @@ strhandle(void)
+ int j, narg, par;
+
+ term.esc &= ~(ESC_STR_END|ESC_STR);
+- strparse();
+- par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
++ strescseq.buf[strescseq.len] = '\0';
+
+ switch (strescseq.type) {
+ case ']': /* OSC -- Operating System Command */
++ strparse();
++ par = (narg = strescseq.narg) ? atoi(STRESCARGJUST(0)) : 0;
+ switch (par) {
+ case 0:
+ if (narg > 1) {
+- xsettitle(strescseq.args[1]);
+- xseticontitle(strescseq.args[1]);
++ xsettitle(STRESCARGREST(1));
++ xseticontitle(STRESCARGREST(1));
+ }
+ return;
+ case 1:
+ if (narg > 1)
+- xseticontitle(strescseq.args[1]);
++ xseticontitle(STRESCARGREST(1));
+ return;
+ case 2:
+ if (narg > 1)
+- xsettitle(strescseq.args[1]);
++ xsettitle(STRESCARGREST(1));
+ return;
+ case 52:
+ if (narg > 2 && allowwindowops) {
+- dec = base64dec(strescseq.args[2]);
++ dec = base64dec(STRESCARGJUST(2));
+ if (dec) {
+ xsetsel(dec);
+ xclipcopy();
+@@ -1920,7 +1923,7 @@ strhandle(void)
+ if (narg < 2)
+ break;
+
+- p = strescseq.args[1];
++ p = STRESCARGREST(1);
+
+ if (!strcmp(p, "?"))
+ osc_color_response(defaultfg, 10);
+@@ -1933,7 +1936,7 @@ strhandle(void)
+ if (narg < 2)
+ break;
+
+- p = strescseq.args[1];
++ p = STRESCARGREST(1);
+
+ if (!strcmp(p, "?"))
+ osc_color_response(defaultbg, 11);
+@@ -1946,7 +1949,7 @@ strhandle(void)
+ if (narg < 2)
+ break;
+
+- p = strescseq.args[1];
++ p = STRESCARGREST(1);
+
+ if (!strcmp(p, "?"))
+ osc_color_response(defaultcs, 12);
+@@ -1958,10 +1961,10 @@ strhandle(void)
+ case 4: /* color set */
+ if (narg < 3)
+ break;
+- p = strescseq.args[2];
++ p = STRESCARGJUST(2);
+ /* FALLTHROUGH */
+ case 104: /* color reset */
+- j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
++ j = (narg > 1) ? atoi(STRESCARGJUST(1)) : -1;
+
+ if (p && !strcmp(p, "?"))
+ osc4_color_response(j);
+@@ -1981,7 +1984,7 @@ strhandle(void)
+ }
+ break;
+ case 'k': /* old title set compatibility */
+- xsettitle(strescseq.args[0]);
++ xsettitle(strescseq.buf);
+ return;
+ case 'P': /* DCS -- Device Control String */
+ case '_': /* APC -- Application Program Command */
+@@ -2000,18 +2003,17 @@ strparse(void)
+ char *p = strescseq.buf;
+
+ strescseq.narg = 0;
+- strescseq.buf[strescseq.len] = '\0';
+
+ if (*p == '\0')
+ return;
+
+ while (strescseq.narg < STR_ARG_SIZ) {
+- strescseq.args[strescseq.narg++] = p;
+ while ((c = *p) != ';' && c != '\0')
+- ++p;
++ p++;
++ strescseq.argp[strescseq.narg++] = p;
+ if (c == '\0')
+ return;
+- *p++ = '\0';
++ p++;
+ }
+ }
+
+--
+2.37.1
+
diff --git a/st/patches/st-vertcenter-20231003-eb3b894.diff b/st/patches/st-vertcenter-20231003-eb3b894.diff
new file mode 100644
index 0000000..f2d08a2
--- /dev/null
+++ b/st/patches/st-vertcenter-20231003-eb3b894.diff
@@ -0,0 +1,65 @@
+From c85891b21261b68b09ed9ae6a1ca18655ef19e69 Mon Sep 17 00:00:00 2001
+From: roket1428 <meorhan@protonmail.com>
+Date: Tue, 3 Oct 2023 11:10:39 +0300
+Subject: [PATCH] vertcenter patch
+
+---
+ x.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/x.c b/x.c
+index aa09997..9ecb46e 100644
+--- a/x.c
++++ b/x.c
+@@ -83,6 +83,7 @@ typedef struct {
+ int w, h; /* window width and height */
+ int ch; /* char height */
+ int cw; /* char width */
++ int cyo; /* char y offset */
+ int mode; /* window state/mode flags */
+ int cursor; /* cursor style */
+ } TermWindow;
+@@ -1031,6 +1032,7 @@ xloadfonts(const char *fontstr, double fontsize)
+ /* Setting character width and height. */
+ win.cw = ceilf(dc.font.width * cwscale);
+ win.ch = ceilf(dc.font.height * chscale);
++ win.cyo = ceilf(dc.font.height * (chscale - 1) / 2);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+@@ -1255,7 +1257,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ FcCharSet *fccharset;
+ int i, f, numspecs = 0;
+
+- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
++ for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) {
+ /* Fetch rune and mode for current glyph. */
+ rune = glyphs[i].u;
+ mode = glyphs[i].mode;
+@@ -1280,7 +1282,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
+ }
+- yp = winy + font->ascent;
++ yp = winy + font->ascent + win.cyo;
+ }
+
+ /* Lookup character index with default font. */
+@@ -1493,12 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE) {
+- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1,
+ width, 1);
+ }
+
+ if (base.mode & ATTR_STRUCK) {
+- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3,
+ width, 1);
+ }
+
+--
+2.42.0
+
diff --git a/st/patches/st-w3m-0.8.3.diff b/st/patches/st-w3m-0.8.3.diff
new file mode 100644
index 0000000..a4e104b
--- /dev/null
+++ b/st/patches/st-w3m-0.8.3.diff
@@ -0,0 +1,42 @@
+From 69cffc587b54b0a9cd81adb87abad8e526d5b25b Mon Sep 17 00:00:00 2001
+From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
+Date: Thu, 4 Jun 2020 17:35:08 +0300
+Subject: [PATCH] support w3m images
+
+w3m images are a hack which renders on top of the terminal's drawable,
+which didn't work in st because when using double buffering, the front
+buffer (on which w3m draws its images) is ignored, and st draws only
+on the back buffer, which is then copied to the front buffer.
+
+There's a patch to make it work at the FAQ already, but that patch
+canceles double-buffering, which can have negative side effects on
+some cases such as flickering.
+
+This patch achieves the same goal but instead of canceling the double
+buffer it first copies the front buffer to the back buffer.
+
+This has the same issues as the FAQ patch in that the cursor line is
+deleted at the image (because st renders always full lines), but
+otherwise it's simpler and does keeps double buffering.
+---
+ x.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/x.c b/x.c
+index e5f1737..b6ae162 100644
+--- a/x.c
++++ b/x.c
+@@ -1594,6 +1594,8 @@ xsettitle(char *p)
+ int
+ xstartdraw(void)
+ {
++ if (IS_SET(MODE_VISIBLE))
++ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
+ return IS_SET(MODE_VISIBLE);
+ }
+
+
+base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027
+--
+2.17.1
+
diff --git a/st/patches/st-xclearwin-20200419-6ee7143.diff b/st/patches/st-xclearwin-20200419-6ee7143.diff
new file mode 100644
index 0000000..52f0477
--- /dev/null
+++ b/st/patches/st-xclearwin-20200419-6ee7143.diff
@@ -0,0 +1,62 @@
+From 6ee7143600e5ac6c7a26d2ee985ac2a3087a5570 Mon Sep 17 00:00:00 2001
+From: Christian Tenllado <ctenllado@gmail.com>
+Date: Sun, 19 Apr 2020 11:57:31 +0200
+Subject: [PATCH] xclearwin clears the window
+
+When an OCS sequence was used to change the bg color, the borders where
+dirty. This simple patch just clears the window before the redraw of the
+terminal when the bg color has been changed. This is apparently enough
+and seams to be very smooth. There was a TODO comment for it on the st.c
+file, which I removed.
+---
+ st.c | 6 ++----
+ win.h | 1 +
+ x.c | 6 ++++++
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/st.c b/st.c
+index 3e48410..2efb4bd 100644
+--- a/st.c
++++ b/st.c
+@@ -1874,10 +1874,8 @@ strhandle(void)
+ fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
+ j, p ? p : "(null)");
+ } else {
+- /*
+- * TODO if defaultbg color is changed, borders
+- * are dirty
+- */
++ if (j == defaultbg)
++ xclearwin();
+ redraw();
+ }
+ return;
+diff --git a/win.h b/win.h
+index a6ef1b9..d7b4980 100644
+--- a/win.h
++++ b/win.h
+@@ -37,3 +37,4 @@ void xsetpointermotion(int);
+ void xsetsel(char *);
+ int xstartdraw(void);
+ void xximspot(int, int);
++void xclearwin(void);
+diff --git a/x.c b/x.c
+index 4cf6b21..afd35e0 100644
+--- a/x.c
++++ b/x.c
+@@ -825,6 +825,12 @@ xclear(int x1, int y1, int x2, int y2)
+ x1, y1, x2-x1, y2-y1);
+ }
+
++void
++xclearwin(void)
++{
++ xclear(0, 0, win.w, win.h);
++}
++
+ void
+ xhints(void)
+ {
+--
+2.20.1
+
diff --git a/st/patches/st-xresources-20200604-9ba7ecf.diff b/st/patches/st-xresources-20200604-9ba7ecf.diff
new file mode 100644
index 0000000..01d6db9
--- /dev/null
+++ b/st/patches/st-xresources-20200604-9ba7ecf.diff
@@ -0,0 +1,183 @@
+# From 2752a599ee01305a435729bfacf43b1dde7cf0ef Mon Sep 17 00:00:00 2001
+# From: Benji Encalada Mora <benji@encalada.dev>
+# Date: Thu, 4 Jun 2020 00:41:10 -0500
+# Subject: [PATCH] fix: replace xfps and actionfps variables
+#
+# ---
+# config.def.h | 36 ++++++++++++++++++++++++
+# x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++---
+# 2 files changed, 110 insertions(+), 4 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..9b99782 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -168,6 +168,42 @@ static unsigned int defaultattr = 11;
+ */
+ static uint forcemousemod = ShiftMask;
+
++/*
++ * Xresources preferences to load at startup
++ */
++ResourcePref resources[] = {
++ { "font", STRING, &font },
++ { "color0", STRING, &colorname[0] },
++ { "color1", STRING, &colorname[1] },
++ { "color2", STRING, &colorname[2] },
++ { "color3", STRING, &colorname[3] },
++ { "color4", STRING, &colorname[4] },
++ { "color5", STRING, &colorname[5] },
++ { "color6", STRING, &colorname[6] },
++ { "color7", STRING, &colorname[7] },
++ { "color8", STRING, &colorname[8] },
++ { "color9", STRING, &colorname[9] },
++ { "color10", STRING, &colorname[10] },
++ { "color11", STRING, &colorname[11] },
++ { "color12", STRING, &colorname[12] },
++ { "color13", STRING, &colorname[13] },
++ { "color14", STRING, &colorname[14] },
++ { "color15", STRING, &colorname[15] },
++ { "background", STRING, &colorname[256] },
++ { "foreground", STRING, &colorname[257] },
++ { "cursorColor", STRING, &colorname[258] },
++ { "termname", STRING, &termname },
++ { "shell", STRING, &shell },
++ { "minlatency", INTEGER, &minlatency },
++ { "maxlatency", INTEGER, &maxlatency },
++ { "blinktimeout", INTEGER, &blinktimeout },
++ { "bellvolume", INTEGER, &bellvolume },
++ { "tabspaces", INTEGER, &tabspaces },
++ { "borderpx", INTEGER, &borderpx },
++ { "cwscale", FLOAT, &cwscale },
++ { "chscale", FLOAT, &chscale },
++};
++
+ /*
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+diff --git a/x.c b/x.c
+index 210f184..76f167f 100644
+--- a/x.c
++++ b/x.c
+@@ -14,6 +14,7 @@
+ #include <X11/keysym.h>
+ #include <X11/Xft/Xft.h>
+ #include <X11/XKBlib.h>
++#include <X11/Xresource.h>
+
+ char *argv0;
+ #include "arg.h"
+@@ -45,6 +46,19 @@ typedef struct {
+ signed char appcursor; /* application cursor */
+ } Key;
+
++/* Xresources preferences */
++enum resource_type {
++ STRING = 0,
++ INTEGER = 1,
++ FLOAT = 2
++};
++
++typedef struct {
++ char *name;
++ enum resource_type type;
++ void *dst;
++} ResourcePref;
++
+ /* X modifiers */
+ #define XK_ANY_MOD UINT_MAX
+ #define XK_NO_MOD 0
+@@ -828,8 +842,8 @@ xclear(int x1, int y1, int x2, int y2)
+ void
+ xhints(void)
+ {
+- XClassHint class = {opt_name ? opt_name : termname,
+- opt_class ? opt_class : termname};
++ XClassHint class = {opt_name ? opt_name : "st",
++ opt_class ? opt_class : "St"};
+ XWMHints wm = {.flags = InputHint, .input = 1};
+ XSizeHints *sizeh;
+
+@@ -1104,8 +1118,6 @@ xinit(int cols, int rows)
+ pid_t thispid = getpid();
+ XColor xmousefg, xmousebg;
+
+- if (!(xw.dpy = XOpenDisplay(NULL)))
+- die("can't open display\n");
+ xw.scr = XDefaultScreen(xw.dpy);
+ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
+
+@@ -1964,6 +1976,59 @@ run(void)
+ }
+ }
+
++int
++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
++{
++ char **sdst = dst;
++ int *idst = dst;
++ float *fdst = dst;
++
++ char fullname[256];
++ char fullclass[256];
++ char *type;
++ XrmValue ret;
++
++ snprintf(fullname, sizeof(fullname), "%s.%s",
++ opt_name ? opt_name : "st", name);
++ snprintf(fullclass, sizeof(fullclass), "%s.%s",
++ opt_class ? opt_class : "St", name);
++ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
++
++ XrmGetResource(db, fullname, fullclass, &type, &ret);
++ if (ret.addr == NULL || strncmp("String", type, 64))
++ return 1;
++
++ switch (rtype) {
++ case STRING:
++ *sdst = ret.addr;
++ break;
++ case INTEGER:
++ *idst = strtoul(ret.addr, NULL, 10);
++ break;
++ case FLOAT:
++ *fdst = strtof(ret.addr, NULL);
++ break;
++ }
++ return 0;
++}
++
++void
++config_init(void)
++{
++ char *resm;
++ XrmDatabase db;
++ ResourcePref *p;
++
++ XrmInitialize();
++ resm = XResourceManagerString(xw.dpy);
++ if (!resm)
++ return;
++
++ db = XrmGetStringDatabase(resm);
++ for (p = resources; p < resources + LEN(resources); p++)
++ resource_load(db, p->name, p->type, p->dst);
++}
++
+ void
+ usage(void)
+ {
+@@ -2037,6 +2102,11 @@ run:
+
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
++
++ if(!(xw.dpy = XOpenDisplay(NULL)))
++ die("Can't open display\n");
++
++ config_init();
+ cols = MAX(cols, 1);
+ rows = MAX(rows, 1);
+ tnew(cols, rows);
+--
+2.26.2
diff --git a/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff
new file mode 100644
index 0000000..d7817a0
--- /dev/null
+++ b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff
@@ -0,0 +1,288 @@
+diff --git a/config.def.h b/config.def.h
+index f92798a..517abbb 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -9,5 +9,19 @@
+ static int borderpx = 2;
+
++/*
++ * Override/adjust fontsize of choosen monitors:
++ */
++MonitorConfig monitors_config[] = {
++ // skip = fixed relative points size (monitor dpi)
++ // =0 : fixed absolute pixel size (default screen dpi)
++ // >0 : auto absolute pixel size (monitor dpi)
++ // <0 : auto relative points size (monitor dpi)
++ // {"DP-1", 0}, // BUG:(size=0): not restored to default after back'n'forth
++ {"HDMI-0~1", -20}, // BUG:(ignored DPI=220): = 20 is eqv to 10pt (DPI=110)
++ {"HDMI-0~2", -14},
++};
++float winmovethreshold = 0.6;
++
+ /*
+ * What program is execed by st depends of these precedence rules:
+ * 1: program passed with -e
+@@ -272,6 +272,7 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Prior, zoom, {.f = +1} },
+ { TERMMOD, XK_Next, zoom, {.f = -1} },
+ { TERMMOD, XK_Home, zoomreset, {.f = 0} },
++ { TERMMOD, XK_End, refreshxrandr, {.i = 0} },
+ { TERMMOD, XK_C, clipcopy, {.i = 0} },
+ { TERMMOD, XK_V, clippaste, {.i = 0} },
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+diff --git a/config.mk b/config.mk
+index aaa54ff..2d28597 100644
+--- a/config.mk
++++ b/config.mk
+@@ -24,5 +24,7 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
+
++LIBS += -lXrandr
++
+ # flags
+ STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+ STLDFLAGS = $(LIBS) $(LDFLAGS)
+diff --git a/x.c b/x.c
+index 684311c..ce1c418 100644
+--- a/x.c
++++ b/x.c
+@@ -14,6 +14,7 @@
+ #include <X11/keysym.h>
+ #include <X11/Xft/Xft.h>
+ #include <X11/XKBlib.h>
++#include <X11/extensions/Xrandr.h>
+
+ char *argv0;
+ #include "arg.h"
+@@ -45,5 +46,18 @@ typedef struct {
+ signed char appcursor; /* application cursor */
+ } Key;
+
++typedef struct {
++ const char *name;
++ float defaultfontsize;
++} MonitorConfig;
++
++typedef struct {
++ Atom name;
++ int x, y, w, h;
++ float defaultfontsize, usedfontsize;
++} MonitorInfo;
++
++static void refreshxrandr(const Arg *dummy);
++
+ /* X modifiers */
+ #define XK_ANY_MOD UINT_MAX
+@@ -233,7 +233,12 @@ static XWindow xw;
+ [PropertyNotify] = propnotify,
+ [SelectionRequest] = selrequest,
+ };
+
++static double defaultrelfontsize = 0;
++static MonitorInfo *monitors_info = NULL;
++static int monitors_num = 0;
++static int prev_mindex = -1;
++
+ /* Globals */
+ static DC dc;
+ static XWindow xw;
+@@ -2280,6 +2280,144 @@ xseturgency(int add)
+ XFree(h);
+ }
+
++static void
++cachemonitorinfo()
++{
++ int prev_num = monitors_num;
++ MonitorInfo *prev_info = monitors_info;
++ XRRMonitorInfo *xmonitors = XRRGetMonitors(xw.dpy, XRootWindow(xw.dpy, xw.scr), 1, &monitors_num);
++ if (!monitors_num)
++ die("xrandr found no monitors");
++
++ monitors_info = xmalloc(monitors_num * sizeof(MonitorInfo));
++
++ for (int i = 0; i < monitors_num; ++i) {
++ XRRMonitorInfo *xm = &xmonitors[i];
++ MonitorInfo *m = &monitors_info[i];
++
++ m->name = xm->name;
++ m->x = xm->x;
++ m->y = xm->y;
++ m->w = xm->width;
++ m->h = xm->height;
++
++ float px_mm = ((float)m->w / xm->mwidth + (float)m->h / xm->mheight) / 2;
++ float px_pt = 25.4 * px_mm / 72;
++ m->defaultfontsize = defaultrelfontsize * px_pt;
++
++ // Override defaultfontsize (dpi) by user config
++ char *name = XGetAtomName(xw.dpy, xm->name);
++ for (int j = 0; j < LEN(monitors_config); ++j)
++ if (!strcmp(name, monitors_config[j].name)) {
++ m->defaultfontsize = monitors_config[j].defaultfontsize;
++ if (m->defaultfontsize < 0)
++ m->defaultfontsize *= -px_pt;
++ break;
++ }
++ // fprintf(stderr, "%s: %fpx, %f\n", name, m->defaultfontsize, m->usedfontsize);
++ XFree(name);
++
++ // Restore usedfontsize (zoom) after re-cache for monitors with the same name
++ m->usedfontsize = m->defaultfontsize;
++ for (int j = 0; j < prev_num; ++j)
++ if (prev_info[j].name == m->name) {
++ m->usedfontsize = prev_info[j].usedfontsize;
++ break;
++ }
++ }
++
++ XRRFreeMonitors(xmonitors);
++ free(prev_info);
++}
++
++static int
++getmonitorindex_threshold(int w, int h, int x, int y)
++{
++ int mindex = -1;
++ float fontsize = 0;
++ int thresholdarea = winmovethreshold * w * h;
++
++ for (int i = 0; i < monitors_num; ++i) {
++ MonitorInfo *m = &monitors_info[i];
++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x));
++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y));
++ int area = overlap_w * overlap_h;
++ // Choose monitor with largest dpi (defaultfontsize)
++ // from all "mirrored"/overlapped (e.g. projector)
++ if (area >= thresholdarea && fontsize < m->defaultfontsize) {
++ fontsize = m->defaultfontsize;
++ mindex = i;
++ }
++ }
++ return mindex;
++}
++
++static int
++getmonitorindex_nearest(int w, int h, int x, int y)
++{
++ int mindex = -1;
++ float fontsize = 0;
++ int overlaparea = 0;
++
++ for (int i = 0; i < monitors_num; ++i) {
++ MonitorInfo *m = &monitors_info[i];
++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x));
++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y));
++ int area = overlap_w * overlap_h;
++ // Choose monitor with largest overlapping area
++ // e.g. when "st" is initially spawned in-between monitors
++ if (area > overlaparea) {
++ overlaparea = area;
++ mindex = i;
++ }
++ }
++ return mindex;
++}
++
++static void
++adjustmonitorfontsize(int mindex)
++{
++ if (mindex < 0 || prev_mindex == mindex)
++ return;
++ // Save zoom of current monitor before switching
++ if (prev_mindex >= 0)
++ monitors_info[prev_mindex].usedfontsize = usedfontsize;
++
++ defaultfontsize = monitors_info[mindex].defaultfontsize;
++ // fprintf(stderr, "Crossing: %fpx\n", defaultfontsize);
++
++ // NOTE: do nothing if font size differs by less than 1%
++ double fontsize = monitors_info[mindex].usedfontsize;
++ double delta = 0.01 * usedfontsize;
++ if (!BETWEEN(fontsize - usedfontsize, -delta, delta)) {
++ // fprintf(stderr, "Adjusted: %fpx\n", fontsize);
++ xunloadfonts();
++ xloadfonts(usedfont, fontsize);
++ }
++ prev_mindex = mindex;
++}
++
++void
++refreshxrandr(const Arg *dummy)
++{
++ // Reset index to detect change of window association on "xrandr ... --primary"
++ // otherwise: zoom won't be saved on switching and new font size won't be loaded
++ // CRIT!!! event from xrandr may place another monitor into same index
++ if (prev_mindex >= 0)
++ monitors_info[prev_mindex].usedfontsize = usedfontsize;
++ prev_mindex = -1;
++
++ XWindowAttributes xattr = {0};
++ cachemonitorinfo();
++ XGetWindowAttributes(xw.dpy, xw.win, &xattr);
++
++ int mindex = getmonitorindex_threshold(xattr.width, xattr.height, xattr.x, xattr.y);
++ if (mindex < 0)
++ mindex = getmonitorindex_nearest(xattr.width, xattr.height, xattr.x, xattr.y);
++ adjustmonitorfontsize(mindex);
++}
++
++
+ void
+ xbell(void)
+ {
+@@ -2437,6 +2437,14 @@ cmessage(XEvent *e)
+ void
+ resize(XEvent *e)
+ {
++ // BAD: no resize on monitor plug/unplug/reconfigure -- until window itself is kept in the same place
++ // NOTE: no resize event on zoomabs()
++ // fprintf(stderr, "Resize: %dx%d+%d+%d\n",
++ // e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y);
++
++ adjustmonitorfontsize(getmonitorindex_threshold(
++ e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y));
++
+ if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
+ return;
+
+@@ -2469,6 +2469,22 @@ run(void)
+ }
+ } while (ev.type != MapNotify);
+
++ int rr_event_base, rr_error_base, rr_major, rr_minor;
++ if (!XRRQueryExtension (xw.dpy, &rr_event_base, &rr_error_base) ||
++ !XRRQueryVersion (xw.dpy, &rr_major, &rr_minor) ||
++ rr_major < 1 || (rr_major == 1 && rr_minor < 5))
++ {
++ die("RandR 1.5 extension isn't available\n");
++ }
++ XRRSelectInput(xw.dpy, xw.win, RRCrtcChangeNotifyMask);
++
++ // WARN: can query actual window size/pos only after window is mapped and its width/height are adjusted by WM
++ // * x/y are WM-dependent and can't be determined beforehand anyway
++ // * defaultfontsize isn't available until font is loaded and actual Fc*() size queried
++ // BAD: fonts on startup are always reloaded -- how to specify their size beforehand ?
++ FcPatternGetDouble(dc.font.match->pattern, FC_SIZE, 0, &defaultrelfontsize);
++ refreshxrandr(0);
++
+ ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
+ cresize(w, h);
+
+@@ -2500,6 +2500,16 @@ run(void)
+ XNextEvent(xw.dpy, &ev);
+ if (XFilterEvent(&ev, None))
+ continue;
++ if (LASTEvent <= ev.type) {
++ if (rr_event_base + RRNotify == ev.type &&
++ RRNotify_CrtcChange == ((XRRNotifyEvent *)&ev)->subtype)
++ {
++ XRRUpdateConfiguration(&ev);
++ // fprintf(stderr, "Monitor change: %d > %d\n", rr_event_base, LASTEvent);
++ refreshxrandr(0);
++ }
++ continue;
++ }
+ if (handler[ev.type])
+ (handler[ev.type])(&ev);
+ }
diff --git a/st/st-autocomplete b/st/st-autocomplete
new file mode 100644
index 0000000..0fad536
--- /dev/null
+++ b/st/st-autocomplete
@@ -0,0 +1,310 @@
+#!/usr/bin/perl
+#########################################################################
+# Copyright (C) 2012-2017 Wojciech Siewierski #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+#########################################################################
+
+my ($cmd, $cursor_row, $cursor_column) = @ARGV;
+
+my $lines = [];
+my $lines1 = [];
+
+my $last_line = -1;
+my $lines_before_cursor = 0;
+
+while (<stdin>)
+{
+ $last_line++;
+
+ s/[^[:print:]]/?/g;
+
+ if ($last_line < $cursor_row)
+ {
+ unshift @{$lines1}, $_;
+ $lines_before_cursor++;
+ }
+ else
+ {
+ unshift @{$lines}, $_;
+ }
+}
+
+foreach (@{$lines1})
+{
+ unshift @{$lines}, $_;
+}
+
+my $cursor_row_in = $cursor_row;
+
+$cursor_row = $last_line;
+
+
+$self = {};
+
+# A reference to a function that transforms the completed word
+# into a regex matching the completions. Usually generated by
+# generate_matcher().
+#
+# For example
+# $fun = generate_matcher(".*");
+# $fun->("foo");
+# would return "f.*o.*o"
+#
+# In other words, indirectly decides which characters can
+# appear in the completion.
+my $matcher;
+
+# A regular expression matching a character before each match.
+# For example, it you want to match the text after a
+# whitespace, set it to "\s".
+my $char_class_before;
+
+# A regular expression matching every character in the entered
+# text that will be used to find matching completions. Usually
+# "\w" or similar.
+my $char_class_to_complete;
+
+# A regular expression matching every allowed last character
+# of the completion (uses greedy matching).
+my $char_class_at_end;
+
+if ($cmd eq 'word-complete') {
+ # Basic word completion. Completes the current word
+ # without any special matching.
+ $char_class_before = '[^-\w]';
+ $matcher = sub { quotemeta shift }; # identity
+ $char_class_at_end = '[-\w]';
+ $char_class_to_complete = '[-\w]';
+} elsif ($cmd eq 'WORD-complete') {
+ # The same as above but in the Vim meaning of a "WORD" --
+ # whitespace delimited.
+ $char_class_before = '\s';
+ $matcher = sub { quotemeta shift };
+ $char_class_at_end = '\S';
+ $char_class_to_complete = '\S';
+} elsif ($cmd eq 'fuzzy-word-complete' ||
+ $cmd eq 'skeleton-word-complete') {
+ # Fuzzy completion of the current word.
+ $char_class_before = '[^-\w]';
+ $matcher = generate_matcher('[-\w]*');
+ $char_class_at_end = '[-\w]';
+ $char_class_to_complete = '[-\w]';
+} elsif ($cmd eq 'fuzzy-WORD-complete') {
+ # Fuzzy completion of the current WORD.
+ $char_class_before = '\s';
+ $matcher = generate_matcher('\S*');
+ $char_class_at_end = '\S';
+ $char_class_to_complete = '\S';
+} elsif ($cmd eq 'fuzzy-complete' ||
+ $cmd eq 'skeleton-complete') {
+ # Fuzzy completion of an arbitrary text.
+ $char_class_before = '\W';
+ $matcher = generate_matcher('.*?');
+ $char_class_at_end = '\w';
+ $char_class_to_complete = '\S';
+} elsif ($cmd eq 'suffix-complete') {
+ # Fuzzy completion of an completing suffixes, like
+ # completing test=hello from /blah/hello.
+ $char_class_before = '\S';
+ $matcher = generate_matcher('\S*');
+ $char_class_at_end = '\S';
+ $char_class_to_complete = '\S';
+} elsif ($cmd eq 'surround-complete') {
+ # Completing contents of quotes and braces.
+
+ # Here we are using three named groups: s, b, p for quotes, braces
+ # and parenthesis.
+ $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())';
+
+ $matcher = generate_matcher('.*?');
+
+ # Here we match text till enclosing pair, using perl conditionals in
+ # regexps (?(condition)yes-expression|no-expression).
+ # \0 is used to hack concatenation with '*' later in the code.
+ $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0';
+ $char_class_to_complete = '\S';
+}
+
+
+# use the last used word or read the word behind the cursor
+my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column,
+ $char_class_to_complete);
+
+print stdout "$word_to_complete\n";
+
+if ($word_to_complete) {
+ while (1) {
+ # ignore the completed word itself
+ $self->{already_completed}{$word_to_complete} = 1;
+
+ # continue the last search or start from the current row
+ my $completion = find_match($self,
+ $word_to_complete,
+ $self->{next_row} // $cursor_row,
+ $matcher->($word_to_complete),
+ $char_class_before,
+ $char_class_at_end);
+ if ($completion) {
+ print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n";
+ }
+ else {
+ last;
+ }
+ }
+}
+
+######################################################################
+
+sub highlight_match {
+ my ($self, $linenum, $completion) = @_;
+
+ # clear_highlight($self);
+
+ my $line = @{$lines}[$linenum];
+ my $re = quotemeta $completion;
+
+ $line =~ /$re/;
+
+ my $beg = $-[0];
+ my $end = $+[0];
+
+ if ($linenum >= $lines_before_cursor)
+ {
+ $lline = $last_line - $lines_before_cursor;
+ $linenum -= $lines_before_cursor;
+ $linenum = $lline - $linenum;
+ $linenum += $lines_before_cursor;
+ }
+
+
+ $self->{highlight} = [$linenum, $beg, $end];
+}
+
+######################################################################
+
+sub read_word_at_coord {
+ my ($self, $row, $col, $char_class) = @_;
+
+ $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the cursor...
+ s/.*?($char_class*)$/$1/; # ...and read the last word from it
+ return $_;
+}
+
+######################################################################
+
+# Returns a function that takes a string and returns that string with
+# this function's argument inserted between its every two characters.
+# The resulting string is used as a regular expression matching the
+# completion candidates.
+sub generate_matcher {
+ my $regex_between = shift;
+
+ sub {
+ $_ = shift;
+
+ # sorry for this lispy code, I couldn't resist ;)
+ (join "$regex_between",
+ (map quotemeta,
+ (split //)))
+ }
+}
+
+######################################################################
+
+# Checks whether the completion found by find_match() was already
+# found and if it was, calls find_match() again to find the next
+# completion.
+#
+# Takes all the arguments that find_match() would take, to make a
+# mutually recursive call.
+sub skip_duplicates {
+ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_;
+ my $completion;
+
+ if ($current_row <= $lines_before_cursor)
+ {
+ $completion = shift @{$self->{matches_in_row}}; # get the leftmost one
+ }
+ else
+ {
+ $completion = pop @{$self->{matches_in_row}}; # get the leftmost one
+ }
+
+ # check for duplicates
+ if (exists $self->{already_completed}{$completion}) {
+ # skip this completion
+ return find_match(@_);
+ } else {
+ $self->{already_completed}{$completion} = 1;
+
+ highlight_match($self,
+ $self->{next_row}+1,
+ $completion);
+
+ return $completion;
+ }
+}
+
+######################################################################
+
+# Finds the next matching completion in the row current row or above
+# while skipping duplicates using skip_duplicates().
+sub find_match {
+ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_;
+ $self->{matches_in_row} //= [];
+
+ # cycle through all the matches in the current row if not starting a new search
+ if (@{$self->{matches_in_row}}) {
+ return skip_duplicates($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end);
+ }
+
+
+ my $i;
+ # search through all the rows starting with current one or one above the last checked
+ for ($i = $current_row; $i >= 0; --$i) {
+ my $line = @{$lines}[$i]; # get the line of text from the row
+
+ # if ($i == $cursor_row) {
+ # $line = substr $line, 0, $cursor_column;
+ # }
+
+ $_ = $line;
+
+ # find all the matches in the current line
+ my $match;
+ push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = /
+ (.*${char_class_before})
+ (?<match>
+ ${regexp}
+ ${char_class_at_end}*
+ )
+ /ix;
+ # corner case: match at the very beginning of line
+ push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i;
+
+ if (@{$self->{matches_in_row}}) {
+ # remember which row should be searched next
+ $self->{next_row} = --$i;
+
+ # arguments needed for find_match() mutual recursion
+ return skip_duplicates($self, $word_to_match, $i, $regexp, $char_class_before, $char_class_at_end);
+ }
+ }
+
+ # # no more possible completions, revert to the original word
+ # undo_completion($self) if $i < 0;
+
+ return undef;
+}
diff --git a/st/st-copyout b/st/st-copyout
deleted file mode 100644
index 0d19e5a..0000000
--- a/st/st-copyout
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-# Using external pipe with st, give a dmenu prompt of recent commands,
-# allowing the user to copy the output of one.
-# xclip required for this script.
-# By Jaywalker and Luke
-tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX)
-trap 'rm "$tmpfile"' 0 1 15
-sed -n "w $tmpfile"
-sed -i 's/\x0//g' "$tmpfile"
-ps1="$(grep "\S" "$tmpfile" | tail -n 1 | sed 's/^\s*//' | cut -d' ' -f1)"
-chosen="$(grep -F "$ps1" "$tmpfile" | sed '$ d' | tac | dmenu -p "Copy which command's output?" -i -l 10 | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
-eps1="$(echo "$ps1" | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
-awk "/^$chosen$/{p=1;print;next} p&&/$eps1/{p=0};p" "$tmpfile" | xclip -selection clipboard
diff --git a/st/st-urlhandler b/st/st-urlhandler
deleted file mode 100644
index 0eb4586..0000000
--- a/st/st-urlhandler
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-urlregex="(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:;a-zA-Z0-9./+@$&%?$\#=_~-]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)"
-
-urls="$(sed 's/.*│//g' | tr -d '\n' | # First remove linebreaks and mutt sidebars:
- grep -aEo "$urlregex" | # grep only urls as defined above.
- uniq | # Ignore neighboring duplicates.
- sed "s/\(\.\|,\|;\|\!\\|\?\)$//;
- s/^www./http:\/\/www\./")" # xdg-open will not detect url without http
-
-[ -z "$urls" ] && exit 1
-
-while getopts "hoc" o; do case "${o}" in
- h) printf "Optional arguments for custom use:\\n -c: copy\\n -o: xdg-open\\n -h: Show this message\\n" && exit 1 ;;
- o) chosen="$(echo "$urls" | dmenu -i -p 'Follow which url?' -l 10)"
- setsid xdg-open "$chosen" >/dev/null 2>&1 & ;;
- c) echo "$urls" | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard ;;
- *) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;;
-esac done
diff --git a/st/st.1 b/st/st.1
index 351710b..fa6e2b7 100644
--- a/st/st.1
+++ b/st/st.1
@@ -4,6 +4,8 @@ st \- simple terminal
.SH SYNOPSIS
.B st
.RB [ \-aiv ]
+.RB [ \-b
+.IR borderpx ]
.RB [ \-c
.IR class ]
.RB [ \-f
@@ -28,6 +30,8 @@ st \- simple terminal
.PP
.B st
.RB [ \-aiv ]
+.RB [ \-b
+.IR borderpx ]
.RB [ \-c
.IR class ]
.RB [ \-f
@@ -55,6 +59,10 @@ is a simple terminal emulator.
.B \-a
disable alternate screens in terminal
.TP
+.BI \-b " borderpx"
+set border size to
+.I borderpx
+.TP
.BI \-c " class"
defines the window class (default $TERM).
.TP
@@ -125,63 +133,44 @@ and all the remaining arguments are used as a command
even without it.
.SH SHORTCUTS
.TP
-.B Alt-a/s
-Increase or decrease opacity/alpha value (make window more or less transparent).
-.TP
-.B Alt-=
-Reset to default opacity/alpha value.
-.TP
-.B Alt-e/y or Alt-Up/Down or Alt-Mouse Wheel
-Scroll up/down one line at a time.
-.TP
-.B Alt-u/d or Alt-Page Up/Page Down
-Scroll up/down one screen at a time.
-.TP
-.B Alt-Shift-k/j or Alt-Shift-Page Up/Page Down or Alt-Shift-Mouse Wheel
-Increase or decrease font size.
-.TP
-.B Alt-+
-Reset to default font size.
-.TP
-.B Alt-c
-Copy to clipboard.
-.TP
-.B Alt-C
-Show dmenu menu of all URLs on screen and choose one to copy.
-.TP
-.B Alt-v or Shift-Insert
-Paste from clipboard.
-.TP
-.B Alt-V
-Show dmenu menu of all URLs on screen and choose one to open.
-.TP
-.B Alt-p
-Paste/input primary selection.
-.TP
-.B Alt-o
-Show dmenu menu of all recently run commands and copy the output of the chosen command to the clipboard.
-.I xclip
-required.
-.TP
-.B Alt-I
-Cycle fonts.
-.TP
.B Break
Send a break in the serial line.
Break key is obtained in PC keyboards
pressing at the same time control and pause.
.TP
-.B Alt-Ctrl-Print Screen
+.B Ctrl-Print Screen
Toggle if st should print to the
.I iofile.
.TP
-.B Alt-Shift-Print Screen
+.B Shift-Print Screen
Print the full screen to the
.I iofile.
.TP
-.B Alt-Print Screen
+.B Print Screen
Print the selection to the
.I iofile.
+.TP
+.B Ctrl-Shift-Page Up
+Increase font size.
+.TP
+.B Ctrl-Shift-Page Down
+Decrease font size.
+.TP
+.B Ctrl-Shift-Home
+Reset to default font size.
+.TP
+.B Ctrl-Shift-y
+Paste from primary selection (middle mouse button).
+.TP
+.B Ctrl-Shift-c
+Copy the selected text to the clipboard selection.
+.TP
+.B Ctrl-Shift-v
+Paste from the clipboard selection.
+.TP
+.B Ctrl-Shift-i
+Launch dmenu to enter a unicode codepoint and send the corresponding glyph
+to st.
.SH CUSTOMIZATION
.B st
can be customized by creating a custom config.h and (re)compiling the source
@@ -197,3 +186,4 @@ See the LICENSE file for the terms of redistribution.
.BR scroll (1)
.SH BUGS
See the TODO file in the distribution.
+
diff --git a/st/st.c b/st/st.c
index 0f4593e..1146a13 100644
--- a/st/st.c
+++ b/st/st.c
@@ -16,10 +16,15 @@
#include <termios.h>
#include <unistd.h>
#include <wchar.h>
+#include <X11/keysym.h>
+#include <X11/X.h>
+#include "autocomplete.h"
#include "st.h"
#include "win.h"
+extern char *argv0;
+
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -44,8 +49,8 @@
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
- term.scr + HISTSIZE + 1) % HISTSIZE] : \
- term.line[(y) - term.scr])
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
+ term.line[(y) - term.scr])
#define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)])
enum term_mode {
@@ -118,7 +123,6 @@ typedef struct {
typedef struct {
int row; /* nb row */
int col; /* nb col */
- int maxcol;
Line *line; /* screen */
Line *alt; /* alternate screen */
Line hist[HISTSIZE]; /* history buffer */
@@ -161,9 +165,16 @@ typedef struct {
int narg; /* nb of args */
} STREscape;
+typedef struct {
+ int state;
+ size_t length;
+} URLdfa;
+
static void execsh(char *, char **);
+static int chdir_by_pid(pid_t pid);
static void stty(char **);
static void sigchld(int);
+static void sigusr1(int);
static void ttywriteraw(const char *, size_t);
static void csidump(void);
@@ -209,6 +220,7 @@ static void tdefutf8(char);
static int32_t tdefcolor(const int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
+static int daddch(URLdfa *, char);
static void drawregion(int, int, int, int);
@@ -226,6 +238,8 @@ static char base64dec_getc(const char **);
static ssize_t xwrite(int, const char *, size_t);
+static int gettmuxpts(void);
+
/* Globals */
static Term term;
static Selection sel;
@@ -280,8 +294,6 @@ xrealloc(void *p, size_t len)
char *
xstrdup(const char *s)
{
- if ((s = strdup(s)) == NULL)
- die("strdup: %s\n", strerror(errno));
char *p;
if ((p = strdup(s)) == NULL)
@@ -488,7 +500,6 @@ selextend(int col, int row, int type, int done)
sel.mode = done ? SEL_IDLE : SEL_READY;
}
-
void
selnormalize(void)
{
@@ -661,6 +672,92 @@ getsel(void)
return str;
}
+char *
+strstrany(char* s, char** strs) {
+ char *match;
+ for (int i = 0; strs[i]; i++) {
+ if ((match = strstr(s, strs[i]))) {
+ return match;
+ }
+ }
+ return NULL;
+}
+
+void
+highlighturlsline(int row)
+{
+ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */
+ char *match;
+ for (int j = 0; j < term.col; j++) {
+ if (term.line[row][j].u < 127) {
+ linestr[j] = term.line[row][j].u;
+ }
+ linestr[term.col] = '\0';
+ }
+ int url_start = -1;
+ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) {
+ url_start = match - linestr;
+ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) {
+ term.line[row][c].mode |= ATTR_URL;
+ tsetdirt(row, c);
+ }
+ }
+ free(linestr);
+}
+
+void
+unhighlighturlsline(int row)
+{
+ for (int j = 0; j < term.col; j++) {
+ Glyph* g = &term.line[row][j];
+ if (g->mode & ATTR_URL) {
+ g->mode &= ~ATTR_URL;
+ tsetdirt(row, j);
+ }
+ }
+ return;
+}
+
+int
+followurl(int col, int row) {
+ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */
+ char *match;
+ for (int i = 0; i < term.col; i++) {
+ if (term.line[row][i].u < 127) {
+ linestr[i] = term.line[row][i].u;
+ }
+ linestr[term.col] = '\0';
+ }
+ int url_start = -1, found_url = 0;
+ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) {
+ url_start = match - linestr;
+ int url_end = url_start;
+ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) {
+ url_end++;
+ }
+ if (url_start <= col && col < url_end) {
+ found_url = 1;
+ linestr[url_end] = '\0';
+ break;
+ }
+ }
+ if (!found_url) {
+ free(linestr);
+ return 0;
+ }
+
+ pid_t chpid;
+ if ((chpid = fork()) == 0) {
+ if (fork() == 0)
+ execlp(urlhandler, urlhandler, linestr + url_start, NULL);
+ exit(1);
+ }
+ if (chpid > 0)
+ waitpid(chpid, NULL, 0);
+ free(linestr);
+ return 1;
+}
+
void
selclear(void)
{
@@ -735,6 +832,13 @@ execsh(char *cmd, char **args)
}
void
+sigusr1(int unused)
+{
+ static Arg a = {.v = externalpipe_sigusr1};
+ externalpipe(&a);
+}
+
+void
sigchld(int a)
{
int stat;
@@ -743,8 +847,14 @@ sigchld(int a)
if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
- if (pid != p)
+ if (pid != p) {
+ if (p == 0 && wait(&stat) < 0)
+ die("wait: %s\n", strerror(errno));
+
+ /* reinstall sigchld handler */
+ signal(SIGCHLD, sigchld);
return;
+ }
if (WIFEXITED(stat) && WEXITSTATUS(stat))
die("child exited with status %d\n", WEXITSTATUS(stat));
@@ -780,6 +890,12 @@ stty(char **args)
int
ttynew(const char *line, char *cmd, const char *out, char **args)
{
+ static struct sigaction sa;
+ sa.sa_handler = sigusr1;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGUSR1, &sa, NULL);
+
int m, s;
if (out) {
@@ -828,9 +944,10 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break;
default:
#ifdef __OpenBSD__
- if (pledge("stdio rpath tty proc", NULL) == -1)
+ if (pledge("stdio rpath tty proc exec", NULL) == -1)
die("pledge\n");
#endif
+ fcntl(m, F_SETFD, FD_CLOEXEC);
close(s);
cmdfd = m;
signal(SIGCHLD, sigchld);
@@ -1071,6 +1188,124 @@ tnew(int col, int row)
treset();
}
+int tisaltscr(void)
+{
+ return IS_SET(MODE_ALTSCREEN);
+}
+
+void
+newterm(const Arg* a)
+{
+ int pts;
+ FILE *fsession, *fpid;
+ char session[5];
+ char pidstr[10];
+ char buf[48];
+ size_t size;
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+ break;
+ case 0:
+ switch (fork()) {
+ case -1:
+ fprintf(stderr, "fork failed: %s\n", strerror(errno));
+ _exit(1);
+ break;
+ case 0:
+ signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */
+ pts = gettmuxpts();
+ if (pts != -1) {
+ snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts);
+ fsession = popen(buf, "r");
+ if (!fsession) {
+ fprintf(stderr, "Couldn't launch tmux.");
+ _exit(1);
+ }
+ size = fread(session, 1, sizeof session, fsession);
+ if (pclose(fsession) != 0 || size == 0) {
+ fprintf(stderr, "Couldn't get tmux session.");
+ _exit(1);
+ }
+ session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */
+
+ snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session);
+ fpid = popen(buf, "r");
+ if (!fpid) {
+ fprintf(stderr, "Couldn't launch tmux.");
+ _exit(1);
+ }
+ size = fread(pidstr, 1, sizeof pidstr, fpid);
+ if (pclose(fpid) != 0 || size == 0) {
+ fprintf(stderr, "Couldn't get tmux session.");
+ _exit(1);
+ }
+ pidstr[size - 1] = '\0';
+ }
+
+ chdir_by_pid(pts != -1 ? atol(pidstr) : pid);
+ execl("/proc/self/exe", argv0, NULL);
+ _exit(1);
+ break;
+ default:
+ _exit(0);
+ }
+ default:
+ wait(NULL);
+ }
+}
+
+static int
+chdir_by_pid(pid_t pid)
+{
+ char buf[32];
+ snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid);
+ return chdir(buf);
+}
+
+/* returns the pty of tmux client or -1 if the child of st isn't tmux */
+static int
+gettmuxpts(void)
+{
+ char buf[32];
+ char comm[17];
+ int tty;
+ FILE *fstat;
+ FILE *fcomm;
+ size_t numread;
+
+ snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid);
+
+ fcomm = fopen(buf, "r");
+ if (!fcomm) {
+ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno));
+ _exit(1);
+ }
+
+ numread = fread(comm, 1, sizeof comm - 1, fcomm);
+ comm[numread] = '\0';
+
+ fclose(fcomm);
+
+ if (strcmp("tmux: client\n", comm) != 0)
+ return -1;
+
+ snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid);
+ fstat = fopen(buf, "r");
+ if (!fstat) {
+ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno));
+ _exit(1);
+ }
+
+ /*
+ * We can't skip the second field with %*s because it contains a space so
+ * we skip strlen("tmux: client") + 2 for the braces which is 14.
+ */
+ fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty);
+ fclose(fstat);
+ return ((0xfff00000 & tty) >> 12) | (0xff & tty);
+}
+
void
tswapscreen(void)
{
@@ -1177,7 +1412,7 @@ tscrollup(int orig, int n, int copyhist)
void
selscroll(int orig, int n)
{
- if (sel.ob.x == -1)
+ if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
return;
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
@@ -1311,8 +1546,8 @@ tclearregion(int x1, int y1, int x2, int y2)
if (y1 > y2)
temp = y1, y1 = y2, y2 = temp;
- LIMIT(x1, 0, term.maxcol-1);
- LIMIT(x2, 0, term.maxcol-1);
+ LIMIT(x1, 0, term.col-1);
+ LIMIT(x2, 0, term.col-1);
LIMIT(y1, 0, term.row-1);
LIMIT(y2, 0, term.row-1);
@@ -1726,7 +1961,7 @@ csihandle(void)
ttywrite(vtiden, strlen(vtiden), 0);
break;
case 'b': /* REP -- if last char is printable print it <n> more times */
- DEFAULT(csiescseq.arg[0], 1);
+ LIMIT(csiescseq.arg[0], 1, 65535);
if (term.lastc)
while (csiescseq.arg[0]-- > 0)
tputc(term.lastc);
@@ -1811,6 +2046,7 @@ csihandle(void)
}
break;
case 'S': /* SU -- Scroll <n> line up */
+ if (csiescseq.priv) break;
DEFAULT(csiescseq.arg[0], 1);
tscrollup(term.top, csiescseq.arg[0], 0);
break;
@@ -1852,11 +2088,18 @@ csihandle(void)
case 'm': /* SGR -- Terminal attribute (color) */
tsetattr(csiescseq.arg, csiescseq.narg);
break;
- case 'n': /* DSR – Device Status Report (cursor position) */
- if (csiescseq.arg[0] == 6) {
+ case 'n': /* DSR -- Device Status Report */
+ switch (csiescseq.arg[0]) {
+ case 5: /* Status Report "OK" `0n` */
+ ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
+ break;
+ case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
- term.c.y+1, term.c.x+1);
+ term.c.y+1, term.c.x+1);
ttywrite(buf, len, 0);
+ break;
+ default:
+ goto unknown;
}
break;
case 'r': /* DECSTBM -- Set Scrolling Region */
@@ -1885,6 +2128,33 @@ csihandle(void)
goto unknown;
}
break;
+ case 't': /* title stack operations */
+ switch (csiescseq.arg[0]) {
+ case 22: /* pust current title on stack */
+ switch (csiescseq.arg[1]) {
+ case 0:
+ case 1:
+ case 2:
+ xpushtitle();
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ case 23: /* pop last title from stack */
+ switch (csiescseq.arg[1]) {
+ case 0:
+ case 1:
+ case 2:
+ xsettitle(NULL, 1);
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ default:
+ goto unknown;
+ }
}
}
@@ -1963,7 +2233,7 @@ strhandle(void)
switch (par) {
case 0:
if (narg > 1) {
- xsettitle(strescseq.args[1]);
+ xsettitle(strescseq.args[1], 0);
xseticontitle(strescseq.args[1]);
}
return;
@@ -1973,7 +2243,7 @@ strhandle(void)
return;
case 2:
if (narg > 1)
- xsettitle(strescseq.args[1]);
+ xsettitle(strescseq.args[1], 0);
return;
case 52:
if (narg > 2 && allowwindowops) {
@@ -2015,8 +2285,10 @@ strhandle(void)
if (p && !strcmp(p, "?")) {
osc_color_response(j, 0, 1);
} else if (xsetcolorname(j, p)) {
- if (par == 104 && narg <= 1)
+ if (par == 104 && narg <= 1) {
+ xloadcols();
return; /* color reset without parameter */
+ }
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
j, p ? p : "(null)");
} else {
@@ -2024,13 +2296,15 @@ strhandle(void)
* TODO if defaultbg color is changed, borders
* are dirty
*/
+ if (j == defaultbg)
+ xclearwin();
tfulldirt();
}
return;
}
break;
case 'k': /* old title set compatibility */
- xsettitle(strescseq.args[0]);
+ xsettitle(strescseq.args[0], 0);
return;
case 'P': /* DCS -- Device Control String */
case '_': /* APC -- Application Program Command */
@@ -2173,6 +2447,28 @@ tprinter(char *s, size_t len)
}
void
+iso14755(const Arg *arg)
+{
+ FILE *p;
+ char *us, *e, codepoint[9], uc[UTF_SIZ];
+ unsigned long utf32;
+
+ if (!(p = popen(iso14755_cmd, "r")))
+ return;
+
+ us = fgets(codepoint, sizeof(codepoint), p);
+ pclose(p);
+
+ if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
+ return;
+ if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
+ (*e != '\n' && *e != '\0'))
+ return;
+
+ ttywrite(uc, utf8encode(utf32, uc), 1);
+}
+
+void
toggleprinter(const Arg *arg)
{
term.mode ^= MODE_PRINT;
@@ -2457,8 +2753,10 @@ eschandle(uchar ascii)
break;
case 'c': /* RIS -- Reset to initial state */
treset();
+ xfreetitlestack();
resettitle();
xloadcols();
+ xsetmode(0, MODE_HIDE);
break;
case '=': /* DECPAM -- Application keypad */
xsetmode(1, MODE_APPKEYPAD);
@@ -2551,6 +2849,9 @@ check_control_code:
* they must not cause conflicts with sequences.
*/
if (control) {
+ /* in UTF-8 mode ignore handling C1 control characters */
+ if (IS_SET(MODE_UTF8) && ISCONTROLC1(u))
+ return;
tcontrolcode(u);
/*
* control codes are not shown ever
@@ -2597,11 +2898,16 @@ check_control_code:
gp = &term.line[term.c.y][term.c.x];
}
- if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
+ if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
+ gp->mode &= ~ATTR_WIDE;
+ }
if (term.c.x+width > term.col) {
- tnewline(1);
+ if (IS_SET(MODE_WRAP))
+ tnewline(1);
+ else
+ tmoveto(term.col - width, term.c.y);
gp = &term.line[term.c.y][term.c.x];
}
@@ -2662,17 +2968,13 @@ void
tresize(int col, int row)
{
int i, j;
- int tmp;
- int minrow, mincol;
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
int *bp;
TCursor c;
- tmp = col;
- if (!term.maxcol)
- term.maxcol = term.col;
- col = MAX(col, term.maxcol);
- minrow = MIN(row, term.row);
- mincol = MIN(col, term.maxcol);
+ if ( row < term.row || col < term.col )
+ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
if (col < 1 || row < 1) {
fprintf(stderr,
@@ -2680,6 +2982,8 @@ tresize(int col, int row)
return;
}
+ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
+
/*
* slide screen to keep cursor where we expect it -
* tscrollup would work here, but we can optimize to
@@ -2724,18 +3028,17 @@ tresize(int col, int row)
term.line[i] = xmalloc(col * sizeof(Glyph));
term.alt[i] = xmalloc(col * sizeof(Glyph));
}
- if (col > term.maxcol) {
- bp = term.tabs + term.maxcol;
+ if (col > term.col) {
+ bp = term.tabs + term.col;
- memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol));
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
while (--bp > term.tabs && !*bp)
/* nothing */ ;
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
*bp = 1;
}
/* update terminal size */
- term.col = tmp;
- term.maxcol = col;
+ term.col = col;
term.row = row;
/* reset scrolling region */
tsetscroll(0, row-1);
@@ -2759,7 +3062,7 @@ tresize(int col, int row)
void
resettitle(void)
{
- xsettitle(NULL);
+ xsettitle(NULL, 0);
}
void
@@ -2772,6 +3075,8 @@ drawregion(int x1, int y1, int x2, int y2)
continue;
term.dirty[y] = 0;
+ unhighlighturlsline(y);
+ highlighturlsline(y);
xdrawline(TLINE(y), x1, y, x2);
}
}
@@ -2795,11 +3100,7 @@ draw(void)
drawregion(0, 0, term.col, term.row);
if (term.scr == 0)
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
- term.ocx, term.ocy, term.line[term.ocy][term.ocx],
- term.line[term.ocy], term.col);
- /* xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], */
- /* term.ocx, term.ocy, term.line[term.ocy][term.ocx], */
- /* term.line[term.ocy], term.col); */
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
term.ocx = cx;
term.ocy = term.c.y;
xfinishdraw();
@@ -2814,3 +3115,539 @@ redraw(void)
draw();
}
+void set_notifmode(int type, KeySym ksym) {
+ static char *lib[] = { " MOVE ", " SEL "};
+ static Glyph *g, *deb, *fin;
+ static int col, bot;
+
+ if ( ksym == -1 ) {
+ free(g);
+ col = term.col, bot = term.bot;
+ g = xmalloc(col * sizeof(Glyph));
+ memcpy(g, term.line[bot], col * sizeof(Glyph));
+
+ }
+ else if ( ksym == -2 )
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
+
+ if ( type < 2 ) {
+ char *z = lib[type];
+ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
+ deb->mode = ATTR_REVERSE,
+ deb->u = *z,
+ deb->fg = defaultfg, deb->bg = defaultbg;
+ }
+ else if ( type < 5 )
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
+ else {
+ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
+ deb->mode = ATTR_REVERSE,
+ deb->u = ' ',
+ deb->fg = defaultfg, deb->bg = defaultbg;
+ term.line[bot][0].u = ksym;
+ }
+
+ term.dirty[bot] = 1;
+ drawregion(0, bot, col, bot + 1);
+}
+
+void select_or_drawcursor(int selectsearch_mode, int type) {
+ int done = 0;
+
+ if ( selectsearch_mode & 1 ) {
+ selextend(term.c.x, term.c.y, type, done);
+ xsetsel(getsel());
+ }
+ else
+ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+}
+
+void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) {
+ Rune *r;
+ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
+
+ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
+ for (r = target; r - target < ptarget; r++) {
+ if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) {
+ if ( r - target == ptarget - 1 ) break;
+ } else {
+ r = NULL;
+ break;
+ }
+ }
+ if ( r != NULL ) break;
+ }
+
+ if ( i != bound ) {
+ term.c.y = i / term.col, term.c.x = i % term.col;
+ select_or_drawcursor(selectsearch_mode, type);
+ }
+}
+
+int trt_kbdselect(KeySym ksym, char *buf, int len) {
+ static TCursor cu;
+ static Rune target[64];
+ static int type = 1, ptarget, in_use;
+ static int sens, quant;
+ static char selectsearch_mode;
+ int i, bound, *xy;
+
+
+ if ( selectsearch_mode & 2 ) {
+ if ( ksym == XK_Return ) {
+ selectsearch_mode ^= 2;
+ set_notifmode(selectsearch_mode, -2);
+ if ( ksym == XK_Escape ) ptarget = 0;
+ return 0;
+ }
+ else if ( ksym == XK_BackSpace ) {
+ if ( !ptarget ) return 0;
+ term.line[term.bot][ptarget--].u = ' ';
+ }
+ else if ( len < 1 ) {
+ return 0;
+ }
+ else if ( ptarget == term.col || ksym == XK_Escape ) {
+ return 0;
+ }
+ else {
+ utf8decode(buf, &target[ptarget++], len);
+ term.line[term.bot][ptarget].u = target[ptarget - 1];
+ }
+
+ if ( ksym != XK_BackSpace )
+ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
+
+ term.dirty[term.bot] = 1;
+ drawregion(0, term.bot, term.col, term.bot + 1);
+ return 0;
+ }
+
+ switch ( ksym ) {
+ case -1 :
+ in_use = 1;
+ cu.x = term.c.x, cu.y = term.c.y;
+ set_notifmode(0, ksym);
+ return MODE_KBDSELECT;
+ case XK_s :
+ if ( selectsearch_mode & 1 )
+ selclear();
+ else
+ selstart(term.c.x, term.c.y, 0);
+ set_notifmode(selectsearch_mode ^= 1, ksym);
+ break;
+ case XK_t :
+ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */
+ selextend(term.c.x, term.c.y, type, i = 0);
+ break;
+ case XK_slash :
+ case XK_KP_Divide :
+ case XK_question :
+ ksym &= XK_question; /* Divide to slash */
+ sens = (ksym == XK_slash) ? -1 : 1;
+ ptarget = 0;
+ set_notifmode(15, ksym);
+ selectsearch_mode ^= 2;
+ break;
+ case XK_Escape :
+ if ( !in_use ) break;
+ selclear();
+ case XK_Return :
+ set_notifmode(4, ksym);
+ term.c.x = cu.x, term.c.y = cu.y;
+ select_or_drawcursor(selectsearch_mode = 0, type);
+ in_use = quant = 0;
+ return MODE_KBDSELECT;
+ case XK_n :
+ case XK_N :
+ if ( ptarget )
+ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
+ break;
+ case XK_BackSpace :
+ term.c.x = 0;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_dollar :
+ term.c.x = term.col - 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_Home :
+ term.c.x = 0, term.c.y = 0;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_End :
+ term.c.x = cu.x, term.c.y = cu.y;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_Page_Up :
+ case XK_Page_Down :
+ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_exclam :
+ term.c.x = term.col >> 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_asterisk :
+ case XK_KP_Multiply :
+ term.c.x = term.col >> 1;
+ case XK_underscore :
+ term.c.y = cu.y >> 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ default :
+ if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */
+ quant = (quant * 10) + (ksym ^ XK_0);
+ return 0;
+ }
+ else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */
+ quant = (quant * 10) + (ksym ^ XK_KP_0);
+ return 0;
+ }
+ else if ( ksym == XK_k || ksym == XK_h )
+ i = ksym & 1;
+ else if ( ksym == XK_l || ksym == XK_j )
+ i = ((ksym & 6) | 4) >> 1;
+ else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 )
+ break;
+
+ xy = (i & 1) ? &term.c.y : &term.c.x;
+ sens = (i & 2) ? 1 : -1;
+ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
+
+ if ( quant == 0 )
+ quant++;
+
+ if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) )
+ break;
+
+ *xy += quant * sens;
+ if ( *xy < 0 || ( bound > 0 && *xy > bound) )
+ *xy = bound;
+
+ select_or_drawcursor(selectsearch_mode, type);
+ }
+ quant = 0;
+ return 0;
+}
+
+int
+daddch(URLdfa *dfa, char c)
+{
+ /* () and [] can appear in urls, but excluding them here will reduce false
+ * positives when figuring out where a given url ends.
+ */
+ static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+ static const char RPFX[] = "//:sptth";
+
+ if (!strchr(URLCHARS, c)) {
+ dfa->length = 0;
+ dfa->state = 0;
+
+ return 0;
+ }
+
+ dfa->length++;
+
+ if (dfa->state == 2 && c == '/') {
+ dfa->state = 0;
+ } else if (dfa->state == 3 && c == 'p') {
+ dfa->state++;
+ } else if (c != RPFX[dfa->state]) {
+ dfa->state = 0;
+ return 0;
+ }
+
+ if (dfa->state++ == 7) {
+ dfa->state = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+** Select and copy the previous url on screen (do nothing if there's no url).
+*/
+void
+copyurl(const Arg *arg) {
+ int row = 0, /* row of current URL */
+ col = 0, /* column of current URL start */
+ colend = 0, /* column of last occurrence */
+ passes = 0; /* how many rows have been scanned */
+
+ const char *c = NULL,
+ *match = NULL;
+ URLdfa dfa = { 0 };
+
+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
+ LIMIT(row, term.top, term.bot);
+
+ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
+ LIMIT(colend, 0, term.col);
+
+ /*
+ ** Scan from (term.row - 1,term.col - 1) to (0,0) and find
+ ** next occurrance of a URL
+ */
+ for (passes = 0; passes < term.row; passes++) {
+ /* Read in each column of every row until
+ ** we hit previous occurrence of URL
+ */
+ for (col = colend; col--;)
+ if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' '))
+ break;
+
+ if (col >= 0)
+ break;
+
+ /* .i = 0 --> botton-up
+ * .i = 1 --> top-down
+ */
+ if (!arg->i) {
+ if (--row < 0)
+ row = term.row - 1;
+ } else {
+ if (++row >= term.row)
+ row = 0;
+ }
+
+ colend = term.col;
+ }
+
+ if (passes < term.row) {
+ selstart(col, row, 0);
+ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0);
+ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1);
+ xsetsel(getsel());
+ xclipcopy();
+ }
+}
+
+void autocomplete (const Arg *arg) {
+ static _Bool active = 0;
+ int acmpl_cmdindex = arg->i;
+ static int acmpl_cmdindex_prev;
+
+ if (active == 0)
+ acmpl_cmdindex_prev = acmpl_cmdindex;
+
+ static const char * const acmpl_cmd[] = {
+ [ACMPL_DEACTIVATE] = "__DEACTIVATE__",
+ [ACMPL_WORD] = "word-complete",
+ [ACMPL_WWORD] = "WORD-complete",
+ [ACMPL_FUZZY_WORD] = "fuzzy-word-complete",
+ [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete",
+ [ACMPL_FUZZY] = "fuzzy-complete",
+ [ACMPL_SUFFIX] = "suffix-complete",
+ [ACMPL_SURROUND] = "surround-complete",
+ [ACMPL_UNDO] = "__UNDO__",
+ };
+
+ static FILE *acmpl_exec = NULL;
+ static int acmpl_status;
+ static char *stbuffile;
+ static char *target = NULL;
+ static size_t targetlen;
+ static char *completion = NULL;
+ static size_t complen_prev = 0;
+ static int cx, cy;
+
+ if (acmpl_cmdindex == ACMPL_DEACTIVATE) {
+ if (active) {
+ active = 0;
+ pclose(acmpl_exec);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+
+ if (complen_prev) {
+ selclear();
+ complen_prev = 0;
+ }
+ }
+ return;
+ }
+
+ if (acmpl_cmdindex == ACMPL_UNDO) {
+ if (active) {
+ active = 0;
+ pclose(acmpl_exec);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+
+ if (complen_prev) {
+ selclear();
+ for (size_t i = 0; i < complen_prev; i++)
+ ttywrite((char[]) {'\b'}, 1, 1);
+ complen_prev = 0;
+ ttywrite(target, targetlen, 0);
+ }
+ }
+ return;
+ }
+
+ if (acmpl_cmdindex != acmpl_cmdindex_prev) {
+ if (active) {
+ acmpl_cmdindex_prev = acmpl_cmdindex;
+ goto acmpl_begin;
+ }
+ }
+
+ if (active == 0) {
+ acmpl_cmdindex_prev = acmpl_cmdindex;
+ cx = term.c.x;
+ cy = term.c.y;
+
+ char filename[] = "/tmp/st-autocomplete-XXXXXX";
+ int fd = mkstemp(filename);
+
+ if (fd == -1) {
+ perror("mkstemp");
+ return;
+ }
+
+ stbuffile = strdup(filename);
+
+ FILE *stbuf = fdopen(fd, "w");
+ if (!stbuf) {
+ perror("fdopen");
+ close(fd);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+
+ char *stbufline = malloc(term.col + 2);
+ if (!stbufline) {
+ perror("malloc");
+ fclose(stbuf);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+
+ int cxp = 0;
+ for (size_t y = 0; y < term.row; y++) {
+ if (y == term.c.y) cx += cxp * term.col;
+
+ size_t x = 0;
+ for (; x < term.col; x++)
+ utf8encode(term.line[y][x].u, stbufline + x);
+ if (term.line[y][x - 1].mode & ATTR_WRAP) {
+ x--;
+ if (y <= term.c.y) cy--;
+ cxp++;
+ } else {
+ stbufline[x] = '\n';
+ cxp = 0;
+ }
+ stbufline[x + 1] = 0;
+ fputs(stbufline, stbuf);
+ }
+
+ free(stbufline);
+ fclose(stbuf);
+
+acmpl_begin:
+ target = malloc(term.col + 1);
+ completion = malloc(term.col + 1);
+ if (!target || !completion) {
+ perror("malloc");
+ free(target);
+ free(completion);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+
+ char acmpl[1500];
+ snprintf(acmpl, sizeof(acmpl),
+ "cat %s | st-autocomplete %s %d %d",
+ stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx);
+
+ acmpl_exec = popen(acmpl, "r");
+ if (!acmpl_exec) {
+ perror("popen");
+ free(target);
+ free(completion);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+
+ if (fscanf(acmpl_exec, "%s\n", target) != 1) {
+ perror("fscanf");
+ pclose(acmpl_exec);
+ free(target);
+ free(completion);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+ targetlen = strlen(target);
+ }
+
+ unsigned line, beg, end;
+
+ acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end);
+ if (acmpl_status == EOF) {
+ if (active == 0) {
+ pclose(acmpl_exec);
+ free(target);
+ free(completion);
+ unlink(stbuffile);
+ free(stbuffile);
+ stbuffile = NULL;
+ return;
+ }
+ active = 0;
+ pclose(acmpl_exec);
+ ttywrite(target, targetlen, 0);
+ goto acmpl_begin;
+ }
+
+ active = 1;
+
+ if (complen_prev == 0) {
+ for (size_t i = 0; i < targetlen; i++)
+ ttywrite((char[]) {'\b'}, 1, 1);
+ } else {
+ selclear();
+ for (size_t i = 0; i < complen_prev; i++)
+ ttywrite((char[]) {'\b'}, 1, 1);
+ complen_prev = 0;
+ }
+
+ complen_prev = strlen(completion);
+ ttywrite(completion, complen_prev, 0);
+
+ if (line == cy && beg > cx) {
+ beg += complen_prev - targetlen;
+ end += complen_prev - targetlen;
+ }
+
+ end--;
+
+ int wl = 0;
+ int tl = line;
+ for (int l = 0; l < tl; l++)
+ if (term.line[l][term.col - 1].mode & ATTR_WRAP) {
+ wl++;
+ tl++;
+ }
+
+ selstart(beg % term.col, line + wl + beg / term.col, 0);
+ selextend(end % term.col, line + wl + end / term.col, 1, 0);
+ xsetsel(getsel());
+}
+
diff --git a/st/st.h b/st/st.h
index 310db4f..d7eef31 100644
--- a/st/st.h
+++ b/st/st.h
@@ -11,8 +11,7 @@
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
-#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
- (a).fg != (b).fg || \
+#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
(a).bg != (b).bg)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
@@ -35,10 +34,16 @@ enum glyph_attribute {
ATTR_WIDE = 1 << 9,
ATTR_WDUMMY = 1 << 10,
ATTR_BOXDRAW = 1 << 11,
- ATTR_LIGA = 1 << 12,
+ ATTR_URL = 1 << 12,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
+enum drawing_mode {
+ DRAW_NONE = 0,
+ DRAW_BG = 1 << 0,
+ DRAW_FG = 1 << 1,
+};
+
enum selection_mode {
SEL_IDLE = 0,
SEL_EMPTY = 1,
@@ -80,21 +85,28 @@ typedef union {
const char *s;
} Arg;
+void autocomplete (const Arg *);
+
void die(const char *, ...);
void redraw(void);
void tfulldirt(void);
void draw(void);
void externalpipe(const Arg *);
+void fullscreen(const Arg *);
+void iso14755(const Arg *);
void kscrolldown(const Arg *);
void kscrollup(const Arg *);
-
+void newterm(const Arg *);
+void opencopied(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
void toggleprinter(const Arg *);
+void copyurl(const Arg *);
int tattrset(int);
+int tisaltscr(void);
void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
@@ -113,11 +125,16 @@ void selextend(int, int, int, int);
int selected(int, int);
char *getsel(void);
+void highlighturlsline(int);
+void unhighlighturlsline(int);
+int followurl(int, int);
+
size_t utf8encode(Rune, char *);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *);
+int trt_kbdselect(KeySym, char *, int);
int isboxdraw(Rune);
ushort boxdrawindex(const Glyph *);
@@ -128,6 +145,7 @@ void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpe
#endif
/* config.h globals */
+extern char *externalpipe_sigusr1[];
extern char *utmp;
extern char *scroll;
extern char *stty_args;
@@ -139,8 +157,13 @@ extern char *termname;
extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
-extern float alpha, alpha_def;
-extern float alphaUnfocus;
-extern const int boxdraw, boxdraw_bold, boxdraw_braille;
extern unsigned int defaultcs;
+extern float alpha, alphaUnfocused;
+extern const int boxdraw, boxdraw_bold, boxdraw_braille;
+extern char *urlhandler;
+extern char urlchars[];
+extern char *urlprefixes[];
+extern int nurlprefixes;
+extern char *iso14755_cmd;
+extern float alpha_def;
diff --git a/st/st.info b/st/st.info
index 8201ad6..24dfc7d 100644
--- a/st/st.info
+++ b/st/st.info
@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor,
rin=\E[%p1%dT,
ritm=\E[23m,
rmacs=\E(B,
- rmcup=\E[?1049l,
+ rmcup=\E[?1049l\E[23;0;0t,
rmir=\E[4l,
rmkx=\E[?1l\E>,
rmso=\E[27m,
@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor,
sitm=\E[3m,
sgr0=\E[0m,
smacs=\E(0,
- smcup=\E[?1049h,
+ smcup=\E[?1049h\E[22;0;0t,
smir=\E[4h,
smkx=\E[?1h\E=,
smso=\E[7m,
@@ -184,6 +184,10 @@ st-mono| simpleterm monocolor,
# XTerm extensions
rmxx=\E[29m,
smxx=\E[9m,
+ BE=\E[?2004h,
+ BD=\E[?2004l,
+ PS=\E[200~,
+ PE=\E[201~,
# disabled rep for now: causes some issues with older ncurses versions.
# rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
diff --git a/st/unpatched/st-color_schemes-20220615-baa9357.diff b/st/unpatched/st-color_schemes-20220615-baa9357.diff
new file mode 100644
index 0000000..188fece
--- /dev/null
+++ b/st/unpatched/st-color_schemes-20220615-baa9357.diff
@@ -0,0 +1,169 @@
+From 285c1c63f22bc00771428088c1938b8a0161bd7b Mon Sep 17 00:00:00 2001
+From: Max Schillinger <maxschillinger@web.de>
+Date: Wed, 15 Jun 2022 21:06:42 +0200
+Subject: [PATCH] color_schemes patch for st commit baa9357
+
+---
+ config.def.h | 57 ++++++++++++++++++++++------------------------------
+ x.c | 35 +++++++++++++++-----------------
+ 2 files changed, 40 insertions(+), 52 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..22bdb3c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -93,46 +93,28 @@ char *termname = "st-256color";
+ */
+ unsigned int tabspaces = 8;
+
+-/* Terminal colors (16 first used in escape sequence) */
+-static const char *colorname[] = {
+- /* 8 normal colors */
+- "black",
+- "red3",
+- "green3",
+- "yellow3",
+- "blue2",
+- "magenta3",
+- "cyan3",
+- "gray90",
+-
+- /* 8 bright colors */
+- "gray50",
+- "red",
+- "green",
+- "yellow",
+- "#5c5cff",
+- "magenta",
+- "cyan",
+- "white",
+-
+- [255] = 0,
+-
+- /* more colors can be added after 255 to use with DefaultXX */
+- "#cccccc",
+- "#555555",
+- "gray90", /* default foreground colour */
+- "black", /* default background colour */
++/* Terminal colors (16 used in escape sequence) */
++static const char *palettes[][16] = {
++ {"black", "red3", "green3", "yellow3", "blue2", "magenta3", "cyan3", "gray90",
++ "gray50", "red", "green", "yellow", "#5c5cff", "magenta", "cyan", "white"},
++ {"#223", "#900", "#080", "#fe7", "#35e", "#fc5", "#18e", "#aaa",
++ "#666", "#f25", "#0b0", "#ff6", "#46f", "#d6a", "#6bf", "#ddd"},
++ {"#eaeaea", "#b7141f", "#457b24", "#fc7b08", "#134eb2", "#560088", "#0e717c", "#777777",
++ "#424242", "#e83b3f", "#7aba3a", "#fd8e09", "#54a4f3", "#aa4dbc", "#26bbd1", "#aaaaaa"},
++ {"#20242d", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#b3b8c3",
++ "#000000", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#ffffff"},
+ };
+
++static const char **colorname;
+
+ /*
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+-unsigned int defaultfg = 258;
+-unsigned int defaultbg = 259;
+-unsigned int defaultcs = 256;
+-static unsigned int defaultrcs = 257;
++unsigned int defaultfg = 5;
++unsigned int defaultbg = 0;
++unsigned int defaultcs = 5;
++static unsigned int defaultrcs = 5;
+
+ /*
+ * Default shape of cursor
+@@ -201,6 +183,15 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { MODKEY|ShiftMask, XK_F1, setpalette, {.i = 0} },
++ { MODKEY|ShiftMask, XK_F2, setpalette, {.i = 1} },
++ { MODKEY|ShiftMask, XK_F3, setpalette, {.i = 2} },
++ { MODKEY|ShiftMask, XK_F4, setpalette, {.i = 3} },
++ { MODKEY|ShiftMask, XK_F5, setpalette, {.i = 4} },
++ { MODKEY|ShiftMask, XK_F6, setpalette, {.i = 5} },
++ { MODKEY|ShiftMask, XK_F7, setpalette, {.i = 6} },
++ { MODKEY|ShiftMask, XK_F8, setpalette, {.i = 7} },
++ { MODKEY|ShiftMask, XK_F9, setpalette, {.i = 8} },
+ };
+
+ /*
+diff --git a/x.c b/x.c
+index 2a3bd38..0d77d2a 100644
+--- a/x.c
++++ b/x.c
+@@ -59,6 +59,7 @@ static void zoom(const Arg *);
+ static void zoomabs(const Arg *);
+ static void zoomreset(const Arg *);
+ static void ttysend(const Arg *);
++static void setpalette(const Arg *);
+
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+@@ -769,24 +770,8 @@ sixd_to_16bit(int x)
+ int
+ xloadcolor(int i, const char *name, Color *ncolor)
+ {
+- XRenderColor color = { .alpha = 0xffff };
+-
+- if (!name) {
+- if (BETWEEN(i, 16, 255)) { /* 256 color */
+- if (i < 6*6*6+16) { /* same colors as xterm */
+- color.red = sixd_to_16bit( ((i-16)/36)%6 );
+- color.green = sixd_to_16bit( ((i-16)/6) %6 );
+- color.blue = sixd_to_16bit( ((i-16)/1) %6 );
+- } else { /* greyscale */
+- color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
+- color.green = color.blue = color.red;
+- }
+- return XftColorAllocValue(xw.dpy, xw.vis,
+- xw.cmap, &color, ncolor);
+- } else
+- name = colorname[i];
+- }
+-
++ if (!name)
++ name = colorname[i];
+ return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
+ }
+
+@@ -801,7 +786,7 @@ xloadcols(void)
+ for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+ } else {
+- dc.collen = MAX(LEN(colorname), 256);
++ dc.collen = 16;
+ dc.col = xmalloc(dc.collen * sizeof(Color));
+ }
+
+@@ -2024,6 +2009,16 @@ usage(void)
+ " [stty_args ...]\n", argv0, argv0);
+ }
+
++void
++setpalette(const Arg *arg)
++{
++ if (arg->i < LEN(palettes)) {
++ colorname = palettes[arg->i];
++ xloadcols();
++ cresize(win.w, win.h);
++ }
++}
++
+ int
+ main(int argc, char *argv[])
+ {
+@@ -2076,6 +2071,8 @@ main(int argc, char *argv[])
+ } ARGEND;
+
+ run:
++ colorname = palettes[0];
++
+ if (argc > 0) /* eat all remaining arguments */
+ opt_cmd = argv;
+
+--
+2.36.1
+
diff --git a/st/unpatched/st-delkey-20201112-4ef0cbd.diff b/st/unpatched/st-delkey-20201112-4ef0cbd.diff
new file mode 100644
index 0000000..c334b0d
--- /dev/null
+++ b/st/unpatched/st-delkey-20201112-4ef0cbd.diff
@@ -0,0 +1,20 @@
+--- config.def.h.orig 2020-11-12 20:23:48.867954750 +0100
++++ config.def.h 2020-11-12 20:21:15.055922720 +0100
+@@ -276,7 +276,7 @@
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
++ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
+ { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
+@@ -344,7 +344,7 @@
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
++ { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
+ { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
diff --git a/st/unpatched/st-relativeborder-0.8.3.diff b/st/unpatched/st-relativeborder-0.8.3.diff
new file mode 100644
index 0000000..55839d2
--- /dev/null
+++ b/st/unpatched/st-relativeborder-0.8.3.diff
@@ -0,0 +1,39 @@
+diff -up ../st-0.8.3/config.def.h ./config.def.h
+--- ../st-0.8.3/config.def.h 2020-04-27 13:58:27.000000000 +0200
++++ ./config.def.h 2020-05-24 18:27:19.179361165 +0200
+@@ -4,9 +4,11 @@
+ * appearance
+ *
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
++ * borderperc: percentage of cell width to use as a border
++ * 0 = no border, 100 = border width is same as cell width
+ */
+ static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
+-static int borderpx = 2;
++static int borderperc = 20;
+
+ /*
+ * What program is execed by st depends of these precedence rules:
+diff -up ../st-0.8.3/st.h ./st.h
+--- ../st-0.8.3/st.h 2020-04-27 13:58:27.000000000 +0200
++++ ./st.h 2020-05-24 18:27:20.255369735 +0200
+@@ -52,6 +52,7 @@ enum selection_snap {
+ SNAP_LINE = 2
+ };
+
++int borderpx;
+ typedef unsigned char uchar;
+ typedef unsigned int uint;
+ typedef unsigned long ulong;
+diff -up ../st-0.8.3/x.c ./x.c
+--- ../st-0.8.3/x.c 2020-04-27 13:58:27.000000000 +0200
++++ ./x.c 2020-05-24 18:27:17.551348200 +0200
+@@ -1001,6 +1001,8 @@ xloadfonts(char *fontstr, double fontsiz
+ win.cw = ceilf(dc.font.width * cwscale);
+ win.ch = ceilf(dc.font.height * chscale);
+
++ borderpx = ceilf(((float)borderperc / 100) * win.cw);
++
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (xloadfont(&dc.ifont, pattern))
diff --git a/st/unpatched/st-undercurl-0.9-20240103.diff b/st/unpatched/st-undercurl-0.9-20240103.diff
new file mode 100644
index 0000000..b099933
--- /dev/null
+++ b/st/unpatched/st-undercurl-0.9-20240103.diff
@@ -0,0 +1,606 @@
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..7ae1b92 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -470,3 +470,27 @@ static char ascii_printable[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
++
++/**
++ * Undercurl style. Set UNDERCURL_STYLE to one of the available styles.
++ *
++ * Curly: Dunno how to draw it *shrug*
++ * _ _ _ _
++ * ( ) ( ) ( ) ( )
++ * (_) (_) (_) (_)
++ *
++ * Spiky:
++ * /\ /\ /\ /\
++ * \/ \/ \/
++ *
++ * Capped:
++ * _ _ _
++ * / \ / \ / \
++ * \_/ \_/
++ */
++// Available styles
++#define UNDERCURL_CURLY 0
++#define UNDERCURL_SPIKY 1
++#define UNDERCURL_CAPPED 2
++// Active style
++#define UNDERCURL_STYLE UNDERCURL_SPIKY
+diff --git a/st.c b/st.c
+index 76b7e0d..542ab3a 100644
+--- a/st.c
++++ b/st.c
+@@ -33,6 +33,7 @@
+ #define UTF_SIZ 4
+ #define ESC_BUF_SIZ (128*UTF_SIZ)
+ #define ESC_ARG_SIZ 16
++#define CAR_PER_ARG 4
+ #define STR_BUF_SIZ ESC_BUF_SIZ
+ #define STR_ARG_SIZ ESC_ARG_SIZ
+
+@@ -139,6 +140,7 @@ typedef struct {
+ int arg[ESC_ARG_SIZ];
+ int narg; /* nb of args */
+ char mode[2];
++ int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
+ } CSIEscape;
+
+ /* STR Escape sequence structs */
+@@ -159,7 +161,8 @@ static void ttywriteraw(const char *, size_t);
+
+ static void csidump(void);
+ static void csihandle(void);
++static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
+ static void csiparse(void);
+ static void csireset(void);
+ static void osc_color_response(int, int, int);
+ static int eschandle(uchar);
+@@ -1131,6 +1134,28 @@ tnewline(int first_col)
+ tmoveto(first_col ? 0 : term.c.x, y);
+ }
+
++void
++readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
++{
++ int i = 0;
++ for (; i < CAR_PER_ARG; i++)
++ params[cursor][i] = -1;
++
++ if (**p != ':')
++ return;
++
++ char *np = NULL;
++ i = 0;
++
++ while (**p == ':' && i < CAR_PER_ARG) {
++ while (**p == ':')
++ (*p)++;
++ params[cursor][i] = strtol(*p, &np, 10);
++ *p = np;
++ i++;
++ }
++}
++
+ void
+ csiparse(void)
+ {
+@@ -1153,6 +1178,7 @@ csiparse(void)
+ v = -1;
+ csiescseq.arg[csiescseq.narg++] = v;
+ p = np;
++ readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
+ if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+ break;
+ p++;
+@@ -1369,6 +1395,10 @@ tsetattr(int *attr, int l)
+ ATTR_STRUCK );
+ term.c.attr.fg = defaultfg;
+ term.c.attr.bg = defaultbg;
++ term.c.attr.ustyle = -1;
++ term.c.attr.ucolor[0] = -1;
++ term.c.attr.ucolor[1] = -1;
++ term.c.attr.ucolor[2] = -1;
+ break;
+ case 1:
+ term.c.attr.mode |= ATTR_BOLD;
+@@ -1380,7 +1410,14 @@ tsetattr(int *attr, int l)
+ term.c.attr.mode |= ATTR_ITALIC;
+ break;
+ case 4:
+- term.c.attr.mode |= ATTR_UNDERLINE;
++ term.c.attr.ustyle = csiescseq.carg[i][0];
++
++ if (term.c.attr.ustyle != 0)
++ term.c.attr.mode |= ATTR_UNDERLINE;
++ else
++ term.c.attr.mode &= ~ATTR_UNDERLINE;
++
++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
+ break;
+ case 5: /* slow blink */
+ /* FALLTHROUGH */
+@@ -1431,6 +1468,18 @@ tsetattr(int *attr, int l)
+ case 49:
+ term.c.attr.bg = defaultbg;
+ break;
++ case 58:
++ term.c.attr.ucolor[0] = csiescseq.carg[i][1];
++ term.c.attr.ucolor[1] = csiescseq.carg[i][2];
++ term.c.attr.ucolor[2] = csiescseq.carg[i][3];
++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
++ break;
++ case 59:
++ term.c.attr.ucolor[0] = -1;
++ term.c.attr.ucolor[1] = -1;
++ term.c.attr.ucolor[2] = -1;
++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
++ break;
+ default:
+ if (BETWEEN(attr[i], 30, 37)) {
+ term.c.attr.fg = attr[i] - 30;
+diff --git a/st.h b/st.h
+index 3d351b6..95bdcbd 100644
+--- a/st.h
++++ b/st.h
+@@ -34,6 +34,7 @@ enum glyph_attribute {
+ ATTR_WIDE = 1 << 9,
+ ATTR_WDUMMY = 1 << 10,
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
++ ATTR_DIRTYUNDERLINE = 1 << 15,
+ };
+
+ enum selection_mode {
+@@ -65,6 +66,8 @@ typedef struct {
+ ushort mode; /* attribute flags */
+ uint32_t fg; /* foreground */
+ uint32_t bg; /* background */
++ int ustyle; /* underline style */
++ int ucolor[3]; /* underline color */
+ } Glyph;
+
+ typedef Glyph *Line;
+diff --git a/st.info b/st.info
+index 8201ad6..659878c 100644
+--- a/st.info
++++ b/st.info
+@@ -1,4 +1,5 @@
+ st-mono| simpleterm monocolor,
++ Su,
+ acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+ am,
+ bce,
+diff --git a/x.c b/x.c
+index 210f184..3a0e79e 100644
+--- a/x.c
++++ b/x.c
+@@ -45,6 +45,14 @@ typedef struct {
+ signed char appcursor; /* application cursor */
+ } Key;
+
++/* Undercurl slope types */
++enum undercurl_slope_type {
++ UNDERCURL_SLOPE_ASCENDING = 0,
++ UNDERCURL_SLOPE_TOP_CAP = 1,
++ UNDERCURL_SLOPE_DESCENDING = 2,
++ UNDERCURL_SLOPE_BOTTOM_CAP = 3
++};
++
+ /* X modifiers */
+ #define XK_ANY_MOD UINT_MAX
+ #define XK_NO_MOD 0
+@@ -1339,6 +1347,51 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
+ return numspecs;
+ }
+
++static int isSlopeRising (int x, int iPoint, int waveWidth)
++{
++ // . . . .
++ // / \ / \ / \ / \
++ // / \ / \ / \ / \
++ // . . . . .
++
++ // Find absolute `x` of point
++ x += iPoint * (waveWidth/2);
++
++ // Find index of absolute wave
++ int absSlope = x / ((float)waveWidth/2);
++
++ return (absSlope % 2);
++}
++
++static int getSlope (int x, int iPoint, int waveWidth)
++{
++ // Sizes: Caps are half width of slopes
++ // 1_2 1_2 1_2 1_2
++ // / \ / \ / \ / \
++ // / \ / \ / \ / \
++ // 0 3_0 3_0 3_0 3_
++ // <2-> <1> <---6---->
++
++ // Find type of first point
++ int firstType;
++ x -= (x / waveWidth) * waveWidth;
++ if (x < (waveWidth * (2.f/6.f)))
++ firstType = UNDERCURL_SLOPE_ASCENDING;
++ else if (x < (waveWidth * (3.f/6.f)))
++ firstType = UNDERCURL_SLOPE_TOP_CAP;
++ else if (x < (waveWidth * (5.f/6.f)))
++ firstType = UNDERCURL_SLOPE_DESCENDING;
++ else
++ firstType = UNDERCURL_SLOPE_BOTTOM_CAP;
++
++ // Find type of given point
++ int pointType = (iPoint % 4);
++ pointType += firstType;
++ pointType %= 4;
++
++ return pointType;
++}
++
+ void
+ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
+ {
+@@ -1461,8 +1514,357 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE) {
+- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
+- width, 1);
++ // Underline Color
++ const int widthThreshold = 28; // +1 width every widthThreshold px of font
++ int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width
++ int linecolor;
++ if ((base.ucolor[0] >= 0) &&
++ !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
++ !(base.mode & ATTR_INVISIBLE)
++ ) {
++ // Special color for underline
++ // Index
++ if (base.ucolor[1] < 0) {
++ linecolor = dc.col[base.ucolor[0]].pixel;
++ }
++ // RGB
++ else {
++ XColor lcolor;
++ lcolor.red = base.ucolor[0] * 257;
++ lcolor.green = base.ucolor[1] * 257;
++ lcolor.blue = base.ucolor[2] * 257;
++ lcolor.flags = DoRed | DoGreen | DoBlue;
++ XAllocColor(xw.dpy, xw.cmap, &lcolor);
++ linecolor = lcolor.pixel;
++ }
++ } else {
++ // Foreground color for underline
++ linecolor = fg->pixel;
++ }
++
++ XGCValues ugcv = {
++ .foreground = linecolor,
++ .line_width = wlw,
++ .line_style = LineSolid,
++ .cap_style = CapNotLast
++ };
++
++ GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
++ GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
++ &ugcv);
++
++ // Underline Style
++ if (base.ustyle != 3) {
++ //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1);
++ XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx,
++ winy + dc.font.ascent + 1, width, wlw);
++ } else if (base.ustyle == 3) {
++ int ww = win.cw;//width;
++ int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
++ int wx = winx;
++ int wy = winy + win.ch - dc.font.descent;
++
++#if UNDERCURL_STYLE == UNDERCURL_CURLY
++ // Draw waves
++ int narcs = charlen * 2 + 1;
++ XArc *arcs = xmalloc(sizeof(XArc) * narcs);
++
++ int i = 0;
++ for (i = 0; i < charlen-1; i++) {
++ arcs[i*2] = (XArc) {
++ .x = wx + win.cw * i + ww / 4,
++ .y = wy,
++ .width = win.cw / 2,
++ .height = wh,
++ .angle1 = 0,
++ .angle2 = 180 * 64
++ };
++ arcs[i*2+1] = (XArc) {
++ .x = wx + win.cw * i + ww * 0.75,
++ .y = wy,
++ .width = win.cw/2,
++ .height = wh,
++ .angle1 = 180 * 64,
++ .angle2 = 180 * 64
++ };
++ }
++ // Last wave
++ arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh,
++ 0, 180 * 64 };
++ // Last wave tail
++ arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.),
++ wh, 180 * 64, 90 * 64};
++ // First wave tail
++ i++;
++ arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64,
++ 90 * 64 };
++
++ XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs);
++
++ free(arcs);
++#elif UNDERCURL_STYLE == UNDERCURL_SPIKY
++ // Make the underline corridor larger
++ /*
++ wy -= wh;
++ */
++ wh *= 2;
++
++ // Set the angle of the slope to 45°
++ ww = wh;
++
++ // Position of wave is independent of word, it's absolute
++ wx = (wx / (ww/2)) * (ww/2);
++
++ int marginStart = winx - wx;
++
++ // Calculate number of points with floating precision
++ float n = width; // Width of word in pixels
++ n = (n / ww) * 2; // Number of slopes (/ or \)
++ n += 2; // Add two last points
++ int npoints = n; // Convert to int
++
++ // Total length of underline
++ float waveLength = 0;
++
++ if (npoints >= 3) {
++ // We add an aditional slot in case we use a bonus point
++ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
++
++ // First point (Starts with the word bounds)
++ points[0] = (XPoint) {
++ .x = wx + marginStart,
++ .y = (isSlopeRising(wx, 0, ww))
++ ? (wy - marginStart + ww/2.f)
++ : (wy + marginStart)
++ };
++
++ // Second point (Goes back to the absolute point coordinates)
++ points[1] = (XPoint) {
++ .x = (ww/2.f) - marginStart,
++ .y = (isSlopeRising(wx, 1, ww))
++ ? (ww/2.f - marginStart)
++ : (-ww/2.f + marginStart)
++ };
++ waveLength += (ww/2.f) - marginStart;
++
++ // The rest of the points
++ for (int i = 2; i < npoints-1; i++) {
++ points[i] = (XPoint) {
++ .x = ww/2,
++ .y = (isSlopeRising(wx, i, ww))
++ ? wh/2
++ : -wh/2
++ };
++ waveLength += ww/2;
++ }
++
++ // Last point
++ points[npoints-1] = (XPoint) {
++ .x = ww/2,
++ .y = (isSlopeRising(wx, npoints-1, ww))
++ ? wh/2
++ : -wh/2
++ };
++ waveLength += ww/2;
++
++ // End
++ if (waveLength < width) { // Add a bonus point?
++ int marginEnd = width - waveLength;
++ points[npoints] = (XPoint) {
++ .x = marginEnd,
++ .y = (isSlopeRising(wx, npoints, ww))
++ ? (marginEnd)
++ : (-marginEnd)
++ };
++
++ npoints++;
++ } else if (waveLength > width) { // Is last point too far?
++ int marginEnd = waveLength - width;
++ points[npoints-1].x -= marginEnd;
++ if (isSlopeRising(wx, npoints-1, ww))
++ points[npoints-1].y -= (marginEnd);
++ else
++ points[npoints-1].y += (marginEnd);
++ }
++
++ // Draw the lines
++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
++ CoordModePrevious);
++
++ // Draw a second underline with an offset of 1 pixel
++ if ( ((win.ch / (widthThreshold/2)) % 2)) {
++ points[0].x++;
++
++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
++ npoints, CoordModePrevious);
++ }
++
++ // Free resources
++ free(points);
++ }
++#else // UNDERCURL_CAPPED
++ // Cap is half of wave width
++ float capRatio = 0.5f;
++
++ // Make the underline corridor larger
++ wh *= 2;
++
++ // Set the angle of the slope to 45°
++ ww = wh;
++ ww *= 1 + capRatio; // Add a bit of width for the cap
++
++ // Position of wave is independent of word, it's absolute
++ wx = (wx / ww) * ww;
++
++ float marginStart;
++ switch(getSlope(winx, 0, ww)) {
++ case UNDERCURL_SLOPE_ASCENDING:
++ marginStart = winx - wx;
++ break;
++ case UNDERCURL_SLOPE_TOP_CAP:
++ marginStart = winx - (wx + (ww * (2.f/6.f)));
++ break;
++ case UNDERCURL_SLOPE_DESCENDING:
++ marginStart = winx - (wx + (ww * (3.f/6.f)));
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ marginStart = winx - (wx + (ww * (5.f/6.f)));
++ break;
++ }
++
++ // Calculate number of points with floating precision
++ float n = width; // Width of word in pixels
++ // ._.
++ n = (n / ww) * 4; // Number of points (./ \.)
++ n += 2; // Add two last points
++ int npoints = n; // Convert to int
++
++ // Position of the pen to draw the lines
++ float penX = 0;
++ float penY = 0;
++
++ if (npoints >= 3) {
++ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
++
++ // First point (Starts with the word bounds)
++ penX = winx;
++ switch (getSlope(winx, 0, ww)) {
++ case UNDERCURL_SLOPE_ASCENDING:
++ penY = wy + wh/2.f - marginStart;
++ break;
++ case UNDERCURL_SLOPE_TOP_CAP:
++ penY = wy;
++ break;
++ case UNDERCURL_SLOPE_DESCENDING:
++ penY = wy + marginStart;
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ penY = wy + wh/2.f;
++ break;
++ }
++ points[0].x = penX;
++ points[0].y = penY;
++
++ // Second point (Goes back to the absolute point coordinates)
++ switch (getSlope(winx, 1, ww)) {
++ case UNDERCURL_SLOPE_ASCENDING:
++ penX += ww * (1.f/6.f) - marginStart;
++ penY += 0;
++ break;
++ case UNDERCURL_SLOPE_TOP_CAP:
++ penX += ww * (2.f/6.f) - marginStart;
++ penY += -wh/2.f + marginStart;
++ break;
++ case UNDERCURL_SLOPE_DESCENDING:
++ penX += ww * (1.f/6.f) - marginStart;
++ penY += 0;
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ penX += ww * (2.f/6.f) - marginStart;
++ penY += -marginStart + wh/2.f;
++ break;
++ }
++ points[1].x = penX;
++ points[1].y = penY;
++
++ // The rest of the points
++ for (int i = 2; i < npoints; i++) {
++ switch (getSlope(winx, i, ww)) {
++ case UNDERCURL_SLOPE_ASCENDING:
++ case UNDERCURL_SLOPE_DESCENDING:
++ penX += ww * (1.f/6.f);
++ penY += 0;
++ break;
++ case UNDERCURL_SLOPE_TOP_CAP:
++ penX += ww * (2.f/6.f);
++ penY += -wh / 2.f;
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ penX += ww * (2.f/6.f);
++ penY += wh / 2.f;
++ break;
++ }
++ points[i].x = penX;
++ points[i].y = penY;
++ }
++
++ // End
++ float waveLength = penX - winx;
++ if (waveLength < width) { // Add a bonus point?
++ int marginEnd = width - waveLength;
++ penX += marginEnd;
++ switch(getSlope(winx, npoints, ww)) {
++ case UNDERCURL_SLOPE_ASCENDING:
++ case UNDERCURL_SLOPE_DESCENDING:
++ //penY += 0;
++ break;
++ case UNDERCURL_SLOPE_TOP_CAP:
++ penY += -marginEnd;
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ penY += marginEnd;
++ break;
++ }
++
++ points[npoints].x = penX;
++ points[npoints].y = penY;
++
++ npoints++;
++ } else if (waveLength > width) { // Is last point too far?
++ int marginEnd = waveLength - width;
++ points[npoints-1].x -= marginEnd;
++ switch(getSlope(winx, npoints-1, ww)) {
++ case UNDERCURL_SLOPE_TOP_CAP:
++ points[npoints-1].y += marginEnd;
++ break;
++ case UNDERCURL_SLOPE_BOTTOM_CAP:
++ points[npoints-1].y -= marginEnd;
++ break;
++ default:
++ break;
++ }
++ }
++
++ // Draw the lines
++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
++ CoordModeOrigin);
++
++ // Draw a second underline with an offset of 1 pixel
++ if ( ((win.ch / (widthThreshold/2)) % 2)) {
++ for (int i = 0; i < npoints; i++)
++ points[i].x++;
++
++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
++ npoints, CoordModeOrigin);
++ }
++
++ // Free resources
++ free(points);
++ }
++#endif
++ }
++
++ XFreeGC(xw.dpy, ugc);
+ }
+
+ if (base.mode & ATTR_STRUCK) {
diff --git a/st/unpatched/st-universcroll-0.8.4.diff b/st/unpatched/st-universcroll-0.8.4.diff
new file mode 100644
index 0000000..6a33813
--- /dev/null
+++ b/st/unpatched/st-universcroll-0.8.4.diff
@@ -0,0 +1,90 @@
+From 9726b1e58352126252412e101432e64d46fc51ca Mon Sep 17 00:00:00 2001
+From: Dennis Lee <dennis@dennislee.xyz>
+Date: Sun, 28 Jun 2020 23:01:03 -0700
+Subject: [PATCH] universcroll: mouse wheel only scroll in all modes
+
+Scroll normally via scroll(1), without Shift, when outside of
+`MODE_ALTSCREEN`. Inside an alt screen, continue to scroll normally
+without Shift; in this mode, your scrolling is automatically translated
+into ^Y and ^E. It just werks!
+
+Based on the existing mouse-altscreen patch
+https://st.suckless.org/patches/scrollback/
+adapted for st(1) 0.8.4 and scroll(1).
+---
+ config.def.h | 10 +++++-----
+ st.c | 5 +++++
+ st.h | 1 +
+ x.c | 2 ++
+ 4 files changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..62e87da 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -173,11 +173,11 @@ static uint forcemousemod = ShiftMask;
+ * Beware that overloading Button1 will disable the selection.
+ */
+ static MouseShortcut mshortcuts[] = {
+- /* mask button function argument release */
+- { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+- { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
++ /* mask button function argument release alt */
++ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
++ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+- { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
++ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
+ };
+
+diff --git a/st.c b/st.c
+index 76b7e0d..1f65453 100644
+--- a/st.c
++++ b/st.c
+@@ -1047,6 +1047,11 @@ tnew(int col, int row)
+ treset();
+ }
+
++int tisaltscr(void)
++{
++ return IS_SET(MODE_ALTSCREEN);
++}
++
+ void
+ tswapscreen(void)
+ {
+diff --git a/st.h b/st.h
+index 3d351b6..39cc054 100644
+--- a/st.h
++++ b/st.h
+@@ -87,6 +87,7 @@ void sendbreak(const Arg *);
+ void toggleprinter(const Arg *);
+
+ int tattrset(int);
++int tisaltscr(void);
+ void tnew(int, int);
+ void tresize(int, int);
+ void tsetdirtattr(int);
+diff --git a/x.c b/x.c
+index 210f184..210dde9 100644
+--- a/x.c
++++ b/x.c
+@@ -34,6 +34,7 @@ typedef struct {
+ void (*func)(const Arg *);
+ const Arg arg;
+ uint release;
++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
+ } MouseShortcut;
+
+ typedef struct {
+@@ -446,6 +447,7 @@ mouseaction(XEvent *e, uint release)
+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+ if (ms->release == release &&
+ ms->button == e->xbutton.button &&
++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
+ (match(ms->mod, state) || /* exact or forced */
+ match(ms->mod, state & ~forcemousemod))) {
+ ms->func(&(ms->arg));
+--
+2.27.0
diff --git a/st/unpatched/st-universcroll-example-0.8.4.diff b/st/unpatched/st-universcroll-example-0.8.4.diff
new file mode 100644
index 0000000..76ff70d
--- /dev/null
+++ b/st/unpatched/st-universcroll-example-0.8.4.diff
@@ -0,0 +1,47 @@
+From 59d2c9b65f90f78507b88d773323aab31194b7b4 Mon Sep 17 00:00:00 2001
+From: Dennis Lee <dennis@dennislee.xyz>
+Date: Mon, 29 Jun 2020 21:33:08 -0700
+Subject: [PATCH] universcroll: sane default configuration
+
+- Set scroll program = "scroll"
+- Mouse wheel scroll only with NO_MOD.
+- Mouse wheel zoom with ShiftMask/ANY_MOD.
+---
+ config.def.h | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a52c0a2..74fd64c 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -19,7 +19,7 @@ static int borderpx = 2;
+ static char *shell = "/bin/sh";
+ char *utmp = NULL;
+ /* scroll program: to enable use a string like "scroll" */
+-char *scroll = NULL;
++char *scroll = "scroll";
+ char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
+
+ /* identification sequence returned in DA and DECID */
+@@ -175,10 +175,14 @@ static uint forcemousemod = ShiftMask;
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release alt */
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+- { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 },
+- { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+- { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 },
+- { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
++ { ShiftMask, Button4, zoom, {.f = +1} },
++ { ShiftMask, Button5, zoom, {.f = -1} },
++ { XK_NO_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 },
++ { XK_NO_MOD, Button4, ttysend, {.s = "\031"} },
++ { XK_NO_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 },
++ { XK_NO_MOD, Button5, ttysend, {.s = "\005"} },
++ { XK_ANY_MOD, Button4, zoom, {.f = +1} },
++ { XK_ANY_MOD, Button5, zoom, {.f = -1} },
+ };
+
+ /* Internal keyboard shortcuts. */
+--
+2.27.0
+
diff --git a/st/win.h b/st/win.h
index 8839e31..0c247aa 100644
--- a/st/win.h
+++ b/st/win.h
@@ -21,22 +21,27 @@ enum win_mode {
MODE_NUMLOCK = 1 << 17,
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|MODE_MOUSEMANY,
+ MODE_KBDSELECT = 1 << 18,
};
void xbell(void);
void xclipcopy(void);
-void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
+void xdrawcursor(int, int, Glyph, int, int, Glyph);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
int xsetcolorname(int, const char *);
int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
void xseticontitle(char *);
-void xsettitle(char *);
+void xfreetitlestack(void);
+void xsettitle(char *, int);
+void xpushtitle(void);
int xsetcursor(int);
void xsetmode(int, unsigned int);
void xsetpointermotion(int);
void xsetsel(char *);
int xstartdraw(void);
+void toggle_winmode(int);
+void keyboard_select(const Arg *);
void xximspot(int, int);
-
+void xclearwin(void);
diff --git a/st/x.c b/st/x.c
index 8082ded..d6067d7 100644
--- a/st/x.c
+++ b/st/x.c
@@ -5,6 +5,7 @@
#include <locale.h>
#include <signal.h>
#include <sys/select.h>
+#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
@@ -20,7 +21,6 @@ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
-#include "hb.h"
/* types used in config.h */
typedef struct {
@@ -36,6 +36,7 @@ typedef struct {
void (*func)(const Arg *);
const Arg arg;
uint release;
+ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
} MouseShortcut;
typedef struct {
@@ -47,6 +48,11 @@ typedef struct {
signed char appcursor; /* application cursor */
} Key;
+typedef enum {
+ PixelGeometry,
+ CellGeometry
+} Geometry;
+
/* Xresources preferences */
enum resource_type {
STRING = 0,
@@ -70,17 +76,19 @@ static void clipcopy(const Arg *);
static void clippaste(const Arg *);
static void numlock(const Arg *);
static void selpaste(const Arg *);
-static void changealpha(const Arg *);
static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
static void ttysend(const Arg *);
+static void chgalpha(const Arg *);
static void cyclefonts(const Arg *);
-
/* config.h for applying patches and the configuration. */
#include "config.h"
+/* size of title stack */
+#define TITLESTACKSIZE 8
+
/* XEMBED messages */
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
@@ -102,7 +110,6 @@ typedef struct {
int hborderpx, vborderpx;
int ch; /* char height */
int cw; /* char width */
- int cyo; /* char y offset */
int mode; /* window state/mode flags */
int cursor; /* cursor style */
} TermWindow;
@@ -114,6 +121,7 @@ typedef struct {
Drawable buf;
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
+ Atom netwmstate, netwmfullscreen;
struct {
XIM xim;
XIC xic;
@@ -163,7 +171,7 @@ typedef struct {
static inline ushort sixd_to_16bit(int);
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
+static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int);
static void xdrawglyph(Glyph, int, int);
static void xclear(int, int, int, int);
static int xgeommasktogravity(int);
@@ -186,7 +194,6 @@ static void xsetenv(void);
static void xseturgency(int);
static int evcol(XEvent *);
static int evrow(XEvent *);
-static float clamp(float, float, float);
static void expose(XEvent *);
static void visibility(XEvent *);
@@ -215,6 +222,7 @@ static void usage(void);
static void (*handler[LASTEvent])(XEvent *) = {
[KeyPress] = kpress,
+ [KeyRelease] = kpress,
[ClientMessage] = cmessage,
[ConfigureNotify] = resize,
[VisibilityNotify] = visibility,
@@ -244,6 +252,8 @@ static DC dc;
static XWindow xw;
static XSelection xsel;
static TermWindow win;
+static int tstki; /* title stack index */
+static char *titlestack[TITLESTACKSIZE]; /* title stack */
/* Font Ring Cache */
enum {
@@ -267,6 +277,11 @@ static char *usedfont = NULL;
static double usedfontsize = 0;
static double defaultfontsize = 0;
+/* declared in config.h */
+extern int disablebold;
+extern int disableitalic;
+extern int disableroman;
+
static char *opt_alpha = NULL;
static char *opt_class = NULL;
static char **opt_cmd = NULL;
@@ -277,11 +292,15 @@ static char *opt_line = NULL;
static char *opt_name = NULL;
static char *opt_title = NULL;
-static int focused = 0;
-
-static int oldbutton = 3; /* button event on startup: 3 = release */
static uint buttons; /* bit field of pressed buttons */
static int cursorblinks = 0;
+static int focused = 0;
+
+static Cursor cursor;
+static XColor xmousefg, xmousebg;
+XWindowAttributes attr;
+XVisualInfo vis;
+
void
clipcopy(const Arg *dummy)
@@ -322,20 +341,6 @@ numlock(const Arg *dummy)
}
void
-changealpha(const Arg *arg)
-{
- if((alpha > 0 && arg->f < 0) || (alpha < 1 && arg->f > 0))
- alpha += arg->f;
- else if (arg->f == 0.0f)
- alpha = alpha_def;
- alpha = clamp(alpha, 0.0, 1.0);
- alphaUnfocus = clamp(alpha-alphaOffset, 0.0, 1.0);
-
- xloadcols();
- redraw();
-}
-
-void
zoom(const Arg *arg)
{
Arg larg;
@@ -359,7 +364,6 @@ void
zoomreset(const Arg *arg)
{
Arg larg;
-
zoomabs(&larg);
}
@@ -396,15 +400,6 @@ evrow(XEvent *e)
return y / win.ch;
}
-float
-clamp(float value, float lower, float upper) {
- if(value < lower)
- return lower;
- if(value > upper)
- return upper;
- return value;
-}
-
void
mousesel(XEvent *e, int done)
{
@@ -425,59 +420,68 @@ mousesel(XEvent *e, int done)
void
mousereport(XEvent *e)
{
- int len, x = evcol(e), y = evrow(e),
- button = e->xbutton.button, state = e->xbutton.state;
+ int len, btn, code;
+ int x = evcol(e), y = evrow(e);
+ int state = e->xbutton.state;
char buf[40];
static int ox, oy;
- /* from urxvt */
- if (e->xbutton.type == MotionNotify) {
+ if (e->type == MotionNotify) {
if (x == ox && y == oy)
return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return;
- /* MOUSE_MOTION: no reporting if no button is pressed */
- if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+ /* MODE_MOUSEMOTION: no reporting if no button is pressed */
+ if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
return;
-
- button = oldbutton + 32;
- ox = x;
- oy = y;
+ /* Set btn to lowest-numbered pressed button, or 12 if no
+ * buttons are pressed. */
+ for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
+ ;
+ code = 32;
} else {
- if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
- button = 3;
- } else {
- button -= Button1;
- if (button >= 3)
- button += 64 - 3;
- }
- if (e->xbutton.type == ButtonPress) {
- oldbutton = button;
- ox = x;
- oy = y;
- } else if (e->xbutton.type == ButtonRelease) {
- oldbutton = 3;
+ btn = e->xbutton.button;
+ /* Only buttons 1 through 11 can be encoded */
+ if (btn < 1 || btn > 11)
+ return;
+ if (e->type == ButtonRelease) {
/* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10))
return;
- if (button == 64 || button == 65)
+ /* Don't send release events for the scroll wheel */
+ if (btn == 4 || btn == 5)
return;
}
+ code = 0;
}
+ ox = x;
+ oy = y;
+
+ /* Encode btn into code. If no button is pressed for a motion event in
+ * MODE_MOUSEMANY, then encode it as a release. */
+ if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
+ code += 3;
+ else if (btn >= 8)
+ code += 128 + btn - 8;
+ else if (btn >= 4)
+ code += 64 + btn - 4;
+ else
+ code += btn - 1;
+
if (!IS_SET(MODE_MOUSEX10)) {
- button += ((state & ShiftMask ) ? 4 : 0)
- + ((state & Mod4Mask ) ? 8 : 0)
- + ((state & ControlMask) ? 16 : 0);
+ code += ((state & ShiftMask ) ? 4 : 0)
+ + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ + ((state & ControlMask) ? 16 : 0);
}
if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
- button, x+1, y+1,
+ code, x+1, y+1,
e->type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
- 32+button, 32+x+1, 32+y+1);
+ 32+code, 32+x+1, 32+y+1);
} else {
return;
}
@@ -504,9 +508,14 @@ mouseaction(XEvent *e, uint release)
/* ignore Button<N>mask for Button<N> - it's set on release */
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
+ if (release == 0 && e->xbutton.button == Button1) {
+ return followurl(evcol(e), evrow(e));
+ }
+
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
if (ms->release == release &&
ms->button == e->xbutton.button &&
+ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
(match(ms->mod, state) || /* exact or forced */
match(ms->mod, state & ~forcemousemod))) {
ms->func(&(ms->arg));
@@ -738,6 +747,7 @@ setsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear();
+ clipcopy(NULL);
}
void
@@ -815,6 +825,24 @@ xresize(int col, int row)
xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
}
+void
+fullscreen(const Arg *arg)
+{
+ XEvent ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.xclient.type = ClientMessage;
+ ev.xclient.message_type = xw.netwmstate;
+ ev.xclient.display = xw.dpy;
+ ev.xclient.window = xw.win;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */
+ ev.xclient.data.l[1] = xw.netwmfullscreen;
+
+ XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev);
+}
+
ushort
sixd_to_16bit(int x)
{
@@ -848,7 +876,8 @@ xloadcolor(int i, const char *name, Color *ncolor)
void
xloadalpha(void)
{
- float const usedAlpha = focused ? alpha : alphaUnfocus;
+ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]);
+ float const usedAlpha = focused ? alpha : alphaUnfocused;
if (opt_alpha) alpha = strtof(opt_alpha, NULL);
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
dc.col[defaultbg].pixel &= 0x00FFFFFF;
@@ -858,16 +887,15 @@ xloadalpha(void)
void
xloadcols(void)
{
- int i;
static int loaded;
Color *cp;
if (!loaded) {
dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256));
- dc.col = xmalloc(dc.collen * sizeof(Color));
+ dc.col = xmalloc((dc.collen) * sizeof(Color));
}
- for (i = 0; i+1 < dc.collen; i++)
+ for (int i = 0; i+1 < dc.collen; ++i)
if (!xloadcolor(i, NULL, &dc.col[i])) {
if (colorname[i])
die("could not allocate color '%s'\n", colorname[i]);
@@ -875,9 +903,6 @@ xloadcols(void)
die("could not allocate color %d\n", i);
}
- if (dc.collen) // cannot die, as the color is already loaded.
- xloadcolor(background, NULL, &dc.col[defaultbg]);
-
xloadalpha();
loaded = 1;
}
@@ -885,7 +910,7 @@ xloadcols(void)
int
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
{
- if (!BETWEEN(x, 0, dc.collen))
+ if (!BETWEEN(x, 0, dc.collen - 1))
return 1;
*r = dc.col[x].color.red >> 8;
@@ -900,7 +925,7 @@ xsetcolorname(int x, const char *name)
{
Color ncolor;
- if (!BETWEEN(x, 0, dc.collen))
+ if (!BETWEEN(x, 0, dc.collen - 1))
return 1;
if (!xloadcolor(x, name, &ncolor))
@@ -924,6 +949,12 @@ xclear(int x1, int y1, int x2, int y2)
}
void
+xclearwin(void)
+{
+ xclear(0, 0, win.w, win.h);
+}
+
+void
xhints(void)
{
XClassHint class = {opt_name ? opt_name : "st",
@@ -1098,20 +1129,22 @@ xloadfonts(const char *fontstr, double fontsize)
/* Setting character width and height. */
win.cw = ceilf(dc.font.width * cwscale);
win.ch = ceilf(dc.font.height * chscale);
- win.cyo = ceilf(dc.font.height * (chscale - 1) / 2);
FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (!disableitalic)
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
if (xloadfont(&dc.ifont, pattern))
die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_WEIGHT);
- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (!disablebold)
+ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
if (xloadfont(&dc.ibfont, pattern))
die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ if (!disableroman)
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
if (xloadfont(&dc.bfont, pattern))
die("can't open font %s\n", fontstr);
@@ -1149,7 +1182,6 @@ xloadsparefonts(void)
double sizeshift, fontval;
int fc;
char **fp;
- int width, height;
if (frclen != 0)
die("can't embed spare fonts. cache isn't empty");
@@ -1166,6 +1198,7 @@ xloadsparefonts(void)
}
for (fp = font2; fp - font2 < fc; ++fp) {
+
if (**fp == '-')
pattern = XftXlfdParse(*fp, False, False);
else
@@ -1225,9 +1258,6 @@ xunloadfont(Font *f)
void
xunloadfonts(void)
{
- /* Clear Harfbuzz font cache. */
- hbunloadfonts();
-
/* Free the loaded fonts in the font cache. */
while (frclen > 0)
XftFontClose(xw.dpy, frc[--frclen].font);
@@ -1293,16 +1323,11 @@ xicdestroy(XIC xim, XPointer client, XPointer call)
}
void
-xinit(int cols, int rows)
+xinit(int w, int h)
{
XGCValues gcvalues;
- Cursor cursor;
Window parent;
pid_t thispid = getpid();
- XColor xmousefg, xmousebg;
- XWindowAttributes attr;
- XVisualInfo vis;
- int width, height;
xw.scr = XDefaultScreen(xw.dpy);
@@ -1321,23 +1346,30 @@ xinit(int cols, int rows)
if (!FcInit())
die("could not init fontconfig.\n");
- usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font;
-
- xloadfonts(usedfont, 0);
+ usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font;
+ xloadfonts(usedfont, 0);
/* spare fonts */
xloadsparefonts();
- /* Backup default alpha value */
- alpha_def = alpha;
+ /* Backup default alpha value */
+ alpha_def = alpha;
/* colors */
xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols();
/* adjust fixed window geometry */
- win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
- win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
+ switch (geometry) {
+ case CellGeometry:
+ win.w = 2 * win.hborderpx + 2 * borderpx + w * win.cw;
+ win.h = 2 * win.vborderpx + 2 * borderpx + h * win.ch;
+ break;
+ case PixelGeometry:
+ win.w = w;
+ win.h = h;
+ break;
+ }
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@@ -1404,6 +1436,9 @@ xinit(int cols, int rows)
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
PropModeReplace, (uchar *)&thispid, 1);
+ xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False);
+ xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False);
+
win.mode = MODE_NUMLOCK;
resettitle();
xhints();
@@ -1437,13 +1472,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
FcCharSet *fccharset;
int i, f, numspecs = 0;
- for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) {
+ for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
/* Fetch rune and mode for current glyph. */
rune = glyphs[i].u;
mode = glyphs[i].mode;
/* Skip dummy wide-character spacing. */
- if (mode & ATTR_WDUMMY)
+ if (mode == ATTR_WDUMMY)
continue;
/* Determine font for glyph if different from previous glyph. */
@@ -1462,7 +1497,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
font = &dc.bfont;
frcflags = FRC_BOLD;
}
- yp = winy + font->ascent + win.cyo;
+ yp = winy + font->ascent;
}
if (mode & ATTR_BOXDRAW) {
@@ -1475,9 +1510,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
if (glyphidx) {
specs[numspecs].font = font->match;
specs[numspecs].glyph = glyphidx;
- specs[numspecs].x = (short)xp + cxoffset;
+ specs[numspecs].x = (short)xp + cxoffset;
specs[numspecs].y = (short)yp + cyoffset;
-
xp += runewidth;
numspecs++;
continue;
@@ -1556,14 +1590,29 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
numspecs++;
}
- /* Harfbuzz transformation for ligatures. */
- hbtransform(specs, glyphs, len, x, y);
-
return numspecs;
}
void
-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
+chgalpha(const Arg *arg)
+{
+ if (arg->f == -1.0f && alpha >= 0.1f)
+ alpha -= 0.1f;
+ else if (arg->f == 1.0f && alpha < 1.0f)
+ alpha += 0.1f;
+ else if (arg->f == 0.0f)
+ alpha = alpha_def;
+ else
+ return;
+
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha);
+ /* Required to remove artifacting from borderpx */
+ cresize(0, 0);
+ redraw();
+}
+
+void
+xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
@@ -1643,9 +1692,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
}
if (base.mode & ATTR_REVERSE) {
- temp = fg;
- fg = bg;
- bg = temp;
+ if (bg == fg) {
+ bg = &dc.col[defaultfg];
+ fg = &dc.col[defaultbg];
+ } else {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
}
if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK)
@@ -1654,51 +1708,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
if (base.mode & ATTR_INVISIBLE)
fg = bg;
- /* Intelligent cleaning up of the borders. */
- if (x == 0) {
- xclear(0, (y == 0)? 0 : winy, win.hborderpx,
- winy + win.ch +
- ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
- }
- if (winx + width >= win.hborderpx + win.tw) {
- xclear(winx + width, (y == 0)? 0 : winy, win.w,
- ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
- }
- if (y == 0)
- xclear(winx, 0, winx + width, win.vborderpx);
- if (winy + win.ch >= win.vborderpx + win.th)
- xclear(winx, winy + win.ch, winx + width, win.h);
-
- /* Clean up the region we want to draw to. */
- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
-
- /* Set the clip region because Xft is sometimes dirty. */
- r.x = 0;
- r.y = 0;
- r.height = win.ch;
- r.width = width;
- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
-
- if (base.mode & ATTR_BOXDRAW) {
- drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
- } else {
- /* Render the glyphs. */
- XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
- }
-
- /* Render underline and strikethrough. */
- if (base.mode & ATTR_UNDERLINE) {
- XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1,
- width, 1);
- }
-
- if (base.mode & ATTR_STRUCK) {
- XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3,
- width, 1);
- }
-
- /* Reset clip to none. */
- XftDrawSetClip(xw.draw, 0);
+ if (dmode & DRAW_BG) {
+ /* Intelligent cleaning up of the borders. */
+ if (x == 0) {
+ xclear(0, (y == 0)? 0 : winy, win.hborderpx,
+ winy + win.ch +
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
+ }
+ if (winx + width >= win.hborderpx + win.tw) {
+ xclear(winx + width, (y == 0)? 0 : winy, win.w,
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
+ }
+ if (y == 0)
+ xclear(winx, 0, winx + width, win.vborderpx);
+ if (winy + win.ch >= win.vborderpx + win.th)
+ xclear(winx, winy + win.ch, winx + width, win.h);
+
+ /* Clean up the region we want to draw to. */
+ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+ }
+
+ if (dmode & DRAW_FG) {
+ if (base.mode & ATTR_BOXDRAW) {
+ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
+ } else {
+ /* Render the glyphs. */
+ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+ }
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) {
+ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
+ width, 1);
+ }
+
+ if (base.mode & ATTR_STRUCK) {
+ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
+ width, 1);
+ }
+ }
}
void
@@ -1708,21 +1756,19 @@ xdrawglyph(Glyph g, int x, int y)
XftGlyphFontSpec spec;
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
- xdrawglyphfontspecs(&spec, g, numspecs, x, y);
+ xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG);
}
void
-xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
{
Color drawcol;
+ XRenderColor colbg;
/* remove the old cursor */
if (selected(ox, oy))
og.mode ^= ATTR_REVERSE;
-
- /* Redraw the line where cursor was previously.
- * It will restore the ligatures broken by the cursor. */
- xdrawline(line, 0, oy, len);
+ xdrawglyph(og, ox, oy);
if (IS_SET(MODE_HIDE))
return;
@@ -1746,22 +1792,31 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
if (selected(cx, cy)) {
g.fg = defaultfg;
g.bg = defaultrcs;
+ } else if (!(og.mode & ATTR_REVERSE)) {
+ unsigned long col = g.bg;
+ g.bg = g.fg;
+ g.fg = col;
+ }
+
+ if (IS_TRUECOL(g.bg)) {
+ colbg.alpha = 0xffff;
+ colbg.red = TRUERED(g.bg);
+ colbg.green = TRUEGREEN(g.bg);
+ colbg.blue = TRUEBLUE(g.bg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol);
} else {
- g.fg = defaultbg;
- g.bg = defaultcs;
+ drawcol = dc.col[g.bg];
}
- drawcol = dc.col[g.bg];
}
/* draw the new one */
if (IS_SET(MODE_FOCUSED)) {
switch (win.cursor) {
- default:
+ default:
case 0: /* blinking block */
case 1: /* blinking block (default) */
if (IS_SET(MODE_BLINK))
break;
-
/* FALLTHROUGH */
case 2: /* steady block */
xdrawglyph(g, cx, cy);
@@ -1831,6 +1886,9 @@ xseticontitle(char *p)
XTextProperty prop;
DEFAULT(p, opt_title);
+ if (p[0] == '\0')
+ p = opt_title;
+
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
return;
@@ -1840,10 +1898,33 @@ xseticontitle(char *p)
}
void
-xsettitle(char *p)
+xfreetitlestack(void)
{
- XTextProperty prop;
- DEFAULT(p, opt_title);
+ for (int i = 0; i < LEN(titlestack); i++) {
+ free(titlestack[i]);
+ titlestack[i] = NULL;
+ }
+}
+
+void
+xsettitle(char *p, int pop)
+{
+ XTextProperty prop;
+
+ free(titlestack[tstki]);
+ if (pop) {
+ titlestack[tstki] = NULL;
+ tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
+ p = titlestack[tstki] ? titlestack[tstki] : opt_title;
+ } else if (p) {
+ titlestack[tstki] = xstrdup(p);
+ } else {
+ titlestack[tstki] = NULL;
+ p = opt_title;
+ }
+
+ if (p[0] == '\0')
+ p = opt_title;
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
@@ -1853,41 +1934,60 @@ xsettitle(char *p)
XFree(prop.value);
}
+void
+xpushtitle(void)
+{
+ int tstkin = (tstki + 1) % TITLESTACKSIZE;
+
+ free(titlestack[tstkin]);
+ titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
+ tstki = tstkin;
+}
+
int
xstartdraw(void)
{
+ if (IS_SET(MODE_VISIBLE))
+ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
return IS_SET(MODE_VISIBLE);
}
void
xdrawline(Line line, int x1, int y1, int x2)
{
- int i, x, ox, numspecs;
+ int i, x, ox, numspecs, numspecs_cached;
Glyph base, new;
- XftGlyphFontSpec *specs = xw.specbuf;
-
- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
- i = ox = 0;
- for (x = x1; x < x2 && i < numspecs; x++) {
- new = line[x];
- if (new.mode == ATTR_WDUMMY)
- continue;
- if (selected(x, y1))
- new.mode ^= ATTR_REVERSE;
- if (i > 0 && ATTRCMP(base, new)) {
- xdrawglyphfontspecs(specs, base, i, ox, y1);
- specs += i;
- numspecs -= i;
- i = 0;
- }
- if (i == 0) {
- ox = x;
- base = new;
+ XftGlyphFontSpec *specs;
+
+ numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1);
+
+ /* Draw line in 2 passes: background and foreground. This way wide glyphs
+ won't get truncated (#223) */
+ for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) {
+ specs = xw.specbuf;
+ numspecs = numspecs_cached;
+ i = ox = 0;
+ for (x = x1; x < x2 && i < numspecs; x++) {
+ new = line[x];
+ if (new.mode == ATTR_WDUMMY)
+ continue;
+ if (selected(x, y1))
+ new.mode ^= ATTR_REVERSE;
+ if (i > 0 && ATTRCMP(base, new)) {
+ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
+ specs += i;
+ numspecs -= i;
+ i = 0;
+ }
+ if (i == 0) {
+ ox = x;
+ base = new;
+ }
+ i++;
}
- i++;
+ if (i > 0)
+ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
}
- if (i > 0)
- xdrawglyphfontspecs(specs, base, i, ox, y1);
}
void
@@ -1944,6 +2044,12 @@ xsetmode(int set, unsigned int flags)
{
int mode = win.mode;
MODBIT(win.mode, set, flags);
+ if (flags & MODE_MOUSE) {
+ if (win.mode & MODE_MOUSE)
+ XUndefineCursor(xw.dpy, xw.win);
+ else
+ XDefineCursor(xw.dpy, xw.win, cursor);
+ }
if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
redraw();
}
@@ -1996,7 +2102,7 @@ focus(XEvent *ev)
ttywrite("\033[I", 3, 0);
if (!focused) {
focused = 1;
- xloadcols();
+ xloadalpha();
tfulldirt();
}
} else {
@@ -2007,7 +2113,7 @@ focus(XEvent *ev)
ttywrite("\033[O", 3, 0);
if (focused) {
focused = 0;
- xloadcols();
+ xloadalpha();
tfulldirt();
}
}
@@ -2060,11 +2166,9 @@ void
kpress(XEvent *ev)
{
XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char *buf = NULL, *customkey;
- int len = 0;
- int buf_size = 64;
- int critical = - 1;
+ KeySym ksym = NoSymbol;
+ char buf[64], *customkey;
+ int len;
Rune c;
Status status;
Shortcut *bp;
@@ -2072,44 +2176,51 @@ kpress(XEvent *ev)
if (IS_SET(MODE_KBDLOCK))
return;
-reallocbuf:
- if (critical > 0)
- goto cleanup;
- if (buf)
- free(buf);
-
- buf = xmalloc((buf_size) * sizeof(char));
- critical += 1;
-
if (xw.ime.xic) {
- len = XmbLookupString(xw.ime.xic, e, buf, buf_size, &ksym, &status);
- if (status == XBufferOverflow) {
- buf_size = len;
- goto reallocbuf;
- }
+ len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+ if (status == XBufferOverflow)
+ return;
} else {
- // Not sure how to fix this and if it is fixable
- // but at least it does write something into the buffer
- // so it is not as critical
- len = XLookupString(e, buf, buf_size, &ksym, NULL);
+ len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
+ }
+
+ /* KeyRelease not relevant to shortcuts */
+ if (ev->type == KeyRelease)
+ return;
+
+ if ( IS_SET(MODE_KBDSELECT) ) {
+ if ( match(XK_NO_MOD, e->state) ||
+ (XK_Shift_L | XK_Shift_R) & e->state )
+ win.mode ^= trt_kbdselect(ksym, buf, len);
+ return;
}
+
/* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
if (ksym == bp->keysym && match(bp->mod, e->state)) {
+ if (bp -> func != autocomplete)
+ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
bp->func(&(bp->arg));
- goto cleanup;
+ return;
}
}
+ if (!(
+ len == 0 &&
+ e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way
+ | ALTCTRL == ALTCTRL
+ ))
+ autocomplete ((const Arg []) { ACMPL_DEACTIVATE });
+
/* 2. custom keys from config.h */
if ((customkey = kmap(ksym, e->state))) {
ttywrite(customkey, strlen(customkey), 1);
- goto cleanup;
+ return;
}
/* 3. composed string from input method */
if (len == 0)
- goto cleanup;
+ return;
if (len == 1 && e->state & Mod1Mask) {
if (IS_SET(MODE_8BIT)) {
if (*buf < 0177) {
@@ -2122,11 +2233,7 @@ reallocbuf:
len = 2;
}
}
- if (len <= buf_size)
- ttywrite(buf, len, 1);
-cleanup:
- if (buf)
- free(buf);
+ ttywrite(buf, len, 1);
}
void
@@ -2237,7 +2344,6 @@ run(void)
win.mode ^= MODE_BLINK;
}
lastblink = now;
-
drawing = 1;
}
timeout = (maxlatency - TIMEDIFF(now, trigger)) \
@@ -2322,16 +2428,24 @@ config_init(void)
void
usage(void)
{
- die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
+ die("usage: %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]"
" [-n name] [-o file]\n"
" [-T title] [-t title] [-w windowid]"
" [[-e] command [args ...]]\n"
- " %s [-aiv] [-c class] [-f font] [-g geometry]"
+ " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]"
" [-n name] [-o file]\n"
" [-T title] [-t title] [-w windowid] -l line"
" [stty_args ...]\n", argv0, argv0);
}
+void toggle_winmode(int flag) {
+ win.mode ^= flag;
+}
+
+void keyboard_select(const Arg *dummy) {
+ win.mode ^= trt_kbdselect(-1, NULL, 0);
+}
+
int
main(int argc, char *argv[])
{
@@ -2343,6 +2457,9 @@ main(int argc, char *argv[])
case 'a':
allowaltscreen = 0;
break;
+ case 'b':
+ borderpx = atoi(EARGF(usage()));
+ break;
case 'A':
opt_alpha = EARGF(usage());
break;
@@ -2359,6 +2476,12 @@ main(int argc, char *argv[])
case 'g':
xw.gm = XParseGeometry(EARGF(usage()),
&xw.l, &xw.t, &cols, &rows);
+ geometry = CellGeometry;
+ break;
+ case 'G':
+ xw.gm = XParseGeometry(EARGF(usage()),
+ &xw.l, &xw.t, &width, &height);
+ geometry = PixelGeometry;
break;
case 'i':
xw.isfixed = 1;
@@ -2400,12 +2523,20 @@ run:
die("Can't open display\n");
config_init();
+ switch (geometry) {
+ case CellGeometry:
+ xinit(cols, rows);
+ break;
+ case PixelGeometry:
+ xinit(width, height);
+ cols = (win.w - 2 * borderpx) / win.cw;
+ rows = (win.h - 2 * borderpx) / win.ch;
+ break;
+ }
cols = MAX(cols, 1);
rows = MAX(rows, 1);
defaultbg = MAX(LEN(colorname), 256);
- alphaUnfocus = alpha-alphaOffset;
tnew(cols, rows);
- xinit(cols, rows);
xsetenv();
selinit();
run();
@@ -2413,3 +2544,24 @@ run:
return 0;
}
+void
+opencopied(const Arg *arg)
+{
+ char * const clip = xsel.clipboard;
+ pid_t chpid;
+
+ if(!clip) {
+ fprintf(stderr, "Warning: nothing copied to clipboard\n");
+ return;
+ }
+
+ if ((chpid = fork()) == 0) {
+ if (fork() == 0)
+ execlp(arg->v, arg->v, clip, NULL);
+ exit(1);
+ }
+ if (chpid > 0)
+ waitpid(chpid, NULL, WNOHANG); // Non-blocking wait
+ return;
+}
+